【问题标题】:Scraping every tabledata with scrapy用 scrapy 抓取每个 tabledata
【发布时间】:2020-08-11 18:50:44
【问题描述】:

简介

在使用scrapy 几个星期之后,我仍然有一些问题,要弄清楚,一些xpath 表达式。 大多数情况下,我在提取表格数据和“ul 和 li”标签时遇到了大问题。

示例 我尝试获取以下数据的网页: https://www.karton.eu/460x310x160-mm-Postal-Shipping-Box

有一个名为:“Productdata”的表,我需要每一行,但我没有得到它。 我试过类似的东西: response.xpath('//*[@id="2"]/tr/td/text()').getall(), response.xpath('//table[@class="table table-striped"]/tr/td/text()').getall()

我的代码

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import KartoneuItem
import csv

class KartoneuSpider(scrapy.Spider):
    name = "karton13"
    allowed_domains = ['karton.eu']
    with open("kartonsalllinks.csv","r") as f:
        reader = csv.DictReader(f)
        start_urls = [items['Link'] for items in reader]
    
    rules = (
        Rule(LinkExtractor(), callback='parse'),
    )

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

        if not card:
            print('No productlink', response.url)

        for a in card:

            items = KartoneuItem()
            items['SKU'] = a.xpath('.//span[@class="art_nr"]/strong/text()').get()
            items['Title'] = a.xpath('.//h1[@class="fn product-title"]/text()').get()
            items['Link'] = a.url
            items['Price'] = a.xpath('.//div[@class="price_wrapper"]/strong/text()').get()
            items['Delivery_Status'] = a.xpath('.//div[@class="col-lg-4"]/span/text()').get()
            items['Desc'] = a.xpath('.//*[@id="1"]/p/text()').getall()
            items['Breadcrumb'] = a.xpath('.//*[@id="breadcrumb"]/li/a/@href').getall()
            yield items

我已经有一个包含域的每个链接的 .csv 文件,现在上面的代码应该打开每个链接,检查它是否是产品链接(response.xpath('//div[@class="product-info-inner"]')没有该标签的页面,应该跳过,因为它们例如可以是类别链接。

【问题讨论】:

    标签: python html web xpath scrapy


    【解决方案1】:

    你可以直接输出键:

     response.xpath('//table[@class="table table-striped"]//tr/td[1]/text()[normalize-space()]').getall()
    

    输出:

    ['internal dimensions:',
     'external dimensions:',
     'girth:',
     'quality:',
     'weight:',
     'volume:',
     'pallet dimensions:',
     'piece(s) per pallet:',
     'carbon neutral']
    

    对于值(请务必使用/td[2]//text() 而不是/td[2]/text()):

    response.xpath('//table[@class="table table-striped"]//tr/td[2]//text()').getall()
    

    输出:

    ['460 x 310 x 160 mm',
     '515 x 335 x 170 mm',
     '122,5 cm',
     'B-Welle 1.2',
     '0,48 kg',
     '22.82 l',
     '1230 x 800 x 1880 mm',
     '410',
     'ClimatePartner ID printed']
    

    【讨论】:

    • 你能解释一下/td[2]//text() not /td[2]/text()之间的区别吗?或者我在哪里可以读到它?
    • 当然。 /td[2]//text() 表示从 td[2] 元素的后代中查找所有文本下一个节点。 /td[2]//text() 表示查找 td[2] 元素的所有文本下一个节点子节点。您必须使用第一个表达式,因为最后一个文本节点 (ClimatePartner ID printed) 不是 /td[2] 元素的子元素,而是后代。它的父元素是一个锚元素 (a rel="nofollow" title="Link zu ClimatePartner.com"...)。如果您使用/td[2]/text(),您将获得 8 个文本节点,而您需要 9 个(9 个键 > 9 个值)。这就是为什么你必须使用 /td[2]//text() : 来获取 9 个文本节点(9 个值)。
    • W3S 是从基础开始的好地方:w3schools.com/xml/xpath_syntax.asp
    【解决方案2】:

    您在 XPATH 选择器中遗漏了一个 tbody,我不确定您的项目字段是什么等...这里我刚刚抓取了一个列表中的所有产品数据,您可以对其进行操作,也可以使用 XPATH 选择器将数据单独放入单独的项目字段中。

    代码示例

    table_rows = response.xpath('//table[@class="table table-striped"]/tbody/tr/td/text()').getall() 
    cleaned_table_rows = [a for a in table_rows if a != '\n']
    

    输出

    ['internal dimensions:', '460 x 310 x 160 mm', 'external dimensions:', '515 x 335 x 170 mm', 'girth:', '122,5 cm', 'quality:', 'B-Welle 1.2', 'weight:', '0,48 kg', 'volume:', '22.82 l', 'pallet dimensions:', '1230 x 800 x 1880 mm', 'piece(s) per pallet:', '410', 'carbon neutral']
    

    解释

    你是 XPATH 选择器

    response.xpath('//table[@class="table table-striped"]/tr/td/text()').getall()
    

    应该是什么时候

    response.xpath('//table[@class="table table-striped"]/tbody/tr/td/text()').getall() 
    

    然后我使用列表推导来清理列表,因为变量 table_rows 有多个 \n 项。

    【讨论】:

    • 嘿@AaronS,在我发布问题之前,我已经用 /tbody 尝试过 xpath,但我不知道如何摆脱“\n\r\t”我在哪里可以阅读所以格式化这样的东西?
    • 如果 \n\r\t 位于字符串的开头或结尾,则 strip('\n\r\t') 将剥离它。但有时您需要使用替换字符串方法来替换它。 string.replace('\n\r\t',''),该方法的第二个参数是您要替换它的内容。这些是字符串方法的示例,python 文档有一个巨大的列表,但搜索常见的字符串方法会有所帮助。如果 '\n' 在列表中,那么还有多种方法可以实现这一点,我只是做了一个列表推导来创建一个新列表,其中没有任何带有 '\n' 的项目。再次阅读列表方法是关键,没有那么多。
    • 谢谢,我去看看,我对 python 的了解不多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 2012-10-26
    • 1970-01-01
    相关资源
    最近更新 更多