Exposing the Invisible 中文抓取指南 | 抓取Web数据

网页数据抓取

本指南介绍了一系列步骤,可用于自动化收集在线 HTML 表格,并将这些表格转换为更有用的格式。这个过程通常被称为“网页抓取”。1

公共数据有时非常有用。有意义的调查利用了各种数据,从实时航班跟踪数据公司公共注册信息,再到游说披露信息以及(https://exposingtheinvisible.org/en/articles/disclosures-of-a-hashtag)等等),不胜枚举。尽管此类信息在网络上显著增多,但它们并非总是以可用的格式提供。将公共数据用于调查,通常不仅要求数据是机器可读的,而且是结构化的。换句话说,一个包含手绘图表照片的 PDF 文件,远不如一个包含该图表实际数据的 Microsoft Excel 文档有用。1 这种对结构化、可用数据的需求,正是学习网页抓取等技能的根本原因,因为它直接解决了调查人员在获取和处理原始信息时面临的核心挑战。

即使在政府根据信息自由 (FoI) 法律被要求发布其收集、维护或资助的数据的情况下,这也可能成为一个问题。事实上,政府有时会故意混淆数据,以阻止可能揭示他们希望隐藏的某些细节的进一步分析。1

处理公共数据的调查人员面临许多障碍,但其中最常见的两个是:

  1. 嵌入在一系列连续网页中的糟糕、多页的(https://en.wikipedia.org/wiki/HTML) 结构;以及
  2. 困在无法访问的 PDF 文档地狱中的格式精美的表格。1

本指南旨在解决第一个挑战。它提出了一系列步骤,可用于自动化收集在线 HTML 表格,并将这些表格转换为更有用的格式。这个过程通常被称为“网页抓取”。在下文讨论的示例中,将生成(https://en.wikipedia.org/wiki/Comma-separated_values) 文档,这些文档可随时导入 LibreOffice CalcMicrosoft Excel。(有关处理 PDF 表格的建议,请参阅这篇文章,并关注本站即将推出的关于 PDF 抓取工具 Tabula 的指南。)1 通过明确区分这两大挑战并声明本指南的重点,读者可以对将要学习的内容有一个清晰的预期,并理解所学技能在更广泛的数据提取领域中的位置。

本指南的结构

本指南包含四个部分。第一部分讨论了选择本指南其余部分所涵盖的工具和技术的理由。第二部分是关于 HTML 结构、CSS 选择器(用于识别网页上一个或多个特定元素的简短关键字序列)以及如何使用 Tor 浏览器的内置元素检查器来学习第三部分所需知识的简要入门。在第三部分中,将逐步介绍如何将这些选择器应用到 (https://scrapy.org/) 中,下载 HTML 数据并将其另存为 CSV 文件。最后,呈现三个外部网页表格,它们比之前使用的示例更有趣也更复杂。1 这种结构化的学习路径,从基本原理到实际操作,再到高级应用,旨在逐步建立读者的知识和技能。

如果不需要了解这些理由,或许应该直接跳到“使用 Scrapy 和 Tor 浏览器抓取表格数据”部分。1 这种为不同经验水平的读者提供导航建议的做法,体现了对读者时间和先前知识的尊重。

本指南适合哪些人?

简而言之,任何拥有 Debian GNU/Linux 系统——无论是计算机、虚拟机还是启动盘——并且愿意花费大半天时间学习如何可靠、灵活且私密地抓取网页数据的人。即使他们发现那些不太可靠、不太灵活、不太安全的方法可能工作量更少,也仍然愿意学习。1 这种对投入时间和特定技术环境的坦诚,有助于筛选出那些真正致力于掌握这种“硬核方法”以获取其长远益处的读者。

更具体地说,以下步骤假定用户能够编辑文本文件并在 Linux 终端中输入命令。这些步骤是从(https://tails.boum.org) 用户的角度编写的,但在必要时也包含了确保它们在任何(https://www.debian.org) 系统上都能工作的提示。将这些步骤调整为适用于其他一些 Linux 发行版应该相当容易,使其在 Windows 上工作也应该是可能的。1

本指南不要求熟悉 Python 编程语言或 HTML 和 CSS 等网页设计概念,尽管这三者都会在下文中出现。任何关于这些技术的必要知识都将得到解释。1

最后,本指南是为 Firefox 网页浏览器的各种版本编写的,包括 Tor 浏览器和 Iceweasel。(从现在开始,将特别提及 Tor 浏览器,但所描述的大多数步骤在其他版本的 Firefox 上也能正常工作。)由于对 Tails 兼容性的承诺,并未仔细研究 Chromium(谷歌 Chrome 网页浏览器的开源版本)的抓取扩展。因此,如果使用的是 Windows 或非 Tails 的 Linux 发行版——并且如果不太关心匿名性——可以使用 Firefox,或者可以看看 Chromium 的 Web scraper 扩展。它已有几年历史,但看起来仍然很有前景。它是自由开源软件,与本指南中推荐的 Scrapy 和其他工具一样,采用 GNU 通用公共许可证 (GPL) 授权。1 尽管优先推荐基于 Tails 和 Firefox 的方案,但提及 Chromium 扩展等替代方案,并在指出其开源性质时,体现了一种务实的态度,同时也坚持了对开放和透明工具的偏好。

为“The Hard Way”辩护

如果粗略浏览了本指南的其余部分,可能已经注意到截屏数量惊人地少。当然,有一些,但大多数只是显示 Tor 浏览器的内置检查器被用来识别一些像 td.col1 div.resource > a::attr(href) 这样晦涩难懂的诗句。如果那段代码让你感到温暖亲切,或许可以考虑跳到“使用 Scrapy 和 Tor 浏览器抓取表格数据”部分。但如果它看起来有点吓人,请耐心看下去。1 这种开门见山地承认潜在的技术门槛,并通过共情来引导读者,有助于建立信任,并为后续的论证铺平道路。

向你最喜欢的搜索引擎提问,你会发现互联网上有很多图形化的网页抓取工具。这些工具在不同程度上提供了一个用户界面,允许:

  • 通过指向和点击来挑选网页上可用的内容;
  • 下载想要的内容;以及
  • 以选择的格式保存它。1

所有这些听起来都很棒。但如果开始深入研究细节并试用这些软件,会发现许多注意事项。其中一些工具是商业的、闭源的,或者昙花一现。有些功能有限,或者只能在付费前使用有限的时间。有些是由希望帮助抓取数据以便自己也拥有一份副本的公司运营的基于云的服务。有些是使用过时且不安全的浏览器扩展框架编写的。有些只适用于非常简单的表格。有些不知道如何点击“下一页”按钮。有些会向谷歌分析发送请求。诸如此类。1 对这些图形化工具的系统性批判,指出了它们在成本、可持续性、隐私和功能上的常见缺陷,从而有力地论证了为何需要一种更强大、更可控的方法。

所有这些都不足为奇。开发和维护这样的软件需要付出努力,而且如今数据行业举足轻重。当然,这可能并非对所有人在所有时候都重要。许多优秀的调查工作是通过将半打“15 天试用”许可证串联起来完成的。但这些指南的目标是提供不需要做出此类权衡的解决方案。并且,当发现自己需要执行以下操作时,这些解决方案不会让你束手无策:

  • 在多个会话中,增量地抓取大量数据;
  • 解析复杂的表格;
  • 下载图像和 PDF 等二进制文件;
  • 隐藏对正在抓取的数据的兴趣;或者
  • 遵守软件许可证和用户协议的法律约束。1 通过清晰阐述“硬核方法”所能实现的目标——这些目标恰恰是许多图形化工具难以企及的——本指南为其学习曲线提供了充分的理由。

为什么你可能想用 Tails 来抓取数据?

在抓取网页数据时,有很多理由可能让你想使用 Tails。即使打算发布这些数据——或者发布会暴露你访问过这些数据的内容——你可能仍然希望至少在一段时间内隐藏你或你的组织正在特定主题上搜集信息的事实。通过 Tor 请求相关页面,你可以控制你的参与公开的时间点。在此之前,你可以阻止各种行为者知道你正在做什么。这包括网吧里的其他人、你的互联网服务提供商 (ISP)、监视机构、你正在抓取的网站的运营者以及他们的 ISP 等等。1

Tails 还有助于保护你的研究、分析和草稿输出免遭盗窃和没收。当在 Tails 上启用持久存储时,你正在创建一个可以在其中保存数据的单个文件夹,并且该文件夹的内容保证是加密的。当然,还有其他加密数据的方法,但很少有方法能像这样难以出错。Tails 磁盘也很小,易于备份,甚至更容易丢弃。在某些情况下,将一个 Tails 盘放在口袋里是携带笔记本电脑的一个不错的替代方案,尤其是在过境、检查站和突袭可能引起关注的行程中。1 这种对操作安全的全面考量,从在线匿名到物理数据安全,突显了 Tails 对于处于敏感环境中的调查人员的价值。

更普遍地说,如果你希望将敏感的调查工作与个人在线活动分开,Tails 是一个非常有用的工具。即使只有一台笔记本电脑,也可以通过将相关数据的获取和分析限制在 Tails 系统中,从而有效地隔离高风险调查。而且,即使正在从公共网站抓取平庸的数据,也值得考虑是否每次开始为新项目搜寻信息时都必须做出这个决定。除非寻求的数据无法通过 Tor 访问(这种情况确实会发生),否则有充分的理由倾向于隔离。1 提倡将隐私和隔离作为默认操作模式,而不是事后才考虑的措施,这反映了一种成熟的安全意识。

使用 Scrapy 和 Tor 浏览器抓取表格数据

可靠且灵活地抓取网页数据通常需要两个步骤。除非愿意并且能够使用一体化的图形抓取工具,否则通常需要:

  1. 识别出那些能够标识你想要的内容(并且仅仅是你想要的内容)的选择器,然后
  2. 使用这些选择器来配置一个专门用于从网页中提取内容的工具。1

在下面介绍的示例中,将依靠 Tor 浏览器来帮助完成第一阶段,并使用 Scrapy 来处理第二阶段。1 这种将任务分解为“识别”和“提取”两个阶段,并为每个阶段指定特定工具的模块化方法,简化了学习过程。

识别选择器

在开始寻找选择器之前,将首先简要介绍超文本标记语言 (HTML) 和层叠样式表 (CSS)。可以随意跳过这部分。而且,如果不跳过,请放心,当你真正开始使用这些工具时,你的网络浏览器将完成大部分繁重的工作。1 这种对初学者的体谅,以及提供可选的基础知识回顾,使得指南对不同背景的读者都更具包容性。

一个非常简短的 HTML 教程

大多数网站在到达你的网络浏览器时,都是以 HTML 页面的集合形式出现的。一个 HTML 文档的基本底层结构大致如下:

<html>
  <body>
    <p>页面内容...</p>
  </body>
</html>

HTML <table> 元素通常用于格式化这些页面的内容,尤其是在呈现数据时。下面是一个例子:

第一列标题第二列标题
页面一,行一,列一页面一,行一,列二
页面一,行二,列一页面一,行二,列二

上一页下一页

如果将上面的表格和导航链接添加到简化的 HTML 页面中,最终会得到以下元素集合:

<html>
  <body>
    <table>
      <thead>
        <tr>
          <th><p>第一列标题</p></th>
          <th><p>第二列标题</p></th>
        </tr>
      </thead>
      <tbody>
        <tr class="odd">
          <td><p>页面一,行一,列一</p></td>
          <td><p>页面一,行一,列二</p></td>
        </tr>
        <tr class="even">
          <td><p>页面一,行二,列一</p></td>
          <td><p>页面一,行二,列二</p></td>
        </tr>
      </tbody>
    </table>
    <p><a href="/guides/scraping">上一页</a> - <a href="/guides/scraping-2">下一页</a></p>
  </body>
</html>

在此,结构比元素本身的含义更重要,但其中一些“标签”有点晦涩,所以:

  • <p></p> 开始和结束一个段落
  • <a> 开始一个可点击的链接(</a> 结束它)
  • <a></a> 标签之间的文本(“下一页”)是你点击的内容
  • <a> 标签内部href=/guides/scraping-2 告诉浏览器点击时要去哪里
  • <tr></tr> 开始和结束表格中的一行
  • <td></td> 开始和结束表格行中的一个单元格
  • <th></th><td></td> 类似,但它们用于表格标题
  • <table></table> 你已经弄明白了 1

稍后将讨论如何查看网页背后的 HTML,但如果现在就想看看,只需右键单击上面的表格并选择“检查元素”。实际的 HTML 比上面显示的略复杂,但相似之处应该很明显。(可以通过单击其右上角的小 X 来关闭“检查器”窗格。)1 鼓励读者主动使用浏览器工具进行探索,这是一种有效的实践学习方法,能够将抽象的代码与可见的网页元素联系起来。

一个相对简短的 CSS 教程

为了使特定类型的某些(但不是全部)HTML 元素以特定方式表现,可以为它们分配一个 classid 或其他一些“属性”。以下是上述表格的一个略微不同的版本:

第一列标题第二列标题
页面一,行一,列一页面一,行一,列二
页面一,行二,列一页面一,行二,列二

上一页下一页

这可能看起来像这样:

<html>
  <body>
    <table class="classy">
      <thead>
        <tr>
          <th><p>第一列标题</p></th>
          <th><p>第二列标题</p></th>
        </tr>
      </thead>
      <tbody>
        <tr class="odd">
          <td class="special"><p>页面一,行一,列一</p></td>
          <td><p>页面一,行一,列二</p></td>
        </tr>
        <tr class="even">
          <td class="special"><p>页面一,行二,列一</p></td>
          <td><p>页面一,行二,列二</p></td>
        </tr>
      </tbody>
    </table>
    <p><a id="prev_page" href="/en/guides/scraping">上一页</a> - <a id="next_page" href="/en/guides/scraping2">下一页</a></p>
  </body>
</html>

注意某些(但不是全部)<td> 标签内的 class="special"。目前,这些单元格并非特别特殊。它们只是灰色的。而那些 prev_pagenext_page 元素看起来就像任何其他链接一样。但这不是重点。重点是可以使用这些“属性”以一致的方式识别特定类型的数据。在编写 CSS 规则时,网页设计师依靠这种技术来为网页应用图形样式。我们将用它来提取数据。1

为此,需要确定所关注内容的 CSS 选择器。

让我们从那个 id="next_page" 开始。有几种不同的选择器可以用来识别上面示例中的“下一页”链接。最长且最具体的是:

html > body > p > a#next_page

但是,由于只有一个 html 文档,并且它只有一个 body,可以将整个表达式缩短为 p > a#next_page。再者,由于只有一个 next_page,可以只使用 a#next_page。甚至 #next_page。所有这些都是完全有效的选择器。1

此时,你可能想知道所有这些符号是什么意思。正如你可能注意到的,在引用 id 值时,在其前面加上了一个 #。而 > 符号表示“子”关系。它可以用来尽可能精确地识别最右边的元素。查看上面的 HTML 片段,可以看到想要的 <a><p> 的子元素,<p><body> 的子元素,而 <body> 又是 <html> 的子元素。1

以下是一些可能有帮助的示例(如果它们没有帮助,也可以安全地忽略它们):

  • p 会选择上面示例中的每个段落
  • th > p 会选择列标题
  • td > p 会选择四个主要表格单元格的内容
  • body > p 会选择“上一页”和“下一页”链接 1

如果用空格而不是 > 分隔两个元素,则表示“后代”关系。这允许跳过中间的一些步骤。所以 body a#next_page 是有效的,即使它省略了中间的 p,而 body > a#next_page 是无效的(这意味着如果使用它,它将无法“选择”任何东西)。后代关系覆盖的范围更广。例如,body > p 只会选择底部的链接,而 body p 会选择页面上的每个段落。1

那么 class="special" 属性呢?可以像使用 ID 一样使用类,但是用句点 (.) 代替 #。所以,以下所有选择器都会选择相同的数据。看看你是否能弄清楚它是什么:

  • td.special > p
  • .special > p
  • .special p
  • table td.special > p 答案:第一列中所有主要表格单元格的内容 1 这种从简单标签选择到类/ID 选择,再到关系选择器的逐步讲解,有助于学习者逐层构建对 CSS 选择器强大功能的理解。通过一个小型测验来检验理解程度,能够有效地巩固所学知识。

了解你需要哪些选择器

要从网页上的 HTML 表格中抓取数据,你需要一个能够识别该表格中所有的选择器,以及每个的一个选择器。因此,要抓取上面第二个(绿色)表格,你需要三个选择器。有很多可行的变体,但这里是一种可能性:

  • 行选择器html body table.classy > tbody > tr
  • 第一列选择器td.special > p
  • 第二列选择器td:nth-child(2) > p 1

稍后将讨论如何获取这些值,但首先:

  1. 为什么列选择器不以 html body 或至少 table.classy tr 开头?
  2. nth-child(2) 是什么意思?
  3. 分布在多个页面上的表格怎么办?1

1. 列选择器应用于单行,而不是整个页面:

在接下来的部分中,当最终开始提取数据时,你的每个列选择器都将针对由行选择器识别的每一行使用一次。由于编写抓取文件的方式,行选择器应该是相对于它们所在的行。所以它们不应该以 tr 或任何“高于”tr 的内容开头。1

2. nth-child(n) 技巧:

根据正在抓取的表格的配置,可能不必使用此技巧,但在处理不包含每个列的 class=”whatever” 属性的表格时,它可能非常有用。只需确定想要的列,并将该数字放在括号之间。因此,在此示例中,td:nth-child(1) 与 td.special 相同。而 td:nth-child(2) 表示“第二列”。这里使用此方法是因为没有其他方法可以在不匹配第一列的情况下匹配第二列。1

3. 抓取多页表格:

如果希望抓取器自动“单击下一页链接”,则必须告诉它该链接在哪里。上面两个示例表格的下方都有一个下一页链接。绿色表格下方的链接很简单:a#next_page 就足够了。第一个表格下方的链接有点棘手,因为它没有 class,并且大多数页面在其 HTML 中的某个位置至少会包含另一个 <a>…</a> 链接。在这个简化的示例中,html body > p:nth-child(1) > a 可以正常工作,因为该链接位于 <body> 内部但不在 <table> 内部的第一个段落中。1

确定这些选择器是抓取网页数据中最困难的部分。但别担心,Tor 浏览器有一些功能使其比听起来更容易。1 通过问答形式直接解决初学者可能遇到的困惑,例如选择器的相对性以及 nth-child 伪类的用法,这显示了对学习者视角的深刻理解,并有效地降低了学习难度。

使用 Tor 浏览器的检查器识别你需要的选择器

如果使用的 Linux 系统没有预装 Tor 浏览器,可以从(https://www.torproject.org/download/download-easy.html.en)获取),或者按照 Security-in-a-Box 上的(https://securityinabox.org/en/guide/torbrowser/linux)进行操作进行操作)。1

按照以下步骤练习在真实页面上识别选择器。这些针对 Tor 浏览器检查器的具体、可操作的指导,将抽象的选择器知识转化为用户可以执行的实际步骤。

步骤 1:行选择器

右键单击要抓取的表格中的一个数据行,然后选择检查元素。将从查看上面的绿色表格开始。这将打开 Tor 浏览器的检查器,它将显示附近的几行 HTML 并突出显示你单击的行:

现在将鼠标指针悬停在检查器中相邻的行上,同时注意主浏览器窗口。当移动指针时,页面上的各种元素将被突出显示。在检查器中找到一行 HTML,该行突出显示整个表格行(但不突出显示整个表格)。单击它一次。上面第三个屏幕截图缩略图中红色框指示的内容 (table.classy > tbody > tr.odd) 几乎是你的行选择器。(可能需要单击检查器左箭头检查器右箭头 箭头才能看到全部内容。)1

但是请记住,你需要一个匹配所有表格行的选择器,而不仅仅是你碰巧点击的那一行。如果连续两行仍然得到相同的值,只需将其复制下来,你可能就完成了。否则,可能需要进行一些手动编辑。具体来说,可能需要删除一些将选择范围缩小到特定行行子集而不是仅仅一行#id.class 值。1 这种对选择器进行测试和泛化的强调(例如,从 tr.odd 中移除 .odd 以匹配所有行)是在开发稳健抓取器时教授的一项关键技能。

现在,你可能认为只需右键单击某些内容即可复制此值。最终你将能够做到这一点,因为 Firefox 版本 53 将实现(https://bugzilla.mozilla.org/show_bug.cgi?id=1323700)。不幸的是,目前你必须手动记下它。1

在上面的示例中,检查器中带有红色框的那一行的完整值是:

html > body > div.container.main > div.row > div.span8.blog > table.classy > tbody > tr.odd

但是页面上只有一个 table.classy,所以可以忽略之前的所有内容。这就剩下:

table.classy > tbody > tr.odd

并且第二行以 tr.even 而不是 tr.odd 结尾,所以需要再进行一次调整以获得最终的行选择器:

table.classy > tbody > tr

如果还没有亲自尝试过:

  1. 在上面的绿色表格中右键单击一个数据行
  2. 选择检查元素
  3. 将鼠标指针悬停在检查器中相邻的 HTML 行上,
  4. 找到突出显示整个表格行的那一行并单击它,
  5. 记下检查器顶行的选择器,
  6. 检查器中单击下一个表格数据行,然后
  7. 如果两个选择器相同,则将其写下来。如果不同,请尝试想出一个更通用的选择器,并使用下面的信息进行测试。1

步骤 2:测试你的选择器

可以使用 Tor 浏览器的另一个内置功能来测试选择器。这次,将查看检查器的右侧窗格,如下突出显示。如果检查器只有一个窗口,可以单击其右上角附近的小“展开窗格”()按钮。

现在可以:

  1. 在新窗格中的任何位置右键单击并选择添加新规则。这会添加一块如上面第二个屏幕截图缩略图所示的代码。(突出显示的部分将取决于检查器中当前选择的内容。)
  2. 删除突出显示的内容,粘贴要测试的选择器,然后按 <Enter>
  3. 单击新“规则”右侧几乎看不见的“显示元素”十字准星 (显示元素)。这将使十字准星变为蓝色,并突出显示与选择器匹配的所有页面元素。
  4. 如果此突出显示包含所有想要的内容(并且没有不想要的内容),那么选择器就是好的。否则,可以修改选择器并重试。1

在测试行选择器时,尤其希望所有表格行都被突出显示。1

可以再次单击显示元素 图标以取消突出显示。可以通过单击“折叠窗格”(展开窗格按钮)按钮来关闭右侧检查器窗格。这些新的“规则”是临时的,一旦重新加载页面就会消失。1 这些通过GUI工具(如检查器)进行的可视化辅助,对于指导用户完成操作至关重要,因为仅凭文本描述很难清晰地传达GUI交互。

步骤 3: “下一页”选择器

如果要抓取的表格数据分布在多个页面上,则还必须配置下一页选择器。幸运的是,确定此选择器通常要容易得多。因为只需要选择单个元素,所以通常可以使用 Tor 浏览器检查器中的“复制唯一选择器”选项,如下所示。

为此,只需:

  1. 在包含要抓取的表格的第一个页面上,右键单击下一页链接,
  2. 选择检查元素
  3. 将鼠标指针悬停在检查器中附近的 HTML 行上,直到找到正确的 <a>...</a> 链接
  4. 检查器中右键单击该元素,然后选择复制唯一选择器1

可以直接使用此选择器。如果想确保无误,只需手动单击“下一页”链接,然后在第二页上执行相同的步骤。如果选择器相同,则它们应该适用于包含表格数据的所有页面。1

如果必须修改选择器——或者选择缩短或简化它——可以使用上面步骤 2 中描述的方法来测试替代方案。不用担心最终的选择器会突出显示多个下一页链接,只要它不突出显示其他任何内容即可。下面推荐的 Scrapy 模板只关注第一个“匹配项”。1

尝试按照这些步骤操作上面绿色表格下方的“下一页”链接。Tor 浏览器的复制唯一选择器选项应生成以下内容:

#next_page

(在这种情况下,它等同于 a#next_page)而且,如果测试此选择器,应该会看到单击显示元素十字准星仅突出显示这一个页面元素。1

步骤 4:列选择器

通常需要识别多个列选择器。这样做的过程与找到行选择器的过程几乎相同。主要区别在于:

  • 需要为要抓取的每个数据列提供一个选择器,
  • 选择器应相对于行,因此它们不会以 htmltabletr 等段开头。1

对于绿色表格的第一列,Tor 浏览器的检查器给出:

html > body > div.container.main > div.row > div.span8.blog > table.classy > tbody > tr > td.special > p

如果删除直到并包括行 (tr) 段的所有内容,最终会得到:

td.special > p

如果通过展开检查器、为其添加新的“规则”并单击显示元素十字准星来测试此选择器,如步骤 2中所述,应该会看到第一列中的两个单元格都突出显示。1

如上所述,第二列需要一些技巧,因为它没有 class。但是,如果测试以下选择器,将会看到如何使用 nth-child(n) 技巧来完成任务:

td:nth-child(2) > p

测试列选择器时要记住一点:如上所述,列选择器是相对于其“父”行的。因此,在测试行选择器时,有时可能会看到页面其他位置突出显示的内容。这没关系,只要表格中没有其他内容突出显示即可。(如果对此感到担心,可以将行选择器放在列选择器的前面并以这种方式进行测试。在此示例中,将使用以下内容:

table.classy > tbody > tr td:nth-child(2) > p

只是要确保稍后在实际尝试抓取数据时不要使用这个组合的行加列选择器。)1

步骤 5:选择器后缀

在开始抓取数据之前,还有最后一步。上面讨论的选择器识别 HTML 元素。这对于行选择器来说没问题,但通常希望列选择器提取 HTML 元素的内容。类似地,希望下一页选择器匹配实际链接目标的值(换句话说,只是 /guides/scraping-2 而不是以下内容:

<a href=/guides/scraping-2>下一页</a>

为了实现这一点,向列选择器和下一页选择器添加一个简短的“后缀”。最常见的后缀是:

  • ::text,它提取所选 HTML 标签之间的内容。这里用它来获取实际的表格数据。
  • ::attr(href),它匹配 HTML 标签内部 href 属性的值。这里用它来获取“下一页”的 URL,以便抓取器在完成第一页后可以加载第二页。
  • ::attr(src),它匹配 src 属性的值。这里不使用它,但在抓取包含图像的表格时很有用。1

所以,最终的选择器是:

  • 行选择器table.classy > tbody > tr
  • 下一页选择器#next_page::attr(href)
  • 列选择器
    • 第一列td.special > p::text
    • 第二列td:nth-child(2) > p::text 1

配置 Scrapy

现在对 HTML、CSS 以及如何使用 Tor 浏览器的检查器将它们提炼成少数几个选择器有了基本了解,是时候将这些选择器输入 Scrapy 了。Scrapy 是一个用 Python 编程语言编写的自由开源的 Web 抓取平台。为了使用它,将:

  1. 安装 Scrapy;
  2. 创建一个名为“spider”的小型 python 文件,并通过插入以下内容对其进行配置:
    • 想要抓取的 URL,
    • 行选择器,以及
    • 列选择器;
  3. 告诉 Scrapy 在单个页面上运行 spider;
  4. 检查结果并进行任何必要的更改;以及
  5. 插入下一页选择器并再次运行 spider。1 这种概述的迭代开发周期(配置 -> 在单页上测试 -> 优化 -> 在多页上测试)是一种标准的开发实践,它通过增量测试来最小化错误,使得构建抓取器更为高效和可靠。

步骤 1:安装 Scrapy

可以通过启动终端,输入以下命令并在出现提示时提供密码,在 Tails 上安装 Scrapy:

sudo apt-get install python-scrapy

要在 Tails 上安装软件,需要在启动系统时设置一个管理员密码。如果已在运行 Tails 并且没有这样做,则必须重新启动计算机。可能还想配置“加密持久性”功能,该功能允许在 /home/amnesia/Persistent 文件夹中保存数据。否则,保存的任何内容都将在下次启动 Tails 时消失。1

并非必须配置持久性才能使用 Scrapy,但它使事情变得更容易。如果没有持久性,则必须将“spider”文件保存在外部存储设备上,并且每次想要使用它时都必须重新安装 Scrapy。1

即使启用了持久性,每次重新启动时都必须重新安装 Scrapy,除非将一行 python-scrapy 添加到以下文件中:

/live/persistence/TailsData_unlocked/live-additional-software.conf

为此,可以启动终端,输入以下命令并在出现提示时提供密码:

sudo gedit /live/persistence/TailsData_unlocked/live-additional-software.conf

这将打开 GNU Edit 文本编辑器,授予其修改系统文件的权限,并加载必要配置文件(如果有)的内容。然后在文件中添加上面那一行 (python-scrapy),单击 [保存] 按钮,然后通过单击右上角的 X 退出编辑器。除非之前在运行具有持久性的 Tails 时编辑过此文件,否则首次打开时该文件将为空白。1 针对 Tails 环境提供的详细持久性配置,显示了对目标用户实际需求的深刻理解,因为每次启动都重新安装 Scrapy 会非常不便。

在 Tails 以外的 Debian GNU/Linux 系统上,需要安装 TortorsocksScrapy,可以通过启动终端,输入以下命令并在出现提示时提供密码来完成。

sudo apt-get install tor torsocks python-scrapy

即使在非 Tails 的 Debian 系统上,也包含了 torsocks 的安装,这强调了通过 Tor 路由 Scrapy 流量的重要性,从而在 Tails 环境之外也能保持隐私主题的一致性。

步骤 2:创建和配置你的爬虫文件

使用 Scrapy 的方法有很多种。最简单的是创建一个包含选择器和一些标准 Python 代码的单个爬虫文件。可以从这里复制通用爬虫文件的内容

需要将此代码粘贴到 /home/amnesia/Persistent 文件夹中的一个新文件中,以便可以编辑它并添加选择器。为此,启动终端并输入以下命令:

gedit /home/amnesia/Persistent/spider-template.py

这里粘贴内容,然后单击 [保存] 按钮。1 提供一个“通用爬虫文件”作为模板,极大地降低了 Python 新手的入门门槛,使他们能够专注于修改模板中与特定任务相关的部分,而不是从头开始编写。

现在只需命名爬虫,给它一个开始抓取的页面,然后插入选择器。所有这些都可以通过编辑模板的第 7 行到第 14 行来完成:

    ### 用户变量
    #
    start_urls = ['https://some.website.com/some/page']
    name = 'spider_template'
    row_selector = '.your.row >.selector'
    next_selector = 'a.next_page.selector::attr(href)'
    column_selectors = {
        'some_column': '.contents.of >.some.column::text',
        'some_other_column': '.contents.of > a.different.column::attr(href)',
        'a_third_column': '.contents.of >.a3rd.column::text'
    }

start_urlsnamerow_selectornext_selector 变量非常简单:

  • start_urls:输入包含要抓取的表格数据的第一个页面的 URL。如果可能,请使用 https,并记住在 URL 周围保留方括号 ([ & ])。
  • name:这个实际上不太重要。可以随意命名你的抓取器。
  • row_selector:输入之前确定的行选择器。如果想在上面的绿色表格上测试爬虫,可以使用 table.classy > tbody > tr
  • next_selector:**第一次尝试抓取新表格时,应将此项留空。**为此,请删除两个 ' 字符之间的所有内容。结果行应为 next_selector = '' 1

column_selectors 项有点不同。它是一个集合,其中包含每个列选择器的一个条目。可以为每个条目设置一个(冒号 : 之前的文本)和一个。上面模板中的示例some_columnsome_other_columna_third_column。为这些输入的文本将提供将要创建的 .csv 文件的列标题。示例如下:

'.contents.of >.some.column::text'
'.contents.of > a.different.column::attr(href)'
'.contents.of >.a3rd.column::text'

这些选择器完全是虚构的,几乎可以保证在所有网页上都会失败。当然,应该用在上一节中识别的选择器替换它们。1

如果想在上面的绿色表格上测试爬虫,这些行应该如下所示:

    ### 用户变量
    #
    start_urls = ['https://exposingtheinvisible.org/en/guides/scraping']
    name = 'test-spider'
    row_selector = 'table.classy > tbody > tr'
    next_selector = ''
    column_selectors = {
        'first': 'td.special > p::text',
        'second': 'td:nth-child(2) > p::text'
    }

此文件中的其他所有内容都应保持不变。请记住,正在编辑 Python 代码,因此尽量不要更改格式。标点符号如引号 (' & "), 逗号 (,), 冒号 (:), 花括号 ({ & }) 和方括号 ([ & ]) 在 Python 中都有特殊含义。缩进也是如此:这些行中的大多数前面有四个空格,包含列选择器的行前面有八个空格。此外,以数字符号 (#) 开头的行是“注释”,这意味着它们根本不会影响爬虫。最后,在添加或删除列选择器时,请注意除最后一行外的所有行末尾的逗号 (,),如上所示。1 对 Python 语法的明确警告(如缩进、引号、逗号)对初学者至关重要,因为 Python 对这些细节非常敏感,可以帮助避免许多常见的挫败感。

修改 start_urlsnamerow_selectornext_selector 条目,并为每个列选择器添加后,应通过单击 GNU edit 中的 [保存] 按钮来保存新的爬虫。1

配置完爬虫后,应该对其进行测试。

步骤 3:测试你的爬虫

如果使用的是 Tails,并且没有更改爬虫的位置 (/home/amnesia/Persistent) 或文件名 (spider-template.py),可以通过启动终端并输入以下命令来试运行它:

cd /home/amnesia/Persistent
torsocks -i scrapy runspider spider-template.py -o extracted_data.csv

这些命令包括以下元素:

  • cd /home/amnesia/Persistent 移动到 Tails 主目录中的“Persistence”文件夹,这是放置爬虫的地方
  • torsocks -i 告诉 Scrapy 在抓取时使用 Tor 匿名服务
  • scrapy runspider spider-template.py 告诉 Scrapy 运行你的爬虫
  • -o extracted_data.csv 为将包含抓取数据的输出文件提供名称。可以随意命名此文件,但 Scrapy 将使用末尾的三字母文件扩展名(在本例中为 .csv)来确定应如何格式化这些数据。也可以通过使用 .json 文件扩展名输出来输出(http://json.org/) 内容。1 torsocks -i 命令对于确保 Scrapy 的流量通过 Tor 至关重要,从而在执行阶段保持匿名性,这再次强调了隐私方面的考虑。

当 Scrapy 工作时,它会在运行的终端中显示各种信息。此反馈可能至少包含一条与 torsocks 相关的“ERROR”行:

Unable to resolve. Status reply: 4 (in socks5_recv_resolve_reply() at socks5.c:683)

可以安全地忽略此警告(以及大多数其他反馈)。如果一切正常,将在与爬虫相同的目录中找到一个名为 extracted_data.csv 的文件。该文件应包含从 HTML 表格中抓取的所有数据。示例爬虫将从上面的绿色表格中提取以下内容:

second,first
"Page one, row one, column two","Page one, row one, column one"
"Page one, row two, column two","Page one, row two, column one"

如你所见,结果列可能顺序混乱,但它们将与为列描述符设置的值正确关联,这些键值构成了数据的第一行。一旦将 .csv 文件导入电子表格,就可以轻松地重新排序列。1

故障排除提示:

  • 如果爬虫失败,请查找包含 [scrapy] DEBUG: 的行。它们可能帮助你找出问题所在。
  • 如果想在 Scrapy 仍在运行时退出它,只需在终端应用程序中按住 <Ctrl> 键并按 c
  • 如果指定的输出文件已存在(在本例中为 extracted_data.csv),Scrapy 会将新数据附加到其末尾,而不是替换它。因此,如果事情未按计划进行并且想重试,应首先通过输入 rm extracted_data.csv 删除旧文件。
  • 当 Scrapy 完成后,它将显示以下内容:
[scrapy] INFO: Spider closed (finished)

这些故障排除提示源于实际经验,解决了初学者常遇到的问题(例如 Scrapy 追加数据、需要解释日志消息),表明本指南不仅是理论性的,而且植根于实际应用。

步骤 4:在 LibreOffice Calc 中打开你的 CSV 输出

按照以下步骤确认爬虫是否正常工作(或者,如果已经获得了所需内容,则开始清理和分析数据):

  1. 通过单击屏幕左上角的应用程序菜单,将鼠标悬停在办公子菜单上,然后单击 LibreOffice Calc 来启动 LibreOffice Calc
  2. 在 LibreOffice Calc 中,单击文件并选择打开
  3. 导航到你的 .csv 文件,然后单击 [打开] 按钮
  4. 如果尚未默认设置,请配置以下选项:
    • 字符集:Unicode (UTF-8)
    • 从行:1
    • 分隔符选项下选中“逗号”框
    • 取消选中所有其他分隔符选项
    • 文本分隔符下选择 "
  5. 单击 [确定] 按钮。1 推荐使用 LibreOffice Calc 并指定 UTF-8 编码,这与整个指南中普遍存在的自由开源软件 (FOSS) 理念相一致,并且有助于处理各种字符集,防止常见的数据显示问题。

步骤 5:在多个页面上运行你的爬虫

如果 .csv 文件中的所有内容看起来都正确,并且准备好尝试抓取多个页面,只需在爬虫中配置下一页选择器并再次运行它即可。1 多页抓取是在单页成功之后自然的下一步,展示了如何扩展初始框架以处理更多数据。

如果使用的是具有持久性的 Tails,可以使用与之前相同的命令打开爬虫进行编辑:

gedit /home/amnesia/Persistent/spider-template.py

最初的几行现在应该如下所示:

    ### 用户变量
    #
    start_urls = ['https://exposingtheinvisible.org/en/guides/scraping']
    name = 'test-spider'
    row_selector = 'table.classy > tbody > tr'
    next_selector = '#next_page::attr(href)'
    column_selectors = {
        'first': 'td.special > p::text',
        'second': 'td:nth-child(2) > p::text'
    }

唯一的区别是为 next_selector 变量添加了一个实际的选择器(而不是 '')。1

最后,单击 [保存] 按钮,删除旧的输出文件,并告诉 Scrapy 运行更新后的爬虫:

cd /home/amnesia/Persistent
rm extracted_data.csv
torsocks -i scrapy runspider spider-template.py -o extracted_data.csv

现在,.csv 输出应包含来自第二页的数据:

second,first
"Page one, row one, column two","Page one, row one, column one"
"Page one, row two, column two","Page one, row two, column one"
"Page two, row one, column two","Page one, row one, column one"
"Page two, row two, column two","Page one, row two, column one"

故障排除提示:

  • 如果使用的是 Tails 但未启用持久性,请在关闭 Tails 系统之前将输出文件复制到某处。
  • 如果想在测试新爬虫时保留旧版本的爬虫,只需复制一份并开始使用新版本即可。可以通过在终端中输入以下命令来执行此操作:
cp spider-template.py spider-new.py

当然,之后将使用以下命令(而不是上面显示的命令)来编辑新文件:

gedit /home/amnesia/Persistent/spider-new.py

要运行新的爬虫,将使用以下命令:

torsocks -i scrapy runspider spider-new.py -o extracted_data.csv

cp spider-template.py spider-new.py 这个提示是对代码版本控制概念的一个温和介绍,这对于任何编程任务都是一个好习惯,允许用户在不丢失工作版本的情况下进行实验。

真实世界案例

以下各节介绍了三个多页 HTML 数据表,可以用来练习抓取。这些表格(显然)比上面的示例更长。它们也更复杂一些,因此将指出关键差异以及在配置爬虫时如何解决这些差异。1 这些真实世界的示例弥合了理论学习与实际应用之间的差距,因为实际网站通常会带来独特的挑战。

对于每个网站,都包含以下部分:

  • 此表有何不同;
  • 爬虫的 URL、名称和选择器值;以及
  • 其他自定义设置 1

柏林某社区的难民资源

柏林市发布了各社区难民资源列表。Friedrichshain 和 Kreuzberg 区的列表包含足够多的条目,可用作示例抓取目标。1

[将爬虫代码复制并粘贴到新文件中]

此表有何不同

此表具有三个有趣的特征:

  1. 它有一个长而复杂的起始 URL;
  2. 要抓取的数据包含一个指向网站其他位置页面的内部链接;以及
  3. 要抓取的一个单元格包含额外的 HTML 标记。1

1. 复杂的起始 URL:

用于抓取此表的 URL 对应于搜索表单的结果页面。它是:

http://www.berlin.de/ba-friedrichshain-kreuzberg/aktuelles/fluechtlingshilfe/angebote-im-bezirk/traeger-und-aemter/?q=&sprache=--+Alles+--&q_geo=&ipp=5#searchresults

这不会影响爬虫的配置或运行它的命令,但值得注意的是,通常需要浏览网站——导航到子页面、使用搜索表单、筛选结果等——才能找到正确的起始 URL。1

2. 内部链接:

对应于该行中资源负责组织的表格列 (Träger) 包含一个 Mehr… 链接,指向关于该资源的专用页面。需要完整的 URL,但将要抓取的 HTML 属性仅提供一个相对于网站域的 URL。如果像下面显示的那样,对该列选择器使用 ‘link’: 作为键值,爬虫模板将尝试自动处理此问题。如果在抓取其他某个网站时无法正常工作,可以为该列选择器选择一个不同的键(例如 ‘internal_link’:),然后在将其导入电子表格后自行修复 URL。1 提及爬虫模板可以处理相对 URL(如果键是 ‘link’:),这展示了所提供模板中内置的辅助功能,简化了一些常见任务。

3. 内部 HTML 标记:

同一个 (Träger) 列在某些组织的文本描述内部也包含 HTML 标记。因此,通常使用的选择器后缀 (::text) 无法正常工作。相反,必须提取整个 HTML 块。(注意下面的 organisation 列选择器不包含后缀。)如果是 Python 程序员,可以在爬虫内部轻松解决此问题。否则,将不得不在电子表格应用程序中进行清理。1 “单元格包含额外的 HTML 标记”这个问题强调了现实世界数据的复杂性。指南提供了一个务实的解决方案(提取原始 HTML,稍后清理),而不是为初学者提供过于复杂的爬虫内解析方案。

URL、名称和选择器

**剧透警告。**下面将找到在 spider-template.py 文件中进行的所有更改,以抓取 Friedrichshain 和 Kreuzberg 难民资源的多个页面。但在继续之前,应该在 Tor 浏览器中访问该网页,并在必要时查阅(https://exposingtheinvisible.org/en/guides/scraping/#using-the-tor-browsers-inspector-to-identify-the-selectors-you-need)部分)。然后尝试确定以下内容的选择器:

  • 行选择器
  • 下一页选择器
  • 列选择器:
    • 支持组织
    • 所提供资源的描述
    • 支持的语言
    • 资源的位置
    • 指向更详细描述页面的内部链接 1

爬虫对应的用户变量:

    start_urls = ['http://www.berlin.de/ba-friedrichshain-kreuzberg/aktuelles/fluechtlingshilfe/angebote-im-bezirk/traeger-und-aemter/?q=&sprache=--+Alles+--&q_geo=&ipp=5#searchresults']
    name = 'refugee_resources'
    row_selector = 'tbody tr'
    next_selector = '.pager-item-next > a:nth-child(1)::attr(href)'
    item_selectors = { # 更名为 item_selectors 以匹配原文后续示例,原为 column_selectors
        'organisation': 'td:nth-child(1) > div > p',
        'offer': 'td:nth-child(2)::text',
        'language': 'td:nth-child(3)::text',
        'address': 'td:nth-child(4)::text',
        'link': 'td:nth-child(1) > a:nth-child(2)::attr(href)'
    }

其他自定义设置

要抓取此表,可以使用爬虫模板中默认的 custom_settings 集合,如下所示。如上所述,以 # 开头的行是注释,不会影响爬虫的行为。对于其余两个示例中的每一个,都将取消注释至少一行。

    custom_settings = {
        # 'DOWNLOAD_DELAY': '30',
        # 'DEPTH_LIMIT': '100',
        # 'ITEM_PIPELINES': {
        #     'scrapy.pipelines.files.FilesPipeline': 1,
        #     'scrapy.pipelines.images.ImagesPipeline': 1
        # },
        # 'IMAGES_STORE': 'media',
        # 'IMAGES_THUMBS': { 'small': (50, 50) },
        # 'FILES_STORE': 'files',
        'USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0',
        'TELNETCONSOLE_ENABLED': False,
        'DOWNLOAD_HANDLERS': {'s3': None}
    }

Hacker News

在本节中,将使用 YCombinator 的 Hacker News 作为第二个“真实世界”示例。当然,在现实世界中,不需要抓取 Hacker News,因为该网站同时提供(https://news.ycombinator.com/rss)和应用程序编程接口 (API)。不过,滥用 Hacker News 进行抓取练习算是一种传统,而且它确实是一个不太复杂的多页 HTML 表格的好例子。1

[将爬虫代码复制并粘贴到新文件中]

此表有何不同

如果将抓取范围限制在 Hacker News 上列出的每篇文章的第一行,如此处所做,则此表与之前一直使用的那个小绿色示例非常相似。只是它更大。下面介绍一个新挑战,但它非常简单。1

抓取行属性:

如果使用 Tor 浏览器的检查器查看 Hacker News 文章,会看到包含故事的每个表格行 (<tr>) 都有一个唯一的 id 属性。这样的 ID 通常是顺序的,这对于跟踪内容呈现顺序可能是一种有用的方法。即使在这个特定的表格中它们不是顺序的,抓取它们可能仍然有用。但是大多数列选择器都在表格数据 (<td>) 元素内部,并且通常相对于其父行指定它们的选择器。那么如何捕获行本身的属性呢?只需指定一个仅是后缀的后缀。在这种情况下,如下所示,那将是:::attr(id)。1 这个例子扩展了用户对可提取内容的理解——不仅仅是可见文本,还有嵌入在元素属性中的元数据,即使是在行级别。

URL、名称和选择器

**剧透警告。**下面将找到在 spider-template.py 文件中进行的所有更改,以抓取 Hacker News 上多页文章。但在继续之前,应该在 Tor 浏览器中访问该网站,并在必要时查阅(https://exposingtheinvisible.org/en/guides/scraping/#using-the-tor-browsers-inspector-to-identify-the-selectors-you-need)部分部分)。然后尝试确定以下内容的选择器:

  • 行选择器
  • 下一页选择器
  • 列选择器:
    • 文章索引
    • 文章标题
    • 文章本身的网址 1

爬虫对应的用户变量:

    start_urls = ['https://news.ycombinator.com/news']
    name = 'hacker_news'
    row_selector = 'table.itemlist > tr.athing'
    next_selector = 'a.morelink::attr(href)'
    item_selectors = { # 保持 item_selectors 命名一致性
        "index": "::attr(id)",
        "title": "td.title > a.storylink::text",
        "external_link":  "td.title > a.storylink::attr(href)"
    }

其他自定义设置

Hacker News 的 robots.txt 文件指定了](https://en.wikipedia.org/wiki/Robots_exclusion_standard)指定了) 30 秒的 Crawl-delay,因此应确保爬虫不会抓取过快。因此,抓取所有表格数据可能需要长达十分钟的时间。1 引入 DOWNLOAD_DELAY 以响应 robots.txt 文件中的 Crawl-delay 指令,这是负责任抓取行为的一个重要方面,体现了对网站资源和服务条款的尊重。

    custom_settings = {
        'DOWNLOAD_DELAY': '30',
        # 'DEPTH_LIMIT': '100',
        # 'ITEM_PIPELINES': {
        #     'scrapy.pipelines.files.FilesPipeline': 1,
        #     'scrapy.pipelines.images.ImagesPipeline': 1
        # },
        # 'IMAGES_STORE': 'media',
        # 'IMAGES_THUMBS': { 'small': (50, 50) },
        # 'FILES_STORE': 'files',
        'USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0',
        'TELNETCONSOLE_ENABLED': False,
        'DOWNLOAD_HANDLERS': {'s3': None}
    }

Bremen的CCTV摄像头

德国城市不来梅提供了一个公共摄像头的列表,以及每个摄像头所能看到的缩略图。1

[将爬虫代码复制并粘贴到新文件中]

此表有何不同

不来梅的CCTV表格有三个主要特点:

  1. 页面结构使得识别可靠的下一页选择器异常困难,
  2. 为了解决下一页选择器的挑战,必须给爬虫设置一个抓取的最大页数,以及
  3. 希望下载与每个CCTV摄像头相关的实际图像文件。1

1. 难以捉摸的下一页选择器:

用于设置“下一个箭头”样式的 CSS 类仅应用于图标,而不是链接本身,因此不能将其用于下一页选择器。更糟糕的是,页面导航链接行仅在离开第一页后才显示“第一页”和“上一页”链接,因此通常的 :nth-child(n) 技巧不起作用。因此,必须发挥创造力才能想出一个在每个页面上都有效的选择器。在下面的示例中,使用了一个不同的技巧 (nth-last-child(n)),这样就可以从末尾而不是从开头计数。1

2. 指定“深度限制”:

当到达末尾时,“最后一页”和“下一页”链接会消失,这通常会导致抓取器“点击”一个它已经抓取过的页面的链接。然后它会返回几页。直到它(再次)到达末尾,此时它会(再次)返回几页。这将创建一个无限循环,可怜的爬虫最终会永远抓取下去。通过在爬虫的 custom_settings 中将 DEPTH_LIMIT 设置为 11,可以告诉它在到达最后一页后停止。1 nth-last-child(n) 和 DEPTH_LIMIT 的解决方案展示了更高级的 CSS 选择器技术和爬虫控制机制,说明了如何处理棘手的网站设计,为用户应对更具挑战性的实际网站做好准备。

3. 下载图像文件:

这是第一次要求爬虫下载图像文件。Scrapy 使这变得相当容易,但它确实需要:

  • 对相应的列选择器使用特殊的 image_urls ,以及
  • 通过删除相应行开头的 # 字符来取消注释一些 custom_settings1 下载图像的能力显著扩展了抓取器的用途,使其不仅仅局限于文本数据。

URL、名称和选择器

**剧透警告。**下面将找到在 spider-template.py 文件中进行的所有更改,以抓取多个页面的摄像头位置和图像缩略图。但在继续之前,应该在 Tor 浏览器中访问该网站,并在必要时查阅(https://exposingtheinvisible.org/en/guides/scraping/#using-the-tor-browsers-inspector-to-identify-the-selectors-you-need)部分部分)。然后尝试确定以下内容的选择器:

  • 行选择器
  • 下一页选择器
  • 列选择器:
    • 摄像头名称
    • 摄像头状态
    • 摄像头位置
    • 摄像头当前缩略图的 URL 1

爬虫对应的用户变量:

    start_urls = ['http://www.standorte-videoueberwachung.bremen.de/sixcms/detail.php?gsid=bremen02.c.734.de']
    name = 'bremen_cctv'
    row_selector = 'div.cameras_list_item'
    next_selector = 'ul.pagination:nth-child(4) > li:nth-last-child(2) > a::attr(href)'
    item_selectors = { # 保持 item_selectors 命名一致性
        'title': '.cameras_title::text',
        'status': '.cameras_title.cameras_status_text::text',
        'address': '.cameras_address::text',
        'image_urls': '.cameras_thumbnail > img::attr(src)'
    }

其他自定义设置

为了解决此表有何不同部分中描述的问题,将使用以下自定义设置。

    custom_settings = {
        # 'DOWNLOAD_DELAY': '30',
        'DEPTH_LIMIT': '11',
        'ITEM_PIPELINES': {
        #   'scrapy.pipelines.files.FilesPipeline': 1,
            'scrapy.pipelines.images.ImagesPipeline': 1
        },
        'IMAGES_STORE': 'media',
        'IMAGES_THUMBS': { 'small': (50, 50) },
        # 'FILES_STORE': 'files',
        'USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0',
        'TELNETCONSOLE_ENABLED': False,
        'DOWNLOAD_HANDLERS': {'s3': None}
    }

上面的 DEPTH_LIMIT 设置确保在到达最后一页时停止抓取。ITEM_PIPELINES 集合中未注释的项告诉 Scrapy 下载并保存由 image_urls 列选择器识别的所有图像。IMAGES_STORE 告诉它将这些图像文件放入一个名为 media 的文件夹中,它会自动创建该文件夹。IMAGES_THUMBS 告诉它为每个图像创建一个非常小的缩略图。

scrapy.pipelines.files.FilesPipelineFILES_STORE 和特殊的 file_urls 列选择器可用于从网页下载其他类型的文件。这可能包括 PDF、Microsoft Word 文档、音频文件等。下面将禁用这些选项。)

运行爬虫后,查看 .csv 输出并浏览 media 文件夹,以确切了解其工作原理。

一旦理解了使这三个 Scrapy 爬虫完成其工作所需的配置更改,就应该能够安全且私密地从 Web 上的大多数 HTML 表格中抓取结构化数据、图像和文件。与往常一样,还有更多工作要做。仍然需要清理、分析、呈现和解释抓取的数据,但希望上述信息能在下次偶然发现一个重要表格数据宝库而旁边没有“下载为 CSV”链接时,为你提供一个起点。 结论部分重申了读者通过本指南所获得的能力,强调了学习投入的价值。


© 版权声明
THE END
喜欢就支持一下吧
点赞1赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容