【问题标题】:How to extract hidden html content with scrapy?如何用scrapy提取隐藏的html内容?
【发布时间】:2020-07-23 16:30:36
【问题描述】:

我正在使用 scrapy(在 PyCharm v2020.1.3 上)构建一个爬取此网页的蜘蛛:“https://www.woolworths.com.au/shop/browse/drinks/cordias-juices-iced-teas /iced-teas”,我想以列表格式提取产品名称和面包屑,并将结果保存在 csv 文件中。 我尝试了以下代码,但它返回空括号 [] ,在我检查了 html 代码后,我发现内容以 angularjs 格式隐藏。 如果有人对此有解决方案,那就太好了 谢谢

import scrapy

class ProductsSpider(scrapy.Spider):
name = 'products'
start_urls = ['https://www.woolworths.com.au/shop/browse/drinks/cordials-juices-iced-teas/iced-teas']

def parse(self, response):
    product = response.css('a.shelfProductTile-descriptionLink::text').extract()
    yield "productnames"

【问题讨论】:

  • 面包屑是什么?
  • @AaronS by breadcrumb 我的意思是菜单路径:主页 > 饮品 > 甜酒、果汁和冰茶 > 冰茶

标签: python python-3.x web-scraping pycharm


【解决方案1】:

您将无法通过解析 HTML 获得所需的产品。它是大量面向 javascript 的,因此 scrapy 不会解析它。

获取产品名称的最简单方法,我不确定您所说的面包屑是什么意思是重新设计 HTTP 请求。 Woolworths 网站通过 API 生成产品详细信息。如果我们可以模仿浏览器为获取产品信息而发出的请求,我们就可以以简洁的格式获取信息。

首先你必须在settings.py中设置ROBOTSTXT_OBEY = False。小心这些数据的长期刮擦,因为您的 IP 可能会在某个时候被禁止。

代码示例

import scrapy


class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['woolworths.com']


    data = {
    'excludeUnavailable': 'true',
    'source': 'RR-Best Sellers'}

    def start_requests(self):
        url = 'https://www.woolworths.com.au/apis/ui/products/58520,341057,305224,70660,208073,69391,69418,65416,305227,305084,305223,427068,201688,427069,341058,305195,201689,317793,714860,57624'
        yield scrapy.Request(url=url,meta=self.data,callback=self.parse)
    def parse(self, response):
        data = response.json()

        for a in data: 
            yield { 
                'name': a['Name'],

            }

解释

我们从 start_requests 中定义的 URL 开始。此 URL 是 Woolworth 用于获取冰茶信息的 API 的特定 URL。对于 woodworths 上的任何其他链接,/products/ 之后的 URL 部分将特定于网站的该部分。

我们之所以使用它,是因为使用浏览器活动很慢并且容易脆弱。这速度很快,而且我们可以获得的信息通常是高度结构化的,更适合抓取。

那么我们如何获得您可能会询问的 URL?您需要检查页面,并找到正确的请求。如果您单击网络工具,然后重新加载网站。你会看到一堆请求。通常最大的请求是包含所有数据的请求。单击它并单击预览会在右侧为您提供一个框。这提供了产品的所有详细信息。

在下一张图片中,您可以看到产品数据的预览

然后我们可以从该请求中获取请求 URL 和其他任何内容。

我会经常将此请求复制为 CURL(Bash 命令),如此处所示

并将其输入 curl.trillworks.com。这可以将 CURL 转换为 python。为您提供格式良好的标头和模仿请求所需的任何其他数据。

现在把它放到 jupyter 中玩一下,你实际上只需要参数而不是标题,这要好得多。

回到代码。我们做一个请求,使用元参数我们可以传递数据,记住因为它在函数之外我们必须使用self.data,然后指定要解析的回调。

我们可以使用response.json()方法将JSON对象转换为每个产品对应的一组python字典。您必须有 scrapy V2.2 才能使用此方法。其他你可以使用data = json.loads(response.text),但你必须在脚本顶部输入import json

