【问题标题】:Scrapy: Trying to iterate nested items but not producing desired outputScrapy:尝试迭代嵌套项但未产生所需的输出
【发布时间】:2017-10-19 03:48:20
【问题描述】:

我对 Python 和 Scrapy 非常陌生,但是当我尝试迭代嵌套的 html 元素时,它并没有产生预期的结果。

以下是 HTML,我正在尝试废弃。

<div class="level1" role="main">
<div class="level2">
    <h1 id="fullStoreHeading" class="class_h1">Page Title</h1>
    <div class="fsdColumn_3">
        <div class='fsdDeptBox'>
            <img alt="" src="" aria-hidden="true" height="100%" width="100%">
            <h2 class="fsdDeptTitle">TV</h2>
            <div class='fsdDeptCol'>
                <a class="class_a" href="/test?_encoding=UTF8&id=1001">Samsung</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1002">Vizio</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1003">Element</a>
            </div>
        </div>
        <div class='fsdDeptBox'>
            <img alt="" src="" aria-hidden="true" height="100%" width="100%">
            <h2 class="fsdDeptTitle">Laptop</h2>
            <div class='fsdDeptCol'>
                <a class="class_a" href="/test?_encoding=UTF8&id=1004">Apple</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1005">Microsoft</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1006">Dell</a>
            </div>
        </div>
    </div>


    <div class="fsdColumn_3">
        <div class='fsdDeptBox'>
            <img alt="" src="" aria-hidden="true" height="100%" width="100%">
            <h2 class="fsdDeptTitle">Video Game Console</h2>
            <div class='fsdDeptCol'>
                <a class="class_a" href="/test?_encoding=UTF8&id=1007">Xbox One</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1008">Xbox 360</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1009">PS 5</a>
            </div>
        </div>
        <div class='fsdDeptBox'>
            <img alt="" src="" aria-hidden="true" height="100%" width="100%">
            <h2 class="fsdDeptTitle">SSD</h2>
            <div class='fsdDeptCol'>
                <a class="class_a" href="/test?_encoding=UTF8&id=1010">Samsung Evo</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1011">Crucial</a>
                <a class="class_a" href="/test?_encoding=UTF8&id=1012">Sandisk</a>
            </div>
        </div>
    </div>
</div>

我试图从上面的 html 生成的输出是一个列表:

产品类别 -> 品牌 -> Id

例如

电视

   Samsung 1001

   Vizio 1002

   Element 1003

笔记本电脑

  Apple 1004

  Microsoft 1005

  Dell 1006

视频游戏机

  Xbox Onen 1007

  Xbox 360 1008

  PS4 1009

ProductCategories.py

def parse(self, response):
    l = ItemLoader(item=ProductSpiderItem(), response=response)

    titles = response.xpath('//*[@class="fsdDeptTitle"]')

    for title in titles:

        Product_Category= title.xpath('text()').extract()

        l.add_value('Product_Category', Product_Category)

        for brnd in 
          title.xpath('//*[@class="fsdDeptCol"]/a[@class="class_a"]'):

                Brand = brnd.xpath('text()').extract()
                l.add_value('Brand', Brand)

    return l.load_item()

此时它正在打印“Outer For Loop”中的所有产品类别一次,“Inner For Loop”正在打印所有品牌,而与产品类别无关,并且“Inner For Loop”在任何时候打印所有品牌“外部 For 循环”运行。

非常感谢任何帮助解决问题。

非常感谢。

【问题讨论】:

    标签: python scrapy


    【解决方案1】:

    您的第一个“for”循环发送它以遍历 HTML 的 &lt;h2 class="fsdDeptTitle"&gt;SSD&lt;/h2&gt; 部分。然后您要做的是在该代码中查找class=class_a。它不能这样做,因为第一个“for”循环太具体,无法选择“class_a”所在的 HTML。

    您可以通过让您的“for”循环在 HTML 中看起来更高一级来解决此问题。

    titles = response.xpath("//*[@class='fsdDeptBox']")
    for title in titles:
        Product_Category=title.xpath('text()').extract()
        l.add_value('Product_Category', Product_Category)
    
        for brnd in title.xpath('div[@class="fsdDeptCol"]'):
            Brand = brnd.xpath('*/text()').extract()
            l.add_value('Brand', Brand)
        return l.Load_item()
    

    我更改了第一个 'for' 循环以选择足够的 HTML 以包含指向 'class_a' 文本的路径

    旁注。我不太了解正确的 HTML 术语,但我希望这仍然有意义。

    【讨论】:

    • 抱歉,我在写这篇文章时忘记在 // 后面加上 *。我已经编辑了帖子。根据您的建议,我尝试了 '*[@class="fsdDeptCol"]/a[@class="class_a"]' ...但它没有返回任何品牌记录。
    • 我编辑了我的答案以更好地回答这个问题。我将给出的 HTML 作为文件保存在我的计算机上,并用 scrapy shell 打开它。我能够获得所需的输出。
    【解决方案2】:

    我认为您应该多检查一下ItemLoaders 的工作原理。它们还取决于您的项目和项目加载器是如何定义的,例如,假设您已经这样定义:

    class ProductItem(Item):
        category = Field()
        brand = Field()
    class ProductItemLoader(ItemLoader):
        default_item_class = ProductItem
        default_output_processor = TakeFirst()
    

    那么你可以这样做:

    for product in response.css('.fsdDeptCol a'):
        il = ProductItemLoader(selector=product)
        il.add_xpath('category', './ancestor::*/preceding-sibling::h2/text()')
        il.add_xpath('brand', './text()')
        yield il.load_item()
    

    【讨论】:

    • 非常感谢...有没有从 href 值中提取“id”的最佳方法。我可以从 href 值中提取整个字符串。
    • 当然,假设你有 id 字段(以及从 w3lib 和 scrapy 的处理器正确导入),只需添加类似 il.add_xpath('id', './@href', MapCompose(lambda x: url_query_parameter(x, 'id')))
    • 再次感谢。我希望我可以再给你一票。可以请我参考任何好的文章或书籍,在那里我可以学习这些先进的技术,如 MapCompose 等。
    • 很高兴它成功了! (我认为您可以将此问题标记为已回答:))我真的很喜欢文档doc.scrapy.org/en/latest/topics/loaders.html 您还可以检查来自 scrapy 的 repo 的测试
    猜你喜欢
    • 2014-07-30
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    相关资源
    最近更新 更多