Как контролировать поток запросов в scrapy при обработке Google recaptcha v2 с помощью сервиса deathbycaptcha?

1

Привет :) Я работаю с scrapy web crawling framework, используя python, соскабливая веб-сайт и решая капчу, с которой я сталкиваюсь на своей странице с сервисом deathbycaptcha. Моя задержка загрузки установлена на 30 секунд, и я просто очищаю несколько страниц, чтобы получить основную информацию, так что я не слишком сильно вторгаюсь в пропускную способность сайтов или что-то в этом роде. Я рассматриваю выскабливание как опыт, который будет происходить в обычном браузере.

Поэтому сначала поговорим о проблемах.

ISSUE 1 (в коде) Как мне получить зачистку, чтобы в основном прекратить создавать новые запросы или слишком много вовлекаться в капчу во время ее решения? Я пробовал много разных вещей, все это не принесло пользы, и я довольно новичок в scrapy, поэтому я не очень разбираюсь в редактировании middleware для скачивания или в коде двигателя scrapy, но если это единственный способ сделать это, но я надеюсь на очень простое и эффективное решение, чтобы просто позволить captcha делать это, без новых запросов, прерывающих его вообще.

ISSUE 2 (в коде) Как исправить эту функцию таймера, которая, как мне кажется, коррелирует с первой проблемой. Если тайм-аут на captcha выходит без решения, он никогда не перезапустит логический captchaIsRunning и не позволит ему captchaIsRunning попытку снова решить проблему. Таймер существует как одно из моих попыток решения первой проблемы, но... Я получаю сообщение об ошибке. Не уверен, имеет ли он какое-либо отношение к тому факту, что вытягивается из threading и timeit в timeit импорта, но я не думал, что это имеет большое значение. Может ли кто-нибудь вести меня в правильном направлении для фиксации заявления о таймере?

Как я уже сказал, API-интерфейс deathbycaptcha работает нормально, когда у него есть шанс, но запросы на выборку действительно мешают, и я не смог найти подходящего решения этой проблемы. Опять же, я не эксперт по скрипам, но некоторые вещи были далеко от моей зоны комфорта, которую нужно толкнуть, но не слишком сложно, что я в конечном итоге сломаю все. XD Спасибо за помощь, которую мы очень ценим! Извините за этот очень длинный вопрос.

Во всяком случае, страница позволяет вам найти пару результатов, а после примерно о 40-60 страниц она перенаправляется на страницу captcha с recaptcha v2. У службы deathbycaptcha есть API для решения recaptcha v2, но, к сожалению, время их решения может быть значительно более чем на пару минут, что очень неутешительно, но это происходит. Поэтому, естественно, я настроил параметр DOWNLOAD_TIMEOUT на 240 секунд, чтобы у него было достаточно времени, чтобы решить капчу, и продолжайте соскабливать после этого, чтобы он больше не перенаправлялся. Мои настройки scrapy следующие:

CONCURRENT_REQUESTS = 1
DEPTH_LIMIT = 1
DOWNLOAD_DELAY = 30
CONCURRENT_REQUESTS_PER_DOMAIN = 1
CONCURRENT_REQUESTS_PER_IP = 1
DOWNLOAD_TIMEOUT = 240
AUTOTHROTTLE_ENABLED = True
# The initial download delay
AUTOTHROTTLE_START_DELAY = 10
# The maximum download delay to be set in case of high latencies
AUTOTHROTTLE_MAX_DELAY = 60

И тогда, очевидно, остальные, но я подумал, что это были самые важные для моей проблемы. У меня есть одно расширение включено, а затем у middlewares есть пара дополнительных вещей, потому что я также работал с докером и всплеском в этом файле.

SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

MYEXT_ENABLED = False
MYEXT_ITEMCOUNT = 100

EXTENSIONS = {
   'scrapy.extensions.telnet.TelnetConsole': None,
   'scrapy.extensions.spideroclog.SpiderOpenCloseLogging':500,
}

Таким образом, я не думаю, что этот материал влияет на перехватчик или загрузчик в целом. Но вот некоторые из кода моего скребка:

Python:

import sys
import os
sys.path.append(r'F:\Documents\ScrapyDirectory\scrapername\scrapername\spiders')
import deathbycaptcha
import json
import scrapy
import requests
from datetime import datetime
import math
import urllib
import time
from scrapy_splash import SplashRequest
from threading import Timer
from timeit import Timer

