2012-05-15 2 views
6

Sto utilizzando Scrapy, in particolare la classe CrawlSpider di Scrapy per analizzare i collegamenti Web che contengono determinate parole chiave. Ho una lista abbastanza lunga di start_urls che ottiene le sue entrate da un database SQLite connesso a un progetto Django. Voglio salvare i collegamenti web raschiati in questo database.Come accedere a un start_url specifico in Scrapy CrawlSpider?

Ho due modelli Django, uno per gli URL di inizio, come http://example.com e una per i collegamenti web raschiate come http://example.com/website1, http://example.com/website2 ecc Tutti i link web raschiate sono siti secondari di una delle URL di inizio nella lista start_urls.

Il modello di collegamenti Web ha una relazione molti-a-uno con il modello di URL di avvio, ovvero il modello di collegamenti Web ha una Chiave straniera per il modello di URL iniziale. Per salvare correttamente i miei collegamenti web raschiati al database, devo dire al metodo che inizia l'url a cui appartiene il collegamento web raschiato. Come lo posso fare? La classe DjangoItem di Scrapy non aiuta in questo senso poiché devo ancora definire esplicitamente l'url di avvio utilizzato.

In altre parole, come posso passare l'url di avvio correntemente utilizzato al metodo parse_item(), in modo che sia possibile salvarlo insieme ai collegamenti web raschiati appropriati al database? Qualche idea? Grazie in anticipo!

+0

Puoi avere il campo start_url nella stessa tabella della tabella weblinks (come nel DjangoItem che stai utilizzando)?Certo, creerà una denormalizzazione ridondante, ma se vuoi evitare di chiamare esplicitamente, questo potrebbe aiutare. – zubinmehta

risposta

8

Per impostazione predefinita non è possibile accedere all'originale URL iniziale.

Tuttavia, è possibile ignorare il metodo make_requests_from_url e inserire l'URL di avvio in meta. Quindi in un parsing puoi estrarlo da lì (se cedi in quel metodo di analisi successive richieste, non dimenticarti di inoltrare l'URL di avvio in esse).


Non ho lavorato con CrawlSpider e forse quello che Maxim suggerisce che lavorerà per voi, ma di tenere presente che response.url ha l'url dopo eventuali reindirizzamenti.

Ecco un esempio di come lo farei, ma è solo un esempio (tratto dal tutorial Scrapy) e non è stato testato:

class MySpider(CrawlSpider): 
    name = 'example.com' 
    allowed_domains = ['example.com'] 
    start_urls = ['http://www.example.com'] 

    rules = (
     # Extract links matching 'category.php' (but not matching 'subsection.php') 
     # and follow links from them (since no callback means follow=True by default). 
     Rule(SgmlLinkExtractor(allow=('category\.php',), deny=('subsection\.php',))), 

     # Extract links matching 'item.php' and parse them with the spider's method parse_item 
     Rule(SgmlLinkExtractor(allow=('item\.php',)), callback='parse_item'), 
    ) 

    def parse(self, response): # When writing crawl spider rules, avoid using parse as callback, since the CrawlSpider uses the parse method itself to implement its logic. So if you override the parse method, the crawl spider will no longer work. 
     for request_or_item in CrawlSpider.parse(self, response): 
      if isinstance(request_or_item, Request): 
       request_or_item = request_or_item.replace(meta = {'start_url': response.meta['start_url']}) 
      yield request_or_item 

    def make_requests_from_url(self, url): 
     """A method that receives a URL and returns a Request object (or a list of Request objects) to scrape. 
     This method is used to construct the initial requests in the start_requests() method, 
     and is typically used to convert urls to requests. 
     """ 
     return Request(url, dont_filter=True, meta = {'start_url': url}) 

    def parse_item(self, response): 
     self.log('Hi, this is an item page! %s' % response.url) 

     hxs = HtmlXPathSelector(response) 
     item = Item() 
     item['id'] = hxs.select('//td[@id="item_id"]/text()').re(r'ID: (\d+)') 
     item['name'] = hxs.select('//td[@id="item_name"]/text()').extract() 
     item['description'] = hxs.select('//td[@id="item_description"]/text()').extract() 
     item['start_url'] = response.meta['start_url'] 
     return item 

Chiedete se avete domande. A proposito, usando la funzionalità 'Vai alla definizione' di PyDev puoi vedere le fonti di scrapy e capire quali parametri Request, make_requests_from_url e altre classi e metodi aspettarti. Entrare nel codice ti aiuta e ti fa risparmiare tempo, anche se all'inizio potrebbe sembrare difficile.

+0

Penso di capire approssimativamente cosa intendi ma non so davvero come implementarlo. Potete forse fornire un breve esempio che mostri come viene solitamente usato il metodo 'make_requests_from_url' e in che modo si riferisce al metodo' parse'? Sono ancora un principiante. Grazie! – pemistahl

+1

Grazie warwaruk, funziona bene. Tuttavia, ho scoperto che solo il metodo 'make_requests_from_url' e la configurazione del tag' meta' della richiesta è necessario per farlo funzionare. Non voglio salvare l'URL di avvio alla fine, quindi non ha senso per me metterlo in un oggetto. Comunque, molte grazie ancora! :) – pemistahl

1

Se ho letto correttamente il problema, è possibile ottenere l'url da response.url e quindi scrivere a item['url'].

In Spider: item['url'] = response.url

E in cantiere: url = item['url'].

Oppure inserire response.url in meta come warvariuc ha scritto.

1

Sembra che la risposta di warvariuc richieda una leggera modifica a partire da Scrapy 1.3.3: è necessario eseguire l'override di _parse_response anziché parse. La sostituzione di make_requests_from_url non è più necessaria.