使用 Scrapy 解析 JSON 响应

2024 年 8 月 29 日 | 阅读 6 分钟

Scrapy 是一个强大而灵活的 Python Web 抓取框架。它允许开发人员轻松地从网站提取数据,使其成为那些希望以结构化格式提取数据的用户的热门选择。本文将讨论如何使用 Scrapy 抓取 JSON 响应。

在开始之前,让我们简要讨论一下 JSON 是什么。JSON 代表 JavaScript Object Notation,它是一种轻量级的数据交换格式。它易于人类阅读和编写,也易于机器解析和生成。JSON 是 Web 上数据交换的流行格式,通常用于在 Web 服务器和 Web 应用程序之间传输数据。

在处理 API 或使用 JavaScript 动态生成内容的网站时,抓取 JSON 响应是很常见的。Scrapy 通过其对 Scrapy HTTP 请求/响应周期的内置支持,提供了一种方便的方法来抓取 JSON 响应。

让我们以一个简单的 JSON API 端点为例,该端点返回以下格式的书籍列表:

要抓取此 JSON 响应,我们必须创建一个 Scrapy 爬虫。爬虫是一个 Python 类,它定义了如何抓取网站,包括如何发送 HTTP 请求、解析 HTML 或 JSON 响应以及从中提取数据。

要创建 Scrapy 爬虫,我们需要定义以下内容:

  • 爬虫的名称。
  • 开始 URL 是爬虫将访问的第一个 URL。
  • 当收到来自开始 URL 的响应时,将调用解析方法。

让我们创建一个简单的爬虫来抓取上述 JSON 响应。

让我们一步一步地分析这段代码。我们首先导入 scrapy 和 json 模块。然后,我们定义一个继承自 scrapy.Spider 的新类 BooksSpider。

我们将 name 属性设置为“books”,这将在运行爬虫时用于识别它。我们还将 start_urls 属性设置为爬虫将开始抓取的 URL 列表。在这种情况下,我们只有一个 URL,即返回 JSON 响应的端点。

parse 方法定义了如何从 JSON 响应中提取数据。我们首先使用 json-loads 方法加载响应正文,该方法将 JSON 数据解析为 Python 字典。然后,我们使用“books”键从 JSON 响应中提取书籍列表。

接下来,我们循环遍历 books 列表中的每本书,并使用字典键提取相关数据。然后,我们 yield 一个包含每本书提取数据的 Python 字典。

yield 关键字用于代替 return,因为我们想要返回一个生成器对象,该对象允许我们惰性地加载和处理数据。这在处理大量数据时很重要,因为它避免了一次性将所有数据加载到内存中。

现在我们已经定义了爬虫,我们可以使用 scrapy crawl 命令来运行它。我们需要将爬虫的名称作为参数指定,如下所示:

Scrapy 然后将开始抓取开始 URL 并遵循页面上找到的任何链接。由于此示例中只有一个开始 URL,因此爬虫将简单地请求 API 端点并提取数据。

爬虫抓取完成后,它将以多种格式输出提取的数据,包括 JSON、CSV 和 XML。默认情况下,Scrapy 将以 JSON 格式输出数据。我们可以使用 -o 选项后跟所需的文件扩展名来指定其他格式。例如,要以 CSV 格式输出数据,我们可以使用以下命令:

这将在当前目录中创建一个名为 books.csv 的新文件,其中包含 CSV 格式的提取数据。

Scrapy 提供了强大的 Web 抓取功能集,包括处理 cookie、处理重定向、使用代理以及处理用户身份验证的支持。当处理需要附加身份验证或安全措施的复杂网站或 API 时,这些功能可能很有优势。

例如,如果 JSON API 端点需要有效的 API 密钥,我们可以使用 Request 对象的 headers 属性轻松地将其添加到请求头中。我们还可以使用 Request-meta 属性在请求之间传递附加数据,例如会话 ID 或 CSRF 令牌。

Scrapy 的另一个有用功能是其自动处理分页的能力。如果 JSON API 端点以分页方式返回数据,我们可以定义一个 start_requests 方法,该方法为每个数据页面生成一系列请求。然后,我们可以使用 parse 方法从每个页面提取相关数据并将其 yield 到输出文件。

以下是如何抓取返回分页数据的 JSON API 端点的示例:

在此示例中,我们定义了一个 start_requests 方法,该方法为每个数据页面生成一系列请求。我们循环遍历从 2 到 9 的每个页面编号(假设有九个页面),并使用 scrapy.Request 方法为每个页面创建一个请求。我们将页面 URL 作为参数传递,并将 callback 属性设置为 parse 方法。

当爬虫运行时,它将使用 start_urls 属性请求第一个数据页面。然后,它将使用 start_requests 方法为其余页面生成请求。parse 方法将为每个页面调用,并提取相关数据并将其 yield 到输出文件。

Scrapy 还提供对错误处理和重试的支持。如果请求由于网络错误或其他问题而失败,Scrapy 将自动重试该请求一定次数(默认为三次)。如果请求失败,它将被标记为失败,爬虫将继续处理下一个请求。

我们还可以使用爬虫的 handle_httpstatus_list 属性定义自定义错误处理逻辑。例如,如果 JSON API 端点在找不到页面时返回 404 错误,我们可以定义一个自定义错误处理方法来生成下一个页面的新请求。

在此示例中,我们将 `handle_httpstatus_list` 属性定义为包含 `404` 错误代码。如果请求返回 `404` 错误,爬虫将使用失败的响应作为参数调用 `parse` 方法。在 `parse` 方法中,我们检查响应状态是否为 `404`。如果是,我们假设我们已到达分页的末尾并返回。如果状态不是 `404`,我们像往常一样提取数据并将其 yield 到输出文件。

总而言之,Scrapy 提供了强大的功能来从网站和 API 抓取 JSON 响应。通过定义一个从中提取相关数据的爬虫,我们可以轻松地删除大量结构化数据,并将其保存为各种格式以供进一步分析。Scrapy 是一个多功能工具,可以处理许多 Web 抓取任务,并支持分页、错误处理和身份验证。

结论

总之,使用 Scrapy 抓取 JSON 响应是一个直接的过程,可以通过使用对 HTTP 请求和 JSON 解析的内置支持来完成。通过定义一个从中提取所需数据的爬虫,我们可以轻松地从使用 JSON 作为其数据格式的 API 和网站中删除大量结构化数据。