Scrapy刮刀缓慢的原因

时间:2016-07-23 10:24:57

标签: python web-scraping scrapy web-crawler scrapy-spider

我创建了一个非常慢的新Scrapy蜘蛛。它每秒只会刮两页,而我创建的其他Scrapy爬虫爬得更快。

我想知道是什么导致了这个问题,以及如何解决这个问题。代码与其他蜘蛛没有太大差别,我不确定它是否与问题有关,但如果你认为它可能涉及,我会加上它。

事实上,我的印象是请求不是异步的。我从来没有遇到过这种问题,而且我对Scrapy也很陌生。

修改

这是蜘蛛:

class DatamineSpider(scrapy.Spider):
    name = "Datamine"
    allowed_domains = ["domain.com"]
    start_urls = (
        'http://www.example.com/en/search/results/smth/smth/r101/m2108m',
    )

    def parse(self, response):
        for href in response.css('.searchListing_details .search_listing_title .searchListing_title a::attr("href")'):
            url = response.urljoin(href.extract())
            yield scrapy.Request(url, callback=self.parse_stuff)
        next_page = response.css('.pagination .next a::attr("href")')
        next_url = response.urljoin(next_page.extract()[0])
        yield scrapy.Request(next_url, callback=self.parse)

    def parse_stuff(self, response):
        item = Item()
        item['value'] = float(response.xpath('//*[text()="Price" and not(@class)]/../../div[2]/span/text()').extract()[0].split(' ')[1].replace(',',''))
        item['size'] =  float(response.xpath('//*[text()="Area" and not(@class)]/../../div[2]/text()').extract()[0].split(' ')[0].replace(',', '.'))
        try:
            item['yep'] = float(response.xpath('//*[text()="yep" and not(@class)]/../../div[2]/text()').extract()[0])
        except IndexError:
            print "NO YEP"
        else:
            yield item

1 个答案:

答案 0 :(得分:1)

只有两个可能的原因,因为你的蜘蛛表明你非常小心/有经验。

  1. 您的目标网站的响应时间非常短
  2. 每个页面只有1-2个列表页面(您使用parse_stuff()解析的页面)。
  3. 后者很有可能是原因。响应时间为半秒是合理的。这意味着通过遵循分页(下一个)链接,您将有效地每秒抓取2个索引页。由于您正在浏览 - 我猜 - 作为单个域,您的最大并发性将为〜min(CONCURRENT_REQUESTS, CONCURRENT_REQUESTS_PER_DOMAIN)。默认设置通常为8。但是你无法利用这种并发性,因为你没有足够快地创建列表网址。如果您的.searchListing_details .search_listing_title .searchListing_title a::attr("href")表达式只创建一个URL,那么创建列表URL的速率只有2 /秒,而要充分利用并发级别为8的下载程序,您应该创建至少7个URL /索引页面

    唯一的好解决方案是"碎片"索引并开始抓取,例如通过设置许多非重叠start_urls来并行显示多个类别。例如。您可能想要并行抓取电视,洗衣机,立体声或其他任何类别。如果你有4个这样的类别和Scrapy"点击"他们的下一个'每个按钮每秒2次,你将创建8个列表页面/秒,粗略地说,你会更好地利用你的下载器。

    P.S。 next_page.extract()[0] == next_page.extract_first()

    离线讨论后更新:是的...我在这个网站上看不到任何奇怪的东西,除了它很慢(由于节流或由于他们的服务器容量)。一些特定的技巧要走得更快。通过设置4 start_urls而不是1来快速命中4x指数。

    start_urls = (
        'http://www.domain.com/en/search/results/smth/sale/r176/m3685m',
        'http://www.domain.com/en/search/results/smth/smth/r176/m3685m/offset_200',
        'http://www.domain.com/en/search/results/smth/smth/r176/m3685m/offset_400',
        'http://www.domain.com/en/search/results/smth/smth/r176/m3685m/offset_600'
    )
    

    然后使用更高的并发性以允许并行加载更多URL。基本上"停用" CONCURRENT_REQUESTS_PER_DOMAIN将其设置为较大的值,例如1000,然后通过将CONCURRENT_REQUESTS设置为30来调整您的并发性。默认情况下,您的并发性受CONCURRENT_REQUESTS_PER_DOMAIN限制为8,例如,在您的情况下,列表页面的响应时间大于等于1.2秒,表示每秒最多6个列表页面的爬行速度。所以像这样打电话给你的蜘蛛:

    scrapy crawl MySpider -s CONCURRENT_REQUESTS_PER_DOMAIN=1000 -s CONCURRENT_REQUESTS=30
    

    它应该做得更好。

    还有一件事。我从您的目标网站上观察到,您可以从索引页面本身获得所需的所有信息,包括PriceAreayep,而无需"点击"任何上市页面。这样您的抓取速度可以立即提高10倍,因为您不需要使用for href...循环下载所有这些列表页面。只需解析索引页面中的列表。