【问题标题】:Scrapy crawl nested urlsScrapy抓取嵌套网址
【发布时间】:2020-07-30 11:00:28
【问题描述】:

简介

由于我必须更深入地抓取,我面临下一个问题:抓取嵌套页面,例如:https://www.karton.eu/Faltkartons

我的爬虫必须从这个页面开始,转到https://www.karton.eu/Einwellige-Kartonagen 并访问该类别中列出的每个产品。

它应该对每个类别中包含的每个产品的“Faltkartons”的每个子类别都这样做。

已编辑

我的代码现在如下所示:

import scrapy
from ..items import KartonageItem

class KartonSpider(scrapy.Spider):
    name = "kartons12"
    allow_domains = ['karton.eu']
    start_urls = [
        'https://www.karton.eu/Faltkartons'
        ]
    custom_settings = {'FEED_EXPORT_FIELDS': ['SKU', 'Title', 'Link', 'Price', 'Delivery_Status', 'Weight', 'QTY', 'Volume'] } 
    
    def parse(self, response):
        url = response.xpath('//div[@class="cat-thumbnails"]')

        for a in url:
            link = a.xpath('a/@href')
            yield response.follow(url=link.get(), callback=self.parse_category_cartons)

    def parse_category_cartons(self, response):
        url2 = response.xpath('//div[@class="cat-thumbnails"]')

        for a in url2:
            link = a.xpath('a/@href')
            yield response.follow(url=link.get(), callback=self.parse_target_page)

    def parse_target_page(self, response):
        card = response.xpath('//div[@class="text-center articelbox"]')

        for a in card:
            items = KartonageItem()
            link = a.xpath('a/@href')
            items ['SKU'] = a.xpath('.//div[@class="delivery-status"]/small/text()').get()
            items ['Title'] = a.xpath('.//h5[@class="title"]/a/text()').get()
            items ['Link'] = a.xpath('.//h5[@class="text-center artikelbox"]/a/@href').extract()
            items ['Price'] = a.xpath('.//strong[@class="price-ger price text-nowrap"]/span/text()').get()
            items ['Delivery_Status'] = a.xpath('.//div[@class="signal_image status-2"]/small/text()').get()
            yield response.follow(url=link.get(),callback=self.parse_item, meta={'items':items})

    def parse_item(self,response):
        table = response.xpath('//div[@class="product-info-inner"]')

        items = KartonageItem()
        items = response.meta['items']
        items['Weight'] = a.xpath('.//span[@class="staffelpreise-small"]/text()').get()
        items['Volume'] = a.xpath('.//td[@class="icon_contenct"][7]/text()').get()
        yield items

在我的脑海中,它从 start_url 开始,然后我访问 https://www.karton.eu/Einwellige-Kartonagen,寻找链接并关注它们 https://www.karton.eu/einwellig-ab-100-mm。在该页面上,它会检查卡片以获取一些信息,然后点击指向特定产品页面的链接以获取最后的项目。

我的方法的哪些部分是错误的? 我应该将我的课程从“scrapy.Spider”改为“crawl.spider”吗?还是只有在我想设置一些规则时才需要?

仍有可能,我的标题、sku 等的 xpath 可能是错误的,但首先,我只想建立我的基础知识,以抓取这些嵌套页面

我的控制台输出:

最后我设法浏览了所有这些页面,但不知何故我的 .csv 文件仍然是空的

【问题讨论】:

  • 我执行了你的蜘蛛,在这里它对我的表现如何:爬取了 start_urls 页面,在 var card 中选择了 6 个对象,每个对象都有一个链接。产生并爬取了 6 个请求,parse_item 中的每个选择器都返回空,没有任何项目产生。
  • 你能给我一个提示吗,我首先要纠正什么?递归爬虫是否总是必须使用规则,还是没有规则仍然可能?
  • 我不清楚蜘蛛应该做什么。例如,您的蜘蛛到达此页面karton.eu/Zweiwellige-Kartons,但无法抓取任何内容,因为 XPath(在parse_item 方法中)与页面上的任何路径都不匹配(至少对我来说不匹配)。他们应该从那里抓取内容还是继续浏览更多页面,例如karton.eu/zweiwellig-ab-500-mm
  • 我的计划是这样设置的:它从karton.eu/Faltkartons>开始它的第一个目的地是karton.eu/Einwellige-Kartonagen>访问该页面后它应该从karton.eu/einwellig-ab-100-mm>的所有文章开始并保存标题、链接、价格等值。之后,它应该转到 karton.eu/einwellig-ab-200-mm> 并重复它的工作。我的完整目标是它对每个类别的所有产品都执行此操作。现在我开始重新检查我的 xpaths

标签: python python-3.x xpath web-scraping scrapy


【解决方案1】:

根据您提供的 cmets,问题从您跳过链中的请求开始。

您的start_urls 将请求此页面:https://www.karton.eu/Faltkartons 该页面将由parse 方法解析并产生来自https://www.karton.eu/Karton-weiss 的新请求到 https://www.karton.eu/Einwellige-Kartonagen

这些页面将在parse_item 方法中进行解析,但它们不是您想要的最终页面。您需要在卡片之间进行解析并产生新的请求,如下所示:

for url in response.xpath('//div[@class="cat-thumbnails"]/div/a/@href')
    yield scrapy.Request(response.urljoin(url.get()), callback=self.new_parsing_method)

这里的例子,在解析https://www.karton.eu/Zweiwellige-Kartons的时候会发现9个新的链接来自

最后,您需要一种解析方法来抓取这些页面中的项目。由于项目不止一项,我建议您在 for 循环中运行它们。 (您需要正确的 xpath 来抓取数据。)

编辑:

现在重新编辑,我观察了页面结构,发现我的代码是基于错误的假设。问题是有些页面没有子类别页面,有些则有。

