Scrapy 刮板慢的原因
Cause of slow Scrapy scraper
我创建了一个非常慢的新 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
只有两个可能的原因,因为您的蜘蛛表明您很 careful/experienced。
- 您的目标站点的响应时间很短
- 每个页面只有 1-2 个列表页面(您使用
parse_stuff()
解析的页面)。
很可能是后者。半秒的响应时间是合理的。这意味着按照分页 (next) link,您将有效地每秒抓取 2 个索引页面。由于您正在浏览 - 我猜 - 作为单个域,您的最大并发将是 ~ min(CONCURRENT_REQUESTS, CONCURRENT_REQUESTS_PER_DOMAIN)
。默认设置通常为 8。但是您将无法利用这种并发性,因为您没有足够快地创建列表 URLs。如果您的 .searchListing_details .search_listing_title .searchListing_title a::attr("href")
表达式仅创建一个 URL,您创建列表 URLs 的速率仅为 2/秒,而要充分利用并发级别为 8 的下载器,您应该至少要创建 7 个 URLs/index 页。
唯一好的解决方案是 "shard" 索引并开始抓取,例如通过设置多个非重叠 start_urls
来并行多个类别。例如。你可能想同时抓取电视、洗衣机、音响或任何其他类别。如果你有 4 个这样的类别和 Scrapy "clicks" 他们的 'next' 按钮每秒钟 2 次,你将创建 8 个列表 pages/second 并且粗略地说,你会更好地利用你的下载器。
P.S。 next_page.extract()[0]
== next_page.extract_first()
离线讨论后更新:是的...除了速度慢(由于节流或服务器容量)之外,我在该网站上没有看到任何特别奇怪的地方。一些特定的技巧可以加快速度。通过设置 4 start_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'
)
然后使用更高的并发度以允许并行加载更多 URL。基本上 "deactivate" 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
它应该做得更好。
还有一件事。我从您的目标站点观察到,您可以从索引页面本身获得所需的所有信息,包括 Price
、Area
和 yep
,而无需 "hit" 任何列表页面.这会立即使您的爬网速度提高 10 倍,因为您不需要使用 for href...
循环下载所有这些列表页面。只需从索引页解析列表。
我创建了一个非常慢的新 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
只有两个可能的原因,因为您的蜘蛛表明您很 careful/experienced。
- 您的目标站点的响应时间很短
- 每个页面只有 1-2 个列表页面(您使用
parse_stuff()
解析的页面)。
很可能是后者。半秒的响应时间是合理的。这意味着按照分页 (next) link,您将有效地每秒抓取 2 个索引页面。由于您正在浏览 - 我猜 - 作为单个域,您的最大并发将是 ~ min(CONCURRENT_REQUESTS, CONCURRENT_REQUESTS_PER_DOMAIN)
。默认设置通常为 8。但是您将无法利用这种并发性,因为您没有足够快地创建列表 URLs。如果您的 .searchListing_details .search_listing_title .searchListing_title a::attr("href")
表达式仅创建一个 URL,您创建列表 URLs 的速率仅为 2/秒,而要充分利用并发级别为 8 的下载器,您应该至少要创建 7 个 URLs/index 页。
唯一好的解决方案是 "shard" 索引并开始抓取,例如通过设置多个非重叠 start_urls
来并行多个类别。例如。你可能想同时抓取电视、洗衣机、音响或任何其他类别。如果你有 4 个这样的类别和 Scrapy "clicks" 他们的 'next' 按钮每秒钟 2 次,你将创建 8 个列表 pages/second 并且粗略地说,你会更好地利用你的下载器。
P.S。 next_page.extract()[0]
== next_page.extract_first()
离线讨论后更新:是的...除了速度慢(由于节流或服务器容量)之外,我在该网站上没有看到任何特别奇怪的地方。一些特定的技巧可以加快速度。通过设置 4 start_urls
而不是 1.
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。基本上 "deactivate" 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
它应该做得更好。
还有一件事。我从您的目标站点观察到,您可以从索引页面本身获得所需的所有信息,包括 Price
、Area
和 yep
,而无需 "hit" 任何列表页面.这会立即使您的爬网速度提高 10 倍,因为您不需要使用 for href...
循环下载所有这些列表页面。只需从索引页解析列表。