class scrapername(scrapy.Spider):
    name = "scrapername"
    start_urls = []

    global scrapeUrlList
    global charCompStorage
    global captchaIsRunning

    r = requests.get('http://example.com/examplejsonfeed.php')

    myObject = json.loads(r.text)

    #print("Loading names...")
    for o in myObject['objects']:
        #a huge function for creating basically a lot of objects and appending links created from these objects to the scrapeUrlList function

    print(len(scrapeUrlList))
    for url in scrapeUrlList:
        start_urls.append(url[1])
        #add all those urls that just got created to the start_urls list


    link_collection = []

    def resetCaptchaInformation():
        global captchaIsRunning
        if captchaIsRunning:
            captchaIsRunning = False

    def afterCaptchaSubmit(self, response):
        global captchaIsRunning
        print("Captcha submitted: " + response.request.url)
        captchaIsRunning = False

    def parse(self, response):
        global captchaIsRunning
        self.logger.info("got response %s for %r" % (response.status, response.url))

        if "InternalCaptcha" in response.request.url:
        #checks for captcha in the url and if it there it starts running the captcha solver API
            if not captchaIsRunning:
            #I have this statement here as a deterrent to prevent the captcha solver from starting again and again and 
            #again with every new request (which it does)  *ISSUE 1*
                if "captchasubmit" in response.request.url:
                    print("Found captcha submit in url")
                else:
                    print("Internal Captcha is activated")
                    captchaIsRunning = True
                    t = Timer(240.0, self.resetCaptchaInformation)
                    #so I have been having major issues here not sure why?
                    #*ISSUE 2*
                    t.start()

                    username = "username"
                    password = "password"

                    print("Set username and password")

                    Captcha_dict = {
                    'googlekey': '6LcMUhgUAAAAAPn2MfvqN9KYxj7KVut-oCG2oCoK',
                    'pageurl': response.request.url}

                    print("Created catpcha dict")

                    json_Captcha = json.dumps(Captcha_dict)

                    print("json.dumps on captcha dict:")
                    print(json_Captcha)

                    client = deathbycaptcha.SocketClient(username, password)

                    print("Set up client with deathbycaptcha socket client")

                    try:
                        print("Trying to solve captcha")
                        balance = client.get_balance()

                        print("Remaining Balance: " + str(balance))

                        # Put your CAPTCHA type and Json payload here:
                        captcha = client.decode(type=4,token_params=json_Captcha)

                        if captcha:
                            # The CAPTCHA was solved; captcha["captcha"] item holds its
                            # numeric ID, and captcha["text"] item its a text token".
                            print("CAPTCHA %s solved: %s" % (captcha["captcha"], captcha["text"]))

                            data = {
                                'g-recaptcha-response':captcha["text"],
                            }

                            try:
                                dest = response.xpath("/html/body/form/@action").extract_first()
                                print("Form URL: " + dest)
                                submitURL = "https://exampleaddress.com" + dest
                                yield scrapy.FormRequest(url=submitURL, formdata=data, callback=self.afterCaptchaSubmit, dont_filter = True)

                                print("Yielded form request")

                                if '':  # check if the CAPTCHA was incorrectly solved
                                    client.report(captcha["captcha"])
                            except TypeError:
                                sys.exit()
                    except deathbycaptcha.AccessDeniedException:
                        # Access to DBC API denied, check your credentials and/or balance
                        print("error: Access to DBC API denied, check your credentials and/or balance")
            else:
                pass
        else:
            print("no Captcha")
            #this will run if no captcha is on the page that the redirect landed on
            #and basically parses all the information on the page

Извините за весь этот код, благодарю вас за ваше терпение в чтении. Если у вас есть какие-либо вопросы относительно того, почему что-то есть, просто спросите, чтобы я мог объяснить. ТАК КАЧКА РЕШАЕТ. Это не проблема. Когда скребок запущен и происходит много запросов, и он запускается в перенаправление 302, он получает ответ 200 и обходит страницу, обнаруживает капчу и начинает ее решать. Затем scrapy отправляет другой запрос, который получает перенаправление 302, ответ 200 на странице captcha и обнаруживает капчу и пытается ее решить снова. Он запускал API несколько раз и тратил мои жетоны. Следовательно, if not captchaIsRunning: заявления, чтобы остановить это. Итак, вот журналы scrapy, которые я сейчас выставляю, когда они попадают в капчу, помните все, прежде чем это было просто прекрасно, запустив все мои журналы разбора.

Журналы:

