2015-07-23 18 views
12

Il mio spider ha una perdita di memoria seria. Dopo 15 minuti di esecuzione la sua memoria 5gb e scrapy dice (usando prefs()) che 900k richiede oggetti e tutto questo. Quale può essere la ragione di questo alto numero di oggetti di richieste viventi? La richiesta sale solo e non va giù. Tutti gli altri oggetti sono vicini allo zero.Perdita di memoria di Scrapy spider

mio ragno si presenta così:

class ExternalLinkSpider(CrawlSpider): 
    name = 'external_link_spider' 
    allowed_domains = [''] 
    start_urls = [''] 

    rules = (Rule(LxmlLinkExtractor(allow=()), callback='parse_obj', follow=True),) 

    def parse_obj(self, response): 
    if not isinstance(response, HtmlResponse): 
     return 
    for link in LxmlLinkExtractor(allow=(), deny=self.allowed_domains).extract_links(response): 
     if not link.nofollow: 
      yield LinkCrawlItem(domain=link.url) 

Qui uscita di preferenze()

HtmlResponse      2 oldest: 0s ago 
ExternalLinkSpider     1 oldest: 3285s ago 
LinkCrawlItem      2 oldest: 0s ago 
Request      1663405 oldest: 3284s ago 

Memoria per 100k raschiato pagine possono colpire marchio 40GB su alcuni siti (per esempio a victorinox.com esso raggiungere 35GB di memoria a 100k segnati pagine raschiate). In altri è molto meno.

UPD.

Objgraph for oldest request after some time of run

enter image description here

risposta

7

Ci sono alcuni problemi possibili che vedo subito.

Prima di iniziare, volevo menzionare che prefs() non mostra il numero di richieste in coda, mostra il numero di oggetti Request() che sono attivi. È possibile fare riferimento a un oggetto richiesta e mantenerlo attivo, anche se non è più in coda per il download.

Non vedo davvero nulla nel codice che hai fornito che potrebbe causare questo, ma è necessario tenerlo a mente.

Proprio da pipistrello, vorrei chiedere: stai usando i cookie? In caso contrario, i siti che passano attorno a un ID di sessione come variabile GET genereranno un nuovo ID di sessione per ogni visita di pagina. In pratica continuerai ad accodare le stesse pagine all'infinito. Ad esempio, victorinox.com avrà qualcosa come "jsessionid = 18537CBA2F198E3C1A5C9EE17B6C63AD" nella sua stringa URL, con l'ID che cambia per ogni nuovo caricamento della pagina.

In secondo luogo, è possibile che si stia colpendo una trappola a ragno. Cioè, una pagina che si ricarica da sola, con una nuova infinita quantità di link. Pensa a un calendario con un link a "mese prossimo" e "mese precedente". Non sto vedendo direttamente alcuno su victorinox.com, comunque.

In terzo luogo, dal codice fornito lo Spider non è vincolato a un dominio specifico. Estrae ogni collegamento che trova in ogni pagina, eseguendo parse_obj su ognuno di essi. La pagina principale di victorinox.com, ad esempio, ha un collegamento a http://www.youtube.com/victorinoxswissarmy. Questo a sua volta riempirà le tue richieste con tonnellate di link di YouTube.

Avrete bisogno di risolvere altri problemi per scoprire esattamente cosa sta succedendo, però.

Alcune strategie si consiglia di utilizzare:

  1. creare un nuovo Downloader Middleware e accedere a tutte le vostre richieste (in un file o database). Esaminare le richieste di comportamenti strani.
  2. Limita la profondità per impedire che continui ininterrottamente nella tana del coniglio.
  3. Limitare il dominio per verificare se è ancora un problema.

Se si trova che si sta legittimamente solo generando molte richieste e la memoria è un problema, abilitare la coda di lavoro permanente e salvare le richieste su disco, invece. In ogni caso, mi raccomando contro questo come primo passo, poiché è più probabile che il tuo crawler non funzioni come volevi.

+0

Terzo: il mio codice è limitato a un dominio. Ma il dominio può da qualsiasi. Im impostazione di domini consentiti in modo dinamico, quindi im afferrare solo un dominio alla volta. Per quanto riguarda i biscotti - buon punto. Coda persistente: ho detto a utenti scrapy che sono molto molto lenti con un gran numero di richieste, quindi non è un'opzione :( – Aldarund

+0

Ok, non è stato mostrato nel tuo codice, motivo per cui l'ho menzionato! La coda persistente è lento, però, ed è progettato per sospendere/riprendere le code, credo. La differenza di velocità è in realtà memoria vs disco in questa istanza. – Rejected

+0

Im imposta anche una coda FifoMemoryQueue ma l'oggetto di richiesta più vecchio è quasi vecchio come lo spider Oggetto: non dovrebbe essere elaborato e rilasciato? – Aldarund