chore: настроен обход антибот защиты
This commit is contained in:
1 parent
4cc068a616
commit
1cfd9bafef
6 files changed
+118
-66
No files matched your search
+55
-1
@@ -1,7 +1,48 @@
|
||||
import asyncio
|
||||
import json
|
||||
import hashlib
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.async_api import Page
|
||||
from twocaptcha import TwoCaptcha
|
||||
|
||||
|
||||
def cached_persistent(file_name=None):
|
||||
|
||||
def key(*args, **kwargs):
|
||||
return hashlib.sha256(f'{str(args)}-{str(kwargs)}'.encode()).hexdigest()
|
||||
|
||||
def wrapper(fun):
|
||||
|
||||
def clear_cache():
|
||||
cache_file.write_text(json.dumps({}))
|
||||
|
||||
cache_file = Path(file_name)
|
||||
if not cache_file.exists():
|
||||
cache_file.write_text(json.dumps({}))
|
||||
|
||||
async def wrapped(*args, **kwargs):
|
||||
data = json.loads(cache_file.read_text())
|
||||
_key = key(fun.__name__, *args, **kwargs)
|
||||
|
||||
if cached_value := data.get(_key):
|
||||
cached_value, cache_time = cached_value
|
||||
if time.time() - cache_time > 300:
|
||||
cached_value = None
|
||||
|
||||
value = cached_value or await fun(*args, **kwargs)
|
||||
|
||||
data[_key] = [value, time.time()]
|
||||
cache_file.write_text(json.dumps(data))
|
||||
return value
|
||||
|
||||
setattr(wrapped, '_clear_cache', clear_cache)
|
||||
return wrapped
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class Captcha:
|
||||
ctype = "captcha"
|
||||
|
||||
@@ -12,9 +53,22 @@ class Captcha:
|
||||
def get_balance(self) -> float:
|
||||
return self._solver.balance()
|
||||
|
||||
async def solve(self, selector: str, page: Page):
|
||||
async def solve(self, selector: str, page: Page) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
async def _run(self, fun, /, *args, **kwargs):
|
||||
resp = await asyncio.to_thread(fun, *args, **kwargs)
|
||||
return resp["code"]
|
||||
|
||||
async def hcaptcha(self, url, site_key, is_invisible):
|
||||
resp = await self._run(self._solver.hcaptcha, site_key, url, invisible=is_invisible)
|
||||
return resp
|
||||
|
||||
@cached_persistent('recaptcha')
|
||||
async def recaptcha(self, url, site_key):
|
||||
resp = await self._run(self._solver.recaptcha, site_key, url)
|
||||
return resp
|
||||
|
||||
|
||||
def load_captcha(key, captcha_type) -> Captcha:
|
||||
for cls in Captcha.__subclasses__():
|
||||
|
||||
@@ -10,6 +10,7 @@ textarea[id="h-captcha-response-0dm47zf0gn8t"]
|
||||
|
||||
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from .base import Captcha, Page
|
||||
@@ -23,12 +24,11 @@ class SolverHCaptcha(Captcha):
|
||||
ctype = "hcaptcha"
|
||||
|
||||
async def solve(self, selector, page: Page):
|
||||
# проверка что элемент с капчей есть
|
||||
div_container = page.locator(selector)
|
||||
await div_container.wait_for()
|
||||
|
||||
if not div_container:
|
||||
return None
|
||||
|
||||
# поиск данных и элементов
|
||||
site_key = await div_container.get_attribute("data-sitekey")
|
||||
is_invisible = bool(await div_container.get_attribute("data-invisible"))
|
||||
|
||||
@@ -39,7 +39,10 @@ class SolverHCaptcha(Captcha):
|
||||
textarea_g = await page.query_selector(f"#g-recaptcha-response-{textarea_id_postfix}")
|
||||
textarea_h = await page.query_selector(f"#h-captcha-response-{textarea_id_postfix}")
|
||||
|
||||
# решение
|
||||
code = await self.hcaptcha(page.url, site_key, is_invisible)
|
||||
|
||||
# подстановка решения
|
||||
await textarea_g.evaluate((
|
||||
"(el, value) => {"
|
||||
"el.value = value;"
|
||||
@@ -52,9 +55,4 @@ class SolverHCaptcha(Captcha):
|
||||
"el.dispatchEvent(new Event('input', {bubbles: true}));"
|
||||
"}"
|
||||
), code)
|
||||
return None
|
||||
|
||||
async def hcaptcha(self, url, site_key, is_invisible):
|
||||
resp = self._solver.hcaptcha(site_key, url, invisible=is_invisible)
|
||||
logger.debug(f"hcaptcha response: {resp}")
|
||||
return resp["code"]
|
||||
return code
|
||||
@@ -30,9 +30,6 @@ class SolverReCaptcha(Captcha):
|
||||
div_container = page.locator(selector)
|
||||
await div_container.wait_for()
|
||||
|
||||
if not div_container:
|
||||
return None
|
||||
|
||||
site_key_input_element = page.locator("iframe[title='reCAPTCHA']")
|
||||
src_value = await site_key_input_element.get_attribute("src")
|
||||
url_splitted = urlparse(src_value)
|
||||
@@ -49,9 +46,4 @@ class SolverReCaptcha(Captcha):
|
||||
"el.dispatchEvent(new Event('input', {bubbles: true}));"
|
||||
"}"
|
||||
), code)
|
||||
return None
|
||||
|
||||
async def recaptcha(self, url, site_key):
|
||||
resp = self._solver.recaptcha(site_key, url)
|
||||
logger.debug(f"recaptcha response: {resp}")
|
||||
return resp["code"]
|
||||
return code
|
||||
Reference in new issue
Block a user