2013-03-13 14 views
12

Quando ho iniziato a imparare scrapy, sono giunto al requisito di creare dinamicamente gli attributi Item. Sto solo raschiando una pagina web che ha una struttura di tabella e volevo formare l'elemento e gli attributi del campo durante la scansione. Ho analizzato questo esempio Scraping data without having to explicitly define each field to be scraped ma non ci sono riuscito.Scrapy: Definire dinamicamente gli articoli

Devo scrivere una pipeline di elementi per acquisire le informazioni in modo dinamico. Ho anche esaminato la funzione Caricatore di oggetti, ma se qualcuno può spiegare in dettaglio, sarà davvero utile.

+0

Se si potesse fornire un esempio della struttura della tabella e di come può variare, ciò renderebbe più semplice rispondere a questa domanda. – Talvalin

+0

Talvalin, è indipendente dalla struttura della tabella, vorrei aggiungere elementi e inviarlo alla pipeline dinamicamente, senza doverli definire esplicitamente nella classe items.py. apprezza la tua risposta – Srikanth

+2

Ho avuto più successo usando una sottoclasse Item che sovrascrive 'self.fields' con un defaultdict [come mostrato in questa risposta] (http://stackoverflow.com/a/24357273/149872). – elias

risposta

9

Basta usare un singolo campo come segnaposto di dati arbitrari. E poi quando vuoi ottenere i dati, invece di dire for field in item, dici for field in item['row']. Non è necessario pipelines o loaders per eseguire questa operazione, ma sono entrambi ampiamente utilizzati per una buona ragione: vale la pena imparare.

ragno:

from scrapy.item import Item, Field 
from scrapy.spider import BaseSpider 

class TableItem(Item): 
    row = Field() 

class TestSider(BaseSpider): 
    name = "tabletest" 
    start_urls = ('http://scrapy.org?finger', 'http://example.com/toe') 

    def parse(self, response): 
     item = TableItem() 

     row = dict(
      foo='bar', 
      baz=[123, 'test'], 
     ) 
     row['url'] = response.url 

     if 'finger' in response.url: 
      row['digit'] = 'my finger' 
      row['appendage'] = 'hand' 
     else: 
      row['foot'] = 'might be my toe' 

     item['row'] = row 

     return item 

outptut:

[email protected]:/srv/stav/scrapie/oneoff$ scrapy crawl tabletest 
2013-03-14 06:55:52-0600 [scrapy] INFO: Scrapy 0.17.0 started (bot: oneoff) 
2013-03-14 06:55:52-0600 [scrapy] DEBUG: Overridden settings: {'NEWSPIDER_MODULE': 'oneoff.spiders', 'SPIDER_MODULES': ['oneoff.spiders'], 'USER_AGENT': 'Chromium OneOff 24.0.1312.56 Ubuntu 12.04 (24.0.1312.56-0ubuntu0.12.04.1)', 'BOT_NAME': 'oneoff'} 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Enabled extensions: LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Enabled item pipelines: 
2013-03-14 06:55:53-0600 [tabletest] INFO: Spider opened 
2013-03-14 06:55:53-0600 [tabletest] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 
2013-03-14 06:55:53-0600 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Crawled (200) <GET http://scrapy.org?finger> (referer: None) 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Scraped from <200 http://scrapy.org?finger> 
    {'row': {'appendage': 'hand', 
      'baz': [123, 'test'], 
      'digit': 'my finger', 
      'foo': 'bar', 
      'url': 'http://scrapy.org?finger'}} 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Redirecting (302) to <GET http://www.iana.org/domains/example/> from <GET http://example.com/toe> 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Redirecting (302) to <GET http://www.iana.org/domains/example> from <GET http://www.iana.org/domains/example/> 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Crawled (200) <GET http://www.iana.org/domains/example> (referer: None) 
2013-03-14 06:55:53-0600 [tabletest] DEBUG: Scraped from <200 http://www.iana.org/domains/example> 
    {'row': {'baz': [123, 'test'], 
      'foo': 'bar', 
      'foot': 'might be my toe', 
      'url': 'http://www.iana.org/domains/example'}} 
2013-03-14 06:55:53-0600 [tabletest] INFO: Closing spider (finished) 
2013-03-14 06:55:53-0600 [tabletest] INFO: Dumping Scrapy stats: 
    {'downloader/request_bytes': 1066, 
    'downloader/request_count': 4, 
    'downloader/request_method_count/GET': 4, 
    'downloader/response_bytes': 3833, 
    'downloader/response_count': 4, 
    'downloader/response_status_count/200': 2, 
    'downloader/response_status_count/302': 2, 
    'finish_reason': 'finished', 
    'finish_time': datetime.datetime(2013, 3, 14, 12, 55, 53, 848735), 
    'item_scraped_count': 2, 
    'log_count/DEBUG': 13, 
    'log_count/INFO': 4, 
    'response_received_count': 2, 
    'scheduler/dequeued': 4, 
    'scheduler/dequeued/memory': 4, 
    'scheduler/enqueued': 4, 
    'scheduler/enqueued/memory': 4, 
    'start_time': datetime.datetime(2013, 3, 14, 12, 55, 53, 99635)} 
2013-03-14 06:55:53-0600 [tabletest] INFO: Spider closed (finished) 
+0

anche se ... Mi stavo riflettendo sulla spiegazione nella gestione dei dati con caricatori di oggetti e condutture ... Questo è un workaorund per far muovere le cose ... grazie comunque .. – Srikanth

7

utilizzare questa classe:

class Arbitrary(Item): 
    def __setitem__(self, key, value): 
     self._values[key] = value 
     self.fields[key] = {} 
0

ero più xpecting su spiegazione nella gestione dei dati con caricatori delle voci e le tubazioni

Assumendo:

fieldname = 'test' 
fieldxpath = '//h1' 

E '(nelle versioni più recenti) molto semplice ...

item = Item() 
l = ItemLoader(item=item, response=response) 

item.fields[fieldname] = Field() 
l.add_xpath(fieldname, fieldxpath) 

return l.load_item() 
2

So che la mia risposta è in ritardo, ma per chi ancora bisogno di un elementi dinamici utilizzando Scrapy, ho creato un repository su Github includendo un esempio.

Qui si va

https://github.com/WilliamKinaan/ScrapyDynamicItems

+0

mi aiuti a risparmiare un sacco di tempo. Nota: se in items.py usi 'import scrapy' allora devi usare 'scrapy.Field()' nella funzione __setitem__ –

3

La soluzione personalizzata __setitem__ non ha funzionato per me quando si utilizza caricatori articolo disponibile Scrapy 1.0.3 perché l'articolo loader accesses the fields attribute directly:

value = self.item.fields[field_name].get(key, default) 

Il costume __setitem__ viene chiamato solo per gli accessi a livello di articolo come item['new field']. Poiché fields è just a dict, mi sono reso conto che avrei potuto semplicemente creare una sottoclasse Item che utilizza uno defaultdict per gestire con garbo queste situazioni.

Alla fine, solo due righe in più di codice:

from collections import defaultdict 


class FlexItem(scrapy.Item): 
    """An Item that creates fields dynamically""" 
    fields = defaultdict(scrapy.Field) 
+1

Grazie, ho trovato anche questo problema. Per essere chiari (so che hai detto * extra *) devi anche mantenere l'override di '__setitem__' oltre ad aggiungere questo defaultdict. – fpghost

2

Nel Scrapy 1.0+ il modo migliore potrebbe essere quella di produrre dicts Python al posto di istanze voce se non si dispone di uno schema ben definito . Controlla ad es. un esempio sulla prima pagina http://scrapy.org/ - non è definito alcun elemento.

Problemi correlati