【问题标题】:Scrapy not scraping all items on a pageScrapy 不抓取页面上的所有项目
【发布时间】: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


【解决方案1】:

代码中有两个问题

关闭刮刀

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)

【讨论】:

  • 实际上应该是if products: yeild scrapy.Request...,因为最后一页并不总是有确切的 48 个产品。
  • 不一定,如果当前页面有 47 个或更少的产品,我知道没有必要转到下一页,因为它将有 0 个产品。在边缘情况下,最后一页可能有确切的 48 个产品,这将转到具有 0 个产品的下一页,然后循环将结束。你的if products 总是会浏览一个额外的页面,这是可以而且应该避免的
猜你喜欢
  • 2018-09-22
  • 1970-01-01
  • 2012-01-12
  • 2016-03-16
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
相关资源
最近更新 更多