页面结构:

ROOT: www.karton.eu/Faltkartons
 |_ Einwellige Kartons
    |_ Subcategory: Kartons ab 100 mm Länge
      |_ Item List (www.karton.eu/einwellig-ab-100-mm)
        |_ Item Detail (www.karton.eu/113x113x100-mm-einwellige-Kartons)
    ...
    |_ Subcategory: Kartons ab 1000 mm Länge
      |_ ...
 |_ Zweiwellige Kartons #Same as above
 |_ Lange Kartons #Same as above
 |_ quadratische Kartons #There is no subcategory
    |_ Item List (www.karton.eu/quadratische-Kartons)
      |_ Item Detail (www.karton.eu/113x113x100-mm-einwellige-Kartons)
 |_ Kartons Höhenvariabel #There is no subcategory
 |_ Kartons weiß #There is no subcategory

下面的代码将从带有子类别的页面中抓取项目,因为我认为这就是您想要的。无论哪种方式,我都留下了 print 声明,以向您展示由于没有子类别页面而将被跳过的页面。以防您以后想包含它们。

import scrapy
from ..items import KartonageItem

class KartonSpider(scrapy.Spider):
    name = "kartons12"
    allow_domains = ['karton.eu']
    start_urls = [
        'https://www.karton.eu/Faltkartons'
        ]
    custom_settings = {'FEED_EXPORT_FIELDS': ['SKU', 'Title', 'Link', 'Price', 'Delivery_Status', 'Weight', 'QTY', 'Volume'] } 
    
    def parse(self, response):
        url = response.xpath('//div[@class="cat-thumbnails"]')

        for a in url:
            link = a.xpath('a/@href')
            yield response.follow(url=link.get(), callback=self.parse_category_cartons)

    def parse_category_cartons(self, response):
        url2 = response.xpath('//div[@class="cat-thumbnails"]')

        if not url2:
            print('Empty url2:', response.url)

        for a in url2:
            link = a.xpath('a/@href')
            yield response.follow(url=link.get(), callback=self.parse_target_page)

    def parse_target_page(self, response):
        card = response.xpath('//div[@class="text-center artikelbox"]')

        for a in card:
            items = KartonageItem()
            link = a.xpath('a/@href')
            items ['SKU'] = a.xpath('.//div[@class="delivery-status"]/small/text()').get()
            items ['Title'] = a.xpath('.//h5[@class="title"]/a/text()').get()
            items ['Link'] = a.xpath('.//h5[@class="text-center artikelbox"]/a/@href').extract()
            items ['Price'] = a.xpath('.//strong[@class="price-ger price text-nowrap"]/span/text()').get()
            items ['Delivery_Status'] = a.xpath('.//div[@class="signal_image status-2"]/small/text()').get()
            yield response.follow(url=link.get(),callback=self.parse_item, meta={'items':items})

    def parse_item(self,response):
        table = response.xpath('//div[@class="product-info-inner"]')

        #items = KartonageItem() # You don't need this here, as the line bellow you are overwriting the variable.
        items = response.meta['items']
        items['Weight'] = response.xpath('.//span[@class="staffelpreise-small"]/text()').get()
        items['Volume'] = response.xpath('.//td[@class="icon_contenct"][7]/text()').get()
        yield items

注意事项

改变了这个:

    card = response.xpath('//div[@class="text-center articelbox"]')

对此:(K而不是C)

    card = response.xpath('//div[@class="text-center artikelbox"]')

评论了这一点,因为 meta 中的项目已经是 KartonageItem。 (可以去掉)

def parse_item(self,response):
    table = response.xpath('//div[@class="product-info-inner"]')
    #items = KartonageItem()
    items = response.meta['items']

parse_items 方法中更改了这个

    items['Weight'] = a.xpath('.//span[@class="staffelpreise-small"]/text()').get()
    items['Volume'] = a.xpath('.//td[@class="icon_contenct"][7]/text()').get()

到这里:

    items['Weight'] = response.xpath('.//span[@class="staffelpreise-small"]/text()').get()
    items['Volume'] = response.xpath('.//td[@class="icon_contenct"][7]/text()').get()

因为a 在该方法中不存在。

【讨论】:

  • 我需要在 card 变量之前的 for 循环吗?或者我必须把它放在哪里?我想我被卡住了..我在...cat-thumbnails"]/div/a/@href') 中也收到一个错误,“)”总是被标记
  • 我看到您设法请求所有页面。如果你的蜘蛛没有产生任何物品,可能意味着它们没有被填充。尝试在parse_item 方法中记录/打印选择器的返回。我相信他们会空手而归。
  • @y.y 我刚刚执行了你的蜘蛛,现在看来你的一个功能太多了。让我说明一下:这个页面karton.eu/900x160x65-mm-einwellige-Faltschachtel是最后被刮掉的页面吧?或者它应该从某个地方提出新的请求?我刚才提到的这个页面属于parse_target_page,而不是parse_itemcard var 的返回不可避免地是空的,它停在那里并且它不会产生任何项目。检查我的原始答案,将添加您的代码版本。
  • 你之前提到的url,不应该被刮掉。 karton.eu/Faltkartons> 这是 start_url,下一页有 10 个“类别”karton.eu/Einwellige-Kartonagen>now 它应该打开这个“子类别”karton.eu/einwellig-ab-100-mm> 这就是我想要我的信息的地方,但有些信息只存储在产品的实际页面 karton.eu/113x113x100-mm-einwellige-Kartons>
  • 当然。变量有一个定义的scope,这意味着a var 存在于parse_target_page 内部,但不在parse_item 方法内部。此外,实际到达parse_item 的页面是单个项目页面,因此您不需要循环来解析该页面中的多个项目,因为只有一个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多