2018-07-19 14:10:35 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (302) to <GET https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dThomas%2520Garrett%26citystatezip%3dLas%2520Vegas%2c%2520Nv> from <GET https://www.exampleaddress.com/results?name=Thomas%20Garrett&citystatezip=Las%20Vegas,%20Nv>
2018-07-19 14:10:49 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dThomas%2520Garrett%26citystatezip%3dLas%2520Vegas%2c%2520Nv> (referer: None)
2018-07-19 14:10:49 [scrapername] INFO: got response 200 for 'https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dThomas%2520Garrett%26citystatezip%3dLas%2520Vegas%2c%2520Nv'
Internal Captcha is activated
2018-07-19 14:10:49 [scrapy.core.scraper] ERROR: Spider error processing <GET https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dThomas%2520Garrett%26citystatezip%3dLas%2520Vegas%2c%2520Nv> (referer: None)
Traceback (most recent call last):
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy\utils\defer.py", line 102, in iter_errback
    yield next(it)
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy_splash\middleware.py", line 156, in process_spider_output
    for el in result:
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy\spidermiddlewares\offsite.py", line 29, in process_spider_output
    for x in result:
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy\spidermiddlewares\referer.py", line 339, in <genexpr>
    return (_set_referer(r) for r in result or ())
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy\spidermiddlewares\urllength.py", line 37, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "F:\Program Files (x86)\Anaconda3\lib\site-packages\scrapy\spidermiddlewares\depth.py", line 58, in <genexpr>
    return (r for r in result or () if _filter(r))
  File "F:\Documents\ScrapyDirectory\scraperName\scraperName\spiders\scraperName- Copy.py", line 232, in parse
    t = Timer(240.0, self.resetCaptchaInformation)
  File "F:\Program Files (x86)\Anaconda3\lib\timeit.py", line 130, in __init__
    raise ValueError("stmt is neither a string nor callable")
ValueError: stmt is neither a string nor callable
2018-07-19 14:10:53 [scrapy.extensions.logstats] INFO: Crawled 63 pages (at 2 pages/min), scraped 13 items (at 0 items/min)
2018-07-19 14:11:02 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (302) to <GET https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dSamuel%2520Van%2520Cleave%26citystatezip%3dLas%2520Vegas%2c%2520Nv> from <GET https://www.exampleaddress.com/results?name=Samuel%20Van%20Cleave&citystatezip=Las%20Vegas,%20Nv>
2018-07-19 14:11:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dSamuel%2520Van%2520Cleave%26citystatezip%3dLas%2520Vegas%2c%2520Nv> (referer: None)
2018-07-19 14:11:13 [scrapername] INFO: got response 200 for 'https://www.exampleaddress.com/InternalCaptcha?returnUrl=%2fresults%3fname%3dSamuel%2520Van%2520Cleave%26citystatezip%3dLas%2520Vegas%2c%2520Nv'
#and then an endless supply of 302 redirects, and 200 response for their crawl
#nothing happens, because the Timer failed, the captcha never solved?
#I'm not sure what is going wrong with it, hence the issues I am having
Теги:
web-scraping
scrapy
recaptcha

1 ответ

0

Мне все еще нужно несколько недель больше опыта для решения вашей проблемы, но я бы попытался использовать RetryMiddleware:

Вероятно, добавить 302 кодов повтора достаточно:

RETRY_HTTP_CODES
Default: [500, 502, 503, 504, 408]

https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#retry-http-codes

  • 0
    Это действительное предложение, спасибо :) К сожалению, я не думаю, что это решит мою проблему, поскольку мне не нужно повторять 302. 302 работает очень хорошо, перенаправляет меня на страницу с изображением капчи, а затем дает мне ответ 200 для этой страницы, на котором начинает выполняться мой код для решения проблемы с капчей :) Все совершенно нормально. Итак, я предполагаю, что ваше решение может быть направлено на мою функцию таймера, может быть? В любом случае мне нужно повторить попытку через 4 минуты или в другое время, которое я установил, если решение еще не закончено. Мне действительно нужно, чтобы 302 запускался один раз, пока капча не будет сделана.
  • 0
    Как только капча решена, переадресаций не будет больше 302, пока веб-сайт не решит, что хочет выставить мне другую капчу. Как только капча решена, она ползет 200-х весь день. Проблема заключается в том, что, если я не решу, капча будет продолжать отправлять 302 журнала, как вы можете видеть в разделе «Журналы Scrapy» моего кода.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню