J'essaie de gratter un site qui nécessite que l'utilisateur saisisse la valeur de recherche et un captcha. J'ai une routine de reconnaissance optique de caractères (OCR) pour le captcha qui réussit environ 33% du temps. Étant donné que les captchas sont toujours du texte alphabétique, je souhaite recharger le captcha si la fonction OCR renvoie des caractères non alphabétiques. Une fois que j'ai un texte "Word", je veux soumettre le formulaire de recherche.
Les résultats reviennent sur la même page, avec le formulaire prêt pour une nouvelle recherche et un nouveau captcha. Je dois donc rincer et répéter jusqu'à ce que j'aie épuisé mes termes de recherche.
Voici l'algorithme de niveau supérieur:
J'ai essayé d'utiliser un pipeline pour obtenir le captcha, mais je n'ai pas la valeur pour la soumission du formulaire. Si je récupère simplement l'image sans passer par le cadre, en utilisant urllib ou quelque chose, alors le cookie avec la session n'est pas soumis, donc la validation captcha sur le serveur échoue.
Quelle est la façon idéale Scrapy de faire cela?
C'est un sujet vraiment profond avec un tas de solutions. Mais si vous voulez appliquer la logique que vous avez définie dans votre article, vous pouvez utiliser des astuces Downloader Middlewares .
Quelque chose comme:
class CaptchaMiddleware(object):
max_retries = 5
def process_response(request, response, spider):
if not request.meta.get('solve_captcha', False):
return response # only solve requests that are marked with meta key
catpcha = find_catpcha(response)
if not captcha: # it might not have captcha at all!
return response
solved = solve_captcha(captcha)
if solved:
response.meta['catpcha'] = captcha
response.meta['solved_catpcha'] = solved
return response
else:
# retry page for new captcha
# prevent endless loop
if request.meta.get('catpcha_retries', 0) == 5:
logging.warning('max retries for captcha reached for {}'.format(request.url))
raise IgnoreRequest
request.meta['dont_filter'] = True
request.meta['captcha_retries'] = request.meta.get('captcha_retries', 0) + 1
return request
Cet exemple va intercepter chaque réponse et essayer de résoudre le captcha. En cas d'échec, il réessayera la page pour le nouveau captcha, s'il réussit, il ajoutera des méta-clés à la réponse avec des valeurs captcha résolues.
Dans votre araignée, vous l'utiliseriez comme ceci:
class MySpider(scrapy.Spider):
def parse(self, response):
url = ''# url that requires captcha
yield Request(url, callback=self.parse_captchad, meta={'solve_captcha': True},
errback=self.parse_fail)
def parse_captchad(self, response):
solved = response['solved']
# do stuff
def parse_fail(self, response):
# failed to retrieve captcha in 5 tries :(
# do stuff