miyakogi / pyppeteer

Headless chrome/chromium automation library (unofficial port of puppeteer)
Other
3.56k stars 372 forks source link

Raises an error after captcha solving #164

Open vbxx3 opened 5 years ago

vbxx3 commented 5 years ago

I scrap website with recaptcha, after it solves captcha raises an error.

    async def _captcha(self):
        if await self.__page.title() == 'xxx':
            await self.__page.screenshot({'path': 'screenshots/distil.png'}, fullPage=True)
            website_key = await self.__page.Jeval('#dCF_input', 'elem => elem.getAttribute("data-sitekey")')
            user_answer = await NoCaptchaTaskProxyless.aioNoCaptchaTaskProxyless(anticaptcha_key=self._anticaptcha_key)\
                .captcha_handler(websiteURL=self.__page.url,
                                 websiteKey=website_key)
              ''' On function below raises an error'''
            await self.__page.type('#g-recaptcha-response', user_answer['solution']['gRecaptchaResponse'])
            await self.__page.screenshot({'path': 'screenshots/distil_solved.png'}, fullPage=True)
            await self.__page.Jeval('#dCF_input_complete', 'form => form.click()')

    async def scrap(self):
        text = 'elem => elem.textContent'
        href = 'elem => elem.href'
        src = 'elem => elem.src'

        self.__browser = await launch(args=('--window-size=1920,1080', '--start-fullscreen'))
        #context = await self.__browser.createIncognitoBrowserContext()
        self.__page = await self.__browser.newPage()
        await self.__page.setJavaScriptEnabled(False)
        await self.__page.goto('example.com')
        await self._captcha()
        await self.__page.screenshot({'path': 'screenshots/end.png'}, fullPage=True)

Traceback:

Traceback (most recent call last):
  File "C:/xxx/xxx_scraping/main_pypp.py", line 64, in <module>
    asyncio.get_event_loop().run_until_complete(sr.scrap())
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 568, in run_until_complete
    return future.result()
  File "C:/xxxxxx/xxx_scraping/main_pypp.py", line 57, in scrap
    await self._distil()
  File "C:/xxx/xxx_scraping/main_pypp.py", line 43, in _distil
    await self.__page.type('#g-recaptcha-response', user_answer['solution']['gRecaptchaResponse'])
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\page.py", line 1550, in type
    return await frame.type(selector, text, options, **kwargs)
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\frame_manager.py", line 644, in type
    handle = await self.querySelector(selector)
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\frame_manager.py", line 303, in querySelector
    value = await document.querySelector(selector)
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\element_handle.py", line 351, in querySelector
    self, selector,
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\execution_context.py", line 109, in evaluateHandle
    _rewriteError(e)
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\execution_context.py", line 239, in _rewriteError
    raise error
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\execution_context.py", line 106, in evaluateHandle
    'userGesture': True,
  File "C:\!projects\xxx_scrap\venv\lib\site-packages\pyppeteer\connection.py", line 218, in send
    f'Protocol Error ({method}): Session closed. Most likely the '
pyppeteer.errors.NetworkError: Protocol Error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.

print(self.__page.isClosed()) after captcha returns False

vbxx3 commented 5 years ago

It seems like captcha's func is a reason of this issue

class aioNoCaptchaTaskProxyless:
    def __init__(self, anticaptcha_key, sleep_time=5, **kwargs):
        """
        Модуль отвечает за решение ReCaptcha без прокси
        :param anticaptcha_key: Ключ антикапчи
        :param sleep_time: Время ожидания решения капчи
        :param kwargs: Другие необязательные параметры из документации
        """
        if sleep_time < 5:
            raise ValueError(f'Параметр `sleep_time` должен быть не менее 5. Вы передали - {sleep_time}')
        self.sleep_time = sleep_time

        # Пайлоад для создания задачи
        self.task_payload = {"clientKey": anticaptcha_key,
                             "task":
                                 {
                                     "type": "NoCaptchaTaskProxyless",
                                 },
                             "softId": app_key
                             }

        # Пайлоад для получения результата
        self.result_payload = {"clientKey": anticaptcha_key}

        # Если переданы ещё параметры - вносим их в payload
        if kwargs:
            for key in kwargs:
                self.task_payload['task'].update({key: kwargs[key]})

    # Работа с капчёй
    async def captcha_handler(self, websiteURL, websiteKey):
        """
        Метод решения ReCaptcha
        :param websiteURL: Ссылка на страницу с капчёй
        :param websiteKey: Ключ капчи сайта(как получить - написано в документации)
        :return: Возвращает ответ сервера в виде JSON-строки
        """

        # вставляем в пайлоад адрес страницы и ключ-индентификатор рекапчи
        self.task_payload['task'].update({"websiteURL": websiteURL,
                                          "websiteKey": websiteKey})
        # Отправляем на антикапчу пайлоад
        # в результате получаем JSON ответ содержащий номер решаемой капчи
        async with aiohttp.ClientSession() as session:
            async with session.post(create_task_url, json=self.task_payload) as resp:
                captcha_id = await resp.json()

        # Проверка статуса создания задачи, если создано без ошибок - извлекаем ID задачи, иначе возвращаем ответ сервера
        if captcha_id['errorId'] == 0:
            captcha_id = captcha_id["taskId"]
            self.result_payload.update({"taskId": captcha_id})
        else:
            return captcha_id

        # Ждем решения капчи
        await asyncio.sleep(self.sleep_time)
        return await get_async_result(result_payload=self.result_payload, sleep_time=self.sleep_time)