Scrapy不会刮擦页面上的所有项目

时间:2017-12-29 20:22:27

标签: python web-scraping scrapy

我正在抓取一个电子商务网站,除了最后一页之外,每个网页上有48个产品。

我正在使用Scrapy。问题是,它不是从页面中抓取所有产品。例如,它从第1页,第18页,第2页,第10页,第3页,第19页从第4页第10页,依此类推。它应该从每页抓取所有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

抓取后的Scrapy日志:

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

log"解析产品名为"每次调用parse_product时都会打印出来。最后一条日志消息是:

  

2017-12-30 13:18:55 [电子商务]信息:解析产品叫做193次

正如你所看到的,它总共发现了408种产品,但只称19 parse_product功能。因此只有193种产品被刮掉。

1 个答案:

答案 0 :(得分: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)