2016-02-26 21 views
5

sto imparando Scrapy con il tutorial: http://doc.scrapy.org/en/1.0/intro/tutorial.htmlPerché XPath all'interno di un ciclo di selezione ancora restituito un elenco nel tutorial

Quando eseguo il seguente script di esempio nel tutorial. Ho scoperto che anche se era già in loop nella lista dei selettori, la piastrella che ho ricevuto da sel.xpath('a/text()').extract() era ancora una lista, che conteneva una stringa. Come [u'Python 3 Object Oriented Programming'] anziché u'Python 3 Object Oriented Programming'. In un esempio successivo, la lista viene assegnata all'elemento come item['title'] = sel.xpath('a/text()').extract(), che a mio avviso non è logicamente corretto.

import scrapy 

class DmozSpider(scrapy.Spider): 
    name = "dmoz" 
    allowed_domains = ["dmoz.org"] 
    start_urls = [ 
     "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", 
     "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" 
    ] 

    def parse(self, response): 
     for sel in response.xpath('//ul/li'): 
      title = sel.xpath('a/text()').extract() 
      link = sel.xpath('a/@href').extract() 
      desc = sel.xpath('text()').extract() 
      print title, link, desc 

Tuttavia se uso il seguente codice:

import scrapy 

class DmozSpider(scrapy.Spider): 
    name = "dmoz" 
    allowed_domains = ["dmoz.org"] 
    start_urls = [ 
     "http://www.dmoz.org/Computers/Programming/Languages/Python/", 
    ] 

    def parse(self, response): 
     for href in response.css("ul.directory.dir-col > li > a::attr('href')"): 
      link = href.extract() 
      print(link) 

il link è una stringa piuttosto che un elenco.

È un bug o è destinato?

risposta

8

.xpath().extract() e .css().extract() restituire un elenco perché .xpath() e .css() ritorno SelectorList oggetti.

Vedi https://parsel.readthedocs.org/en/v1.0.1/usage.html#parsel.selector.SelectorList.extract

(SelectorList) .extract():

Chiamare la .extract() metodo per ogni elemento è questa lista e restituire i loro risultati appiattite, come un elenco di stringhe Unicode.

.extract_first() è quello che state cercando (che è scarsamente documentata)

Tratto da http://doc.scrapy.org/en/latest/topics/selectors.html:

Se si desidera estrarre solo primo elemento abbinato, è possibile chiamare il selettore .extract_first()

>>> response.xpath('//div[@id="images"]/a/text()').extract_first() 
u'Name: My image 1 ' 

Nel vostro altro esempio:

def parse(self, response): 
    for href in response.css("ul.directory.dir-col > li > a::attr('href')"): 
     link = href.extract() 
     print(link) 

ogni href nel circuito sarà un oggetto Selector.Chiamando .extract() su di esso ti porterà una singola stringa Unicode indietro:

$ scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/" 
2016-02-26 12:11:36 [scrapy] INFO: Scrapy 1.0.5 started (bot: scrapybot) 
(...) 
In [1]: response.css("ul.directory.dir-col > li > a::attr('href')") 
Out[1]: 
[<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'>, 
<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'>, 
... 
<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'>] 

così .css() sul response restituisce un SelectorList:

In [2]: type(response.css("ul.directory.dir-col > li > a::attr('href')")) 
Out[2]: scrapy.selector.unified.SelectorList 

Looping su quell'oggetto ti dà Selector casi:

In [5]: for href in response.css("ul.directory.dir-col > li > a::attr('href')"): 
    ...:  print href 
    ...:  
<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'> 
<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'> 
(...) 
<Selector xpath=u"descendant-or-self::ul[@class and contains(concat(' ', normalize-space(@class), ' '), ' directory ') and (@class and contains(concat(' ', normalize-space(@class), ' '), ' dir-col '))]/li/a/@href" data=u'/Computers/Programming/Languages/Python/'> 

E chiamare .extract() fornisce un singolo str Unicode ing:

In [6]: for href in response.css("ul.directory.dir-col > li > a::attr('href')"): 
    print type(href.extract()) 
    ...:  
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 
<type 'unicode'> 

Nota: .extract() su Selector è wrongly documented in modo da restituire una lista di stringhe. Aprirò un problema su parsel (che è lo stesso dei selettori di Scrapy e usato sotto il cofano in 1.1.)

+0

Grazie per la risposta rapida! Ho appena modificato il post e ho aggiunto un esempio del tutorial in cui 'extract()' fornisce una stringa. È perché sto usando i CSS? – entron

+0

Giusto, ciò che ho scritto non è corretto (troppo veloce di una risposta). In effetti '.xpath(). Extract()' e '.css(). Extract() restituisce liste perché' .xpath() 'e' .css() 'restituiscono oggetti' SelectorList'. Ma il ciclo su '.xpath()' ti dà un 'Selector', dal quale puoi chiamare' .extract() 'e ottenere un singolo elemento. Modificherò la mia risposta –

+0

Questa parte è davvero confusa, ma ora capisco! Grazie mille! – entron