2012-06-11 15 views
8

Jestem nowy w złomowaniu. Piszę pająka zaprojektowanego do sprawdzania długiej listy adresów URL dla kodów statusu serwera i, w razie potrzeby, jakie adresy URL są przekierowywane. Co ważne, jeśli istnieje łańcuch przekierowań, podczas każdego skoku muszę znać kod statusu i adres URL. Używam response.meta ['redirect_urls'] do przechwytywania adresów URL, ale nie jestem pewien, jak przechwycić kody stanu - nie wydaje się, aby był to klucz meta odpowiedzi.Przechwytywanie kodów stanu http za pomocą scrapy pająk

Zdaję sobie sprawę, że być może będę musiał napisać niestandardową odzież sportową, aby ujawnić te wartości, ale nie jestem do końca jasny, jak rejestrować kody statusu dla każdego skoku, ani jak uzyskać dostęp do tych wartości z pająka. Spojrzałem, ale nie mogę znaleźć przykładu, by ktoś to zrobił. Jeśli ktokolwiek może wskazać mi właściwy kierunek, byłoby to bardzo cenne.

Na przykład

items = [] 
    item = RedirectItem() 
    item['url'] = response.url 
    item['redirected_urls'] = response.meta['redirect_urls']  
    item['status_codes'] = #???? 
    items.append(item) 

Edit - W oparciu o informacje zwrotne od warawauk a niektóre naprawdę aktywnej pomocy ze strony facetów na kanale IRC (freenode #scrappy) udało mi się to zrobić. Uważam, że to trochę hacky więc żadnych komentarzy do poprawy powitanie:

(1) Wyłącz domyślny middleware w ustawieniach, a także dodawać własne:

DOWNLOADER_MIDDLEWARES = { 
    'scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware': None, 
    'myproject.middlewares.CustomRedirectMiddleware': 100, 
} 

(2) Utwórz CustomRedirectMiddleware w swoich middleware .py. Dziedziczy z głównej klasy redirectmiddleware i oddaje przekierowanie:

class CustomRedirectMiddleware(RedirectMiddleware): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def process_response(self, request, response, spider): 
     #Get the redirect status codes 
     request.meta.setdefault('redirect_status', []).append(response.status) 
     if 'dont_redirect' in request.meta: 
      return response 
     if request.method.upper() == 'HEAD': 
      if response.status in [301, 302, 303, 307] and 'Location' in response.headers: 
       redirected_url = urljoin(request.url, response.headers['location']) 
       redirected = request.replace(url=redirected_url) 

       return self._redirect(redirected, request, spider, response.status) 
      else: 
       return response 

     if response.status in [302, 303] and 'Location' in response.headers: 
      redirected_url = urljoin(request.url, response.headers['location']) 
      redirected = self._redirect_request_using_get(request, redirected_url) 
      return self._redirect(redirected, request, spider, response.status) 

     if response.status in [301, 307] and 'Location' in response.headers: 
      redirected_url = urljoin(request.url, response.headers['location']) 
      redirected = request.replace(url=redirected_url) 
      return self._redirect(redirected, request, spider, response.status) 

     if isinstance(response, HtmlResponse): 
      interval, url = get_meta_refresh(response) 
      if url and interval < self.max_metarefresh_delay: 
       redirected = self._redirect_request_using_get(request, url) 
       return self._redirect(redirected, request, spider, 'meta refresh') 


     return response 

(3) można uzyskać dostęp do listy przekierowań w pająka z

request.meta['redirect_status'] 
+1

Powinieneś zamieścić swoje rozwiązanie jako odpowiedź – raben

Odpowiedz

2

wierzę, że jest dostępny jako

response.status 

Zobacz http://doc.scrapy.org/en/0.14/topics/request-response.html#scrapy.http.Response

+0

Dziękuję za odpowiedź Linde. Moja trudność polega na tym, że typowe użycie response.status zapewnia status odpowiedzi ostatecznej po wszystkich przekierowaniach. Potrzebuję response.status na każdy skok i nie jestem pewien, jak je wszystkie przechwycić. Czy to ma sens? – reportingmonkey

+0

Możesz równie dobrze dodać kod statusu w taki sam sposób, w jaki wypełniasz ['redirect_urls'];) –

+0

Och, rozumiem, źle zrozumiałem. Następnie myślę, że musisz podklasy 'scrapy.contrib.spidermiddleware.SpiderMiddleware' zgodnie z http://doc.scrapy.org/en/0.14/topics/spider-middleware.html#writing-your-own-spider-middleware i nadpisuje 'process_spider_input', aby dołączyć pośrednie kody statusu do, powiedzmy,' response.meta ['status_codes'] 'które powinno być zainicjowane jako pusta lista. Ale nie próbowałem tego. – lindelof

3

response.meta['redirect_urls' jest wypełnione przez RedirectMiddleware. Twój callback pająka nigdy nie otrzyma odpowiedzi pomiędzy, a dopiero ostatni po wszystkich przekierowaniach.

Jeśli chcesz kontrolować proces, podklasę RedirectMiddleware, wyłącz oryginalną i włącz swoją. Następnie możesz kontrolować proces przekierowania, w tym śledzić statusy odpowiedzi.

Oto oryginalna implementacja (scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware):

class RedirectMiddleware(object): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def _redirect(self, redirected, request, spider, reason): 
     ... 
            redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \ 
                [request.url] 

Jak widać _redirect metoda, która jest wywoływana z różnych części tworzy meta['redirect_urls']

A w metodzie process_responsereturn self._redirect(redirected, request, spider, response.status) jest wywołany, co oznacza, że ​​oryginalna odpowiedź nie jest przekazywana do pająka.

+0

Dzięki warwaruk, to ma sens. Patrzyłem na redirectmiddleware. Myślę, że mogę tę inżynierię odwrócić. Wydaje mi się, że nadal czegoś tu brakuje, ponieważ ta klasa odwołuje się do request.meta.get ['redirect_urls'], więc myślę, że wartości są przekazywane dla każdego żądania. Ma to również sens, ale nie mogę stwierdzić, gdzie tak naprawdę się dzieje. Będę edytować mój pierwotny post, aby sprawdzić, czy mogę wyjaśnić, gdzie walczę – reportingmonkey

+0

@ user1449163, to oprogramowanie pośrednie jest tym, który tworzy 'meta ['redirect_urls']' - zobacz aktualizację odpowiedzi – warvariuc

0

rozwiązanie KISS: Myślałem, że lepiej, aby dodać ścisłego minimum kodu do przechwytywania nowe pole przekierowania, i niech RedirectMiddleware zajmiemy się resztą:

from scrapy.contrib.downloadermiddleware.redirect import RedirectMiddleware 

class CustomRedirectMiddleware(RedirectMiddleware): 
    """Handle redirection of requests based on response status and meta-refresh html tag""" 

    def process_response(self, request, response, spider): 
    #Get the redirect status codes 
    request.meta.setdefault('redirect_status', []).append(response.status) 
    response = super(CustomRedirectMiddleware, self).process_response(request, response, spider) 
    return response 

Następnie instacji BaseSpider, można uzyskać dostęp do redirect_status z następującą wersją:

def parse(self, response): 
     item = ScrapyGoogleindexItem() 
     item['redirections'] = response.meta.get('redirect_times', 0) 
     item['redirect_status'] = response.meta['redirect_status'] 
     return item 
Powiązane problemy