【发布时间】:2017-12-29 20:22:27
【问题描述】:
我正在抓取一个电子商务网站,除最后一页外,每个页面上都有 48 种产品。
我正在为此使用 Scrapy。问题是,它没有从页面上抓取所有产品。例如,它从第 1 页抓取 12,从第 2 页抓取 18,从第 3 页抓取 10,从第 4 页抓取 19,依此类推。它应该从每个页面抓取所有 48 种产品,但它没有。
以下是我的脚本。在过去的 2 天里,我无法弄清楚我做错了什么。
更新 我在抓取之前对 url 列表进行了重复数据删除,并添加了日志消息以找出问题所在。当前代码:
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
爬取后的scrapy log:
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 product called”。最后一条日志消息是:
2017-12-30 13:18:55 [ecommerce] INFO: Parse product called 193 time
如您所见,它一共找到了 408 个产品,但调用 parse_product 函数时只调用了 193 个。因此只有 193 个项目被抓取。
【问题讨论】:
-
添加
print (len(products))看看你得到了什么?您的 Xpath 可能有问题 -
最好将 url 添加到问题中 - 然后我们可以检查页面。不同的页面可能需要不同的解决方案。所以有些人可能需要
Selenium,其他人可能只需要不同的xpath,因为页面为运行JavaScript的客户端发送不同的内容,而为其他客户端发送不同的内容。 IE。 Google 搜索以不同的标签发送项目。 python scrapy not crawling all urls in scraped list 中的同样问题。它在不运行 JS 的 scrapy 中使用不同的标签,在运行 JS 的 Selenium 或浏览器中使用不同的标签。 -
@TarunLalwani 我用日志消息更新了我的问题。
-
@furas 请查看我更新的问题,我添加了一些日志消息。可以看到,它找到了所有产品,但没有调用所有产品的解析函数。
-
如果你显示了 url,那么你就已经解决了。我怀疑某些网址与其他网址相似,并将它们过滤为重复。使用
print()在yields之前和parse_product内部显示网址,您将看到哪些网址被跳过。
标签: python web-scraping scrapy