我正在抓捕一个电子商务网站,除了最后一页之外,每个页面上都有48种产品。
我为此使用Scrapy。问题是,它没有从页面上抓取所有产品。例如,它从页面1刮掉12,从2刮掉18,从3刮掉10,从4刮掉19,依此类推。它应该从每个页面抓取所有48个产品,但不是。
下面是我的脚本。在过去的两天内,我无法弄清楚自己在做什么错。
更新
我在抓取之前对网址列表进行了重复数据删除,并添加了日志消息以找出问题所在。当前代码:
import scrapy
from productspider.items import Product
from urlparse import urlparse
class Ecommerce(scrapy.Spider):
name = "ecommerce"
def __init__(self, *args, **kwargs):
urls = kwargs.pop('urls', [])
if urls:
self.start_urls = urls.split(',')
self.logger.info(self.start_urls)
super(Ecommerce, self).__init__(*args, **kwargs)
page = 1
parse_product_called = 0
def parse(self, response):
url = response.url
if url.endswith('/'):
url = url.rstrip('/')
o = urlparse(url)
products = response.xpath(
"//a[contains(@href, '" + o.path + "/products/')]/@href").extract()
if not products:
raise scrapy.exceptions.CloseSpider("All products scraped")
products = dedupe(products)
self.logger.info("Products found on page %s = %s" % (self.page, len(products)))
for product in products:
yield scrapy.Request(response.urljoin(product), self.parse_product)
self.page += 1
next_page = o.path + "?page=" + str(self.page)
yield scrapy.Request(response.urljoin(next_page), self.parse)
def parse_product(self, response):
self.parse_product_called += 1
self.logger.info("Parse product called %s time" % self.parse_product_called)
product = Product()
product["name"] = response.xpath(
"//meta[@property='og:title']/@content")[0].extract()
product["price"] = response.xpath(
"//meta[@property='og:price:amount']/@content")[0].extract()
return product
def dedupe(seq, idfun=None):
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
抓取后抓取日志:
2017-12-30 13:18:55 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 86621,
'downloader/request_count': 203,
'downloader/request_method_count/GET': 203,
'downloader/response_bytes': 10925361,
'downloader/response_count': 203,
'downloader/response_status_count/200': 203,
'finish_reason': 'All products scraped',
'finish_time': datetime.datetime(2017, 12, 30, 7, 48, 55, 370000),
'item_scraped_count': 193,
'log_count/DEBUG': 397,
'log_count/INFO': 210,
'request_depth_max': 9,
'response_received_count': 203,
'scheduler/dequeued': 203,
'scheduler/dequeued/memory': 203,
'scheduler/enqueued': 418,
'scheduler/enqueued/memory': 418,
'start_time': datetime.datetime(2017, 12, 30, 7, 48, 22, 405000)}
2017-12-30 13:18:55 [scrapy.core.engine] INFO: Spider closed (All products scraped)
和日志消息:
2017-12-30 13:18:25 [电子商务]信息:第1页上找到的产品= 48
2017-12-30 13:18:32 [电子商务]信息:第2页上找到的产品= 48
2017-12-30 13:18:35 [电子商务]信息:第3页上找到的产品= 48
2017-12-30 13:18:38 [电子商务]信息:第4页上找到的产品= 48
2017-12-30 13:18:41 [电子商务]信息:第5页上找到的产品= 48
2017-12-30 13:18:43 [电子商务]信息:第6页上找到的产品= 48
2017-12-30 13:18:45 [电子商务]信息:第7页上找到的产品= 48
2017-12-30 13:18:48 [电子商务]信息:第8页上找到的产品= 48
2017-12-30 13:18:51 [电子商务]信息:第9页上找到的产品= 24
每次调用parse_product时,都会打印“已调用Parse产品”日志。最后一条日志消息是:
2017-12-30 13:18:55 [电子商务]信息:解析产品称为193时间
如您所见,它总共发现了408个产品,但
parse_product
函数只有193个。因此,只有193个项目被废弃。 最佳答案
您代码中的两个问题
关闭刮板
if not products:
raise scrapy.exceptions.CloseSpider("All products scraped")
使用上面的命令,您要求蜘蛛尽快终止。这不是一件好事。仅在您不希望继续抓取时使用
不结束刮板
self.page += 1
next_page = o.path + "?page=" + str(self.page)
yield scrapy.Request(response.urljoin(next_page), self.parse)
您有一个需要结束的不受控制的分页逻辑。因此,您可以使用以下事实:没有48个产品的任何页面都是最后一页
self.page += 1
next_page = o.path + "?page=" + str(self.page)
if len(products) == 48:
yield scrapy.Request(response.urljoin(next_page), self.parse)
关于python - 不抓取不抓取页面上的所有项目,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48028041/