Scrapy刮板速度慢的原因

Aim*_*Hat 1 python web-crawler scrapy web-scraping 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
Run Code Online (Sandbox Code Playgroud)

nev*_*stn 6

考虑到您的蜘蛛表明您非常小心/经验丰富,只有两个潜在原因。

  1. 您的目标站点的响应时间非常短
  2. 每个页面只有 1-2 个列表页面(您使用 解析的页面parse_stuff())。

极有可能是后者。有半秒的响应时间是合理的。这意味着通过跟随分页(下一个)链接,您将有效地每秒抓取 2 个索引页面。由于您正在浏览 - 我猜 - 作为单个域,您的最大并发将是 ~ min(CONCURRENT_REQUESTS, CONCURRENT_REQUESTS_PER_DOMAIN)。对于默认设置,这通常为 8。但是您将无法利用这种并发性,因为您创建列表 URL 的速度不够快。如果您的.searchListing_details .search_listing_title .searchListing_title a::attr("href")表达式仅创建一个 URL,则您创建列表 URL 的速率仅为 2/秒,而要充分利用并发级别为 8 的下载器,您应该创建至少 7 个 URL/索引页面。

唯一好的解决方案是“分片”索引并通过设置许多非重叠的start_urls. 例如,您可能想要并行抓取电视、洗衣机、立体声音响或任何其他类别。如果您有 4 个这样的类别,并且 Scrapy 每秒为每个类别“单击”它们的“下一步”按钮 2 次,您将创建 8 个列表页面/秒,粗略地说,您将更好地利用您的下载器。

附注next_page.extract()[0]==next_page.extract_first()

离线讨论后更新:是的......除了它很慢(由于节流或由于服务器容量)之外,我在这个网站上没有看到任何特别奇怪的东西。一些加快速度的特定技巧。通过设置 4start_urls而不是 1,以 4 倍的速度命中索引。

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'
)
Run Code Online (Sandbox Code Playgroud)

然后使用更高的并发性来允许并行加载更多的 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
Run Code Online (Sandbox Code Playgroud)

它应该做得更好。

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