从预览和使用请求中的 json 我们可以看到这些 python 字典实际上是在一个列表中,因此我们可以使用 for 循环来循环每个产品,这就是我们在这里所做的。

然后我们生成一个字典来提取数据,a 指的是每个产品,它是它自己的字典,a['Name'] 指的是特定的 Python 字典键“名称”并为我们提供正确的值。为了更好地了解这一点,我总是在 jupyter 中使用 requests 包来找出获取我想要的数据的正确方法。

剩下要做的就是使用scrapy crawl test -o products.csv 将其输出到 CSV 文件。

在您指定此页面所需的任何其他数据之前,我真的无法为您提供更多帮助。请记住,您违反了网站希望您抓取的内容,而且该网站上的任何其他页面都需要找出 API 的特定 URL 才能获取这些产品。我已经为您提供了执行此操作的方法,我建议如果您想自动执行此操作,那么尝试与此作斗争是值得的。我们很乐意为您提供帮助,但您可以尝试学习编码的方式。

关于动态内容方法的附加信息

关于这个主题的信息非常丰富。以下是在查看面向 javascript 的网站时要考虑的一些准则。默认情况下,您应该尝试重新设计浏览器为加载页面信息而发出的请求。这就是本网站和许多其他网站中的 javascript 正在做的事情,它提供了一种动态方式,无需重新加载页面即可通过发出 HTTP 请求来显示新信息。如果我们能模仿那个请求,我们就能得到我们想要的信息。这是获取动态内容的最有效方式。

按优先顺序排列

  1. 重新设计 HTTP 请求
  2. Scrapy-splash
  3. Scrapy_selenium
  4. 将 selenium 包导入到您的脚本中

Scrapy-splash 比 selenium 包稍好,因为它预渲染页面,让您可以访问带有数据的选择器。 Selenium 很慢,容易出错,但可以让您模仿浏览器活动。

有多种方法可以将 selenium 包含到您的脚本中,请参阅下面的概述。

推荐阅读/研究

  1. 查看关于动态内容的scrapy文档here 这将为您概述处理动态内容的步骤。我会说一般来说硒应该被认为是最后的手段。在进行更大规模的抓取时效率非常低。

  2. 如果您正在考虑将 selenium 包添加到您的脚本中。这可能是让您的脚本工作的较低门槛,但不一定那么有效。归根结底,scrapy 是一个框架,但在添加 3rd 方包方面有很大的灵活性。蜘蛛脚本只是一个在后台导入scrapy架构的python类。只要您注意响应并翻译一些硒以使用scrapy,您应该能够将硒输入到您的脚本中。我认为这个解决方案可能是效率最低的。

  3. 考虑使用 scrapy-splash,splash 会预渲染页面并允许您添加 javascript 执行。文档是 here 和来自 scrapinghub here 的一篇好文章

  1. Scrapy-selenium 是一个带有自定义 scrapy 下载器中间件的软件包,允许您执行 selenium 操作并执行 javascript。 Docs here 你需要尝试一下才能从中获取登录过程,它没有与 selenium 包本身相同的详细程度。

【讨论】:

  • 非常感谢您的回答先生,我在网络抓取方面非常新,所以我尝试学习,面包屑指的是菜单路径:主页 > 饮料 > 甜酒、果汁和冰茶> 冰茶以列表形式显示,我会尽量采纳您的建议并尽快给您反馈
  • 不太清楚您所说的列表格式是什么意思,您必须更加明确。我必须强调这将无法爬取整个站点,并且这样做会遇到挑战。我不是来为你做这些的,这足以让你思考如何推断这个问题,而且你对这个问题已经相对具体。如果您需要与您最初发布的特定问题不直接相关的任何其他问题的帮助,我建议您在 SO 而不是此处发布另一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-15
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
相关资源
最近更新 更多