Scrapy CSS选择器失效:深入理解浏览器与爬虫获取HTML内容的差异

48次阅读

Scrapy CSS 选择器失效:深入理解浏览器与爬虫获取 HTML 内容的差异

在使用 scrapy 进行网页抓取时,开发者常常会遇到一个令人困惑的问题:精心调试的 css 选择器 浏览器 开发者 工具 中能够准确匹配元素,但在 scrapy 爬取时却一无所获。这通常并非选择器本身有误,而是 scrapy 所见的网页内容与用户在 浏览器 中看到的内容存在本质差异。本文将深入探讨这一现象的原因,并提供实用的方法来验证 scrapy 实际获取的html,从而有效解决此类问题。

1. 问题现象:css选择器在 Scrapy 中失效

考虑一个典型的场景:你正在爬取两个结构相似的页面,例如https://dicionario.priberam.org/putear 和 https://dicionario.priberam.org/puteares。你使用了一个css 选择器,例如 div.dp-conteudo__esquerda span.varpb,期望从中提取特定的文本。在第一个页面上,该选择器成功返回了结果,但在第二个页面上,它却返回空值。

初步检查页面源代码可能会发现,第二个页面上确实存在一个带有 varpb 类的 span 标签,甚至可能出现在不同的父级元素下,但无论如何,Scrapy 似乎都无法找到它。这种不一致性让开发者感到困惑,因为理论上,只要元素存在于 html 中,选择器就应该能够匹配。

2. 根本原因:浏览器与 Scrapy 获取内容的差异

问题的核心在于浏览器和 Scrapy 处理网页内容的方式不同。

  • 浏览器行为: 当你在浏览器中访问一个网页时,浏览器不仅会下载初始 HTML 文档,还会解析并执行其中包含的 javaScript 代码。这些javascript 代码可能会动态地修改 dom 结构、从服务器请求额外的数据(例如通过 ajax),然后将这些数据插入到页面中。因此,你在浏览器开发者 工具 中看到的“源代码”实际上是经过 JavaScript 处理和渲染后的最终 DOM 结构。
  • Scrapy 行为: Scrapy(以及大多数传统的 网络爬虫)默认情况下只负责下载服务器返回的原始 HTML 响应。它不会执行 JavaScript 代码,也不会渲染页面。这意味着,如果网页的某些内容是通过 JavaScript 动态加载或生成的,那么这些内容将不会出现在 Scrapy 获取的原始 HTML 中。

回到我们的例子,第二个页面 https://dicionario.priberam.org/puteares 上的目标 span.varpb 元素很可能就是通过 JavaScript 在页面加载完成后动态添加到 DOM 中的。由于 Scrapy 不执行 JavaScript,它在抓取时就无法“看到”这个动态添加的元素,因此选择器自然会失效。而第一个页面 https://dicionario.priberam.org/putear 上的相应元素可能直接包含在初始 HTML 中,所以 Scrapy 能够成功获取。

立即学习 前端免费学习笔记(深入)”;

3. 验证 Scrapy 所见内容的最佳实践

理解了原因之后,解决问题的关键就是确保你的 CSS 选择器是基于 Scrapy 实际获取到的 HTML 内容来编写的。以下是两种验证 Scrapy 所见内容的方法:

3.1 使用 Scrapy Shell 的 view(response)命令

Scrapy Shell 是一个强大的交互式环境,允许你在不运行整个 爬虫 的情况下测试代码和检查响应。view(response)命令可以让你在浏览器中打开 Scrapy 当前处理的 response对象 所包含的 HTML 内容。这能直观地展示 Scrapy 到底“看到了”什么。

操作步骤:

  1. 在终端中启动 Scrapy Shell 并 fetch 目标 URL:
    scrapy shell 'https://dicionario.priberam.org/puteares'

  2. 在 Scrapy Shell 中,执行 view(response):
    In [1]: view(response)

    这会打开一个新的浏览器窗口,显示 Scrapy 抓取到的原始 HTML。你可以使用浏览器开发者工具检查这个页面,看看目标元素是否真的存在。

    Scrapy CSS 选择器失效:深入理解浏览器与爬虫获取 HTML 内容的差异

    Calliper 文档对比神器

    文档内容对比神器

    Scrapy CSS 选择器失效:深入理解浏览器与爬虫获取 HTML 内容的差异 28

    查看详情 Scrapy CSS 选择器失效:深入理解浏览器与爬虫获取 HTML 内容的差异

3.2 将 response.text 保存到本地文件

另一种更直接、更方便离线分析的方法是将 Scrapy 获取到的原始 HTML 内容保存到一个本地文件。

操作步骤:

  1. 在 Scrapy Shell 中 fetch 目标 URL:

    In [2]: fetch('https://dicionario.priberam.org/putear') 2023-12-28 00:22:01 [scrapy.core.engine] INFO: Spider opened 2023-12-28 00:22:01 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://dicionario.priberam.org/putear> (referer: None)

  2. 将 response.text 写入一个本地html 文件

    In [3]: with open('putear.html', 'wt', encoding='utf8') as fd:    ……:     fd.write(response.text)    ……:

  3. 对第二个页面重复上述步骤:

    In [4]: fetch('https://dicionario.priberam.org/puteares') 2023-12-28 00:23:09 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://dicionario.priberam.org/puteares> (referer: None)  In [5]: with open('puteares.html', 'wt', encoding='utf8') as fd:    ……:     fd.write(response.text)    ……:

  4. 现在,你可以在本地文件系统找到 putear.html 和 puteares.html 这两个文件。用任何文本编辑器或浏览器打开它们,检查它们的源代码。你会发现,在 puteares.html 中,你期望的 div.dp-conteudo__esquerda span.varpb 结构很可能是不存在的,或者 span.varpb 元素位于完全不同的位置,导致你的原始选择器失效。

4. 总结与注意事项

  • 始终验证 Scrapy 所见: 当 CSS 选择器在浏览器中有效但在 Scrapy 中失效时,第一步也是最重要的一步就是验证 Scrapy 实际获取的 HTML 内容。这能帮助你区分是选择器错误还是内容动态加载的问题。
  • 动态内容处理: 如果确认目标内容是通过 JavaScript 动态加载的,传统的 Scrapy爬虫 将无法直接获取。在这种情况下,你需要考虑使用能够执行 JavaScript 的工具,例如:
    • Scrapy Splash: 一个轻量级的 JavaScript 渲染服务,可以与 Scrapy 集成。
    • Selenium/Playwright: 浏览器 自动化 工具,可以模拟用户行为,等待页面加载完成并获取渲染后的 HTML。
  • 选择器优化: 如果目标元素存在于 Scrapy 获取的 HTML 中,但只是位置与浏览器中看到的略有不同,那么你需要根据 Scrapy 实际获取的 HTML 结构来调整你的 CSS 选择器。
  • 优先级: 在调试 Scrapy 选择器时,优先使用 response.css()或 response.xpath()进行测试,而不是完全依赖浏览器开发者工具中的选择器结果,因为它们所操作的 DOM 可能不同。

通过理解 Scrapy 与浏览器在处理动态内容上的差异,并利用上述验证方法,你将能更有效地调试和开发你的 Scrapy 爬虫,从而避免因 HTML 内容不一致而导致的抓取失败。

站长
版权声明:本站原创文章,由 站长 2025-11-12发表,共计3108字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
1a44ec70fbfb7ca70432d56d3e5ef742
text=ZqhQzanResources