2016-08-25 44 views
10

Próbuję zeskrobać witrynę, która wymaga od użytkownika wprowadzenia wartości wyszukiwania i captcha. Mam funkcję rozpoznawania znaków optycznych (OCR) dla captcha, która udaje się w 33% przypadków. Ponieważ captcha są zawsze tekstem alfabetycznym, chcę ponownie załadować captcha, jeśli funkcja OCR zwraca znaki niealfabetyczne. Kiedy mam "słowo" tekstowe, chcę przesłać formularz wyszukiwania.Jak skonfigurować Scrapy do radzenia sobie z captcha

Wyniki powracają na tę samą stronę, a formularz jest gotowy do nowego wyszukiwania i nowego captcha. Muszę więc spłukać i powtarzać, dopóki nie wyczerpam moich wyszukiwanych słów.

Oto algorytm najwyższego poziomu:

  1. strona obciążenia początkowo
  2. Pobierz obraz captcha, uruchom go poprzez OCR
  3. Jeśli OCR nie wróci z tekstu tylko spowodować , odśwież captcha i powtórz ten krok.
  4. Prześlij formularz zapytania na stronie z wyszukiwanym hasłem i captcha
  5. Sprawdź odpowiedź, aby sprawdzić, czy captcha był prawidłowy
  6. Gdyby to było prawidłowe, zeskrobać dane
  7. Go do 2

Próbowałem za pomocą rurociągu dla uzyskania captcha, ale wtedy nie mam wartość składania formularza. Jeśli po prostu pobieram obraz bez przechodzenia przez framework, używając urllib lub czegoś takiego, plik cookie z sesją nie zostanie przesłany, więc sprawdzanie poprawności captcha na serwerze nie powiedzie się.

Jaki jest idealny sposób na wykonanie Scrapy?

Odpowiedz

7

To naprawdę głęboki temat z wieloma rozwiązaniami. Ale jeśli chcesz zastosować logikę, którą zdefiniowałeś w swoim poście, możesz użyć scrapy Downloader Middlewares.

Coś jak:

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 

Ten przykład przechwycić każdą odpowiedź i spróbować rozwiązać captcha. Jeśli się nie uda, ponowi próbkę strony dla nowego captcha, jeśli się powiedzie, doda kilka kluczy meta do odpowiedzi z rozwiązanymi wartościami captcha.
W twoim pająku użyjesz go w ten sposób:

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