当Scrapy遍历hrefs列表时,为什么刮下的项目不按顺序显示?

时间:2015-11-19 19:17:24

标签: scrapy

当Scrapy遍历页面上找到的hrefs列表时,为什么它会开始在列表中间的某处显示已删除的项目而不是第一个href?

我从此页面上的链接列表中提取状态库信息:http://www.publiclibraries.com/

我使用的xpath是:

//div/div/div/table/tr/td/a/@href

代码似乎工作正常,但我想知道为什么,当显示刮下的项目时,Scrapy似乎从肯塔基州,路易斯安那州,密西西比州或密苏里州开始。它实际上首先显示的是哪一个不一致,但它最终会显示所有状态(只是不在页面上找到的顺序)。

为什么不是从Alamabama开始?这与线程有关吗?如果是这样,是否有办法强制Scrapy按照它们出现在初始页面上的顺序显示它们?

蜘蛛代码:

import scrapy
import logging

from scrapy import signals
from scrapy.exceptions import NotConfigured
from tutorial.items import LibAddressItem

class DmozSpider(scrapy.Spider):
    name = "us-pub-lib-physical_addresses"
    allowed_domains = ["publiclibraries.com"]
    start_urls = [
        "http://www.publiclibraries.com/"
    ]

    def parse(self, response):
        print "#################################################################"
        print response.url
        print "Top level states list"
        print "#################################################################"

        for href in response.xpath("//div/div/div/table/tr/td/a/@href"):
            url = response.urljoin(href.extract())
            yield scrapy.Request(url, callback=self.parse_state_libs)

    count = 0
    def parse_state_libs(self, response):
        print "#################################################################"
        print response.url
        print "#################################################################"

        for sel in response.xpath('//div/div/div/table/tr'):
            item = LibAddressItem()
            item['city'] = sel.xpath('td[1]/text()').extract()
            item['library'] = sel.xpath('td[2]/text()').extract()
            item['address'] = sel.xpath('td[3]/text()').extract()
            item['zip_code'] = sel.xpath('td[4]/text()').extract()
            item['phone'] = sel.xpath('td[5]/text()').extract()
            self.count = self.count + 1
            yield item

        print "#####################################"
        print "The number of libraries found so far:"
        print self.count
        print "#####################################"

LibAddressItem:

import scrapy

class LibAddressItem(scrapy.Item):
    city = scrapy.Field()
    state = scrapy.Field()
    library = scrapy.Field()
    address = scrapy.Field()
    zip_code = scrapy.Field()
    phone = scrapy.Field()

最初显示的项目示例:

2015-11-19 13:59:57 [scrapy] DEBUG: Crawled (200) <GET http://www.publiclibraries.com/> (referer: None)
#################################################################
http://www.publiclibraries.com/
Top level states list
#################################################################
2015-11-19 13:59:58 [scrapy] DEBUG: Crawled (200) <GET http://www.publiclibraries.com/kentucky.htm> (referer: http://www.publiclibraries.com/)
#################################################################
http://www.publiclibraries.com/kentucky.htm
#################################################################
2015-11-19 13:59:58 [scrapy] DEBUG: Scraped from <200 http://www.publiclibraries.com/kentucky.htm>
{'address': [], 'city': [], 'library': [], 'phone': [], 'zip_code': []}
2015-11-19 13:59:58 [scrapy] DEBUG: Scraped from <200 http://www.publiclibraries.com/kentucky.htm>
{'address': [u'302 King Drive'],
 'city': [u'Albany'],
 'library': [u'Clinton County Public Library'],
 'phone': [u'(606) 387-5989'],
 'zip_code': [u'42602']}
2015-11-19 13:59:58 [scrapy] DEBUG: Scraped from <200 http://www.publiclibraries.com/kentucky.htm>
{'address': [u'1740 Central Avenue'],
 'city': [u'Ashland'],
 'library': [u'Boyd County Public Library'],
 'phone': [u'(606) 329-0090'],
 'zip_code': [u'41101']}
2015-11-19 13:59:58 [scrapy] DEBUG: Scraped from <200 http://www.publiclibraries.com/kentucky.htm>
{'address': [u'1016 Summit Road'],
 'city': [u'Ashland'],
 'library': [u'Summit Branch'],
 'phone': [u'(606) 928-3366'],
 'zip_code': []}

1 个答案:

答案 0 :(得分:2)

Scrapy以异步方式运行请求,有些请求可以在其他请求之前返回,因此scrapy可以处理第一个成功返回的请求。

可以采取一些不同的措施来解决这个问题:

  1. 在另一个
  2. 之后真正执行一个请求

    您可以发出请求,然后在使用meta后继续处理以下请求:

        urls = [response.urljoin(href.extract()) for href in response.xpath("//div/div/div/table/tr/td/a/@href")]
        yield Request(url[0], callback=self.parse_urls, meta=dict(urls=urls, index=0))
    
    def parse_urls(self, response):
        # do your work with the current page
        yield Request(response.meta['urls'][response.meta['index']+1], 
            meta=dict(urls=response.meta['urls'], index=response.meta['index']+1))
    
    1. 设置请求的优先级
    2. 每个scrapy Request对象都有一个priority属性,可以随时更改,因此您可以在迭代时指定优先级:

          for i, href in enumerate(response.xpath("//div/div/div/table/tr/td/a/@href")):
              url = response.urljoin(href.extract())
              yield scrapy.Request(url, callback=self.parse_state_libs, priority=1000-i)
      

      这应该优先考虑第一个请求,但我认为这并不能完全保证你想要的东西。

      1. 后处理订单
      2. 也许更方便,您可以在请求中指定一些索引,以便稍后可以订购它(也可以使用meta或项目上的字段)。

        希望它有所帮助。