返回博客
指南
Raluca PenciucLast updated on Mar 31, 20262 min read

Ruby 网页抓取:终极教程

Ruby 网页抓取:终极教程

咱们别拐弯抹角了,随着时间的推移,互联网的数据量只会持续增长。这种局面已非任何人所能掌控,但这真的是一件坏事吗?

特别是在过去的十年里,网络爬虫技术已变得极为流行。要在当今的商业世界中取得成功,企业需要制定恰当的策略,而这要求在短时间内获取大量信息。此外,这对开发者来说,既能提升编程技能,又能为公司做出贡献,可谓一举两得。

如果你是 Ruby 阵营的一员,却对网络爬虫知之甚少,本文将为你开辟一个全新的探索领域:构建你自己的网络爬虫。

理解网页抓取

让我们以价格比价平台为例。其职责是从多家在线零售商处获取各类商品的价格。但为何仅限于实物商品?得益于比价网站,航空和酒店业也变得更加消费者友好。那么,这些神奇的网站或应用是如何运作的?当然是通过网络爬虫!

您此刻可能在想:“这些数据还能有什么其他用途?”让我们来看看网络爬虫的一些实际应用:

这篇关于网络爬虫的精彩文章提供了详细的说明和更多应用案例。

即使您理解了网络爬虫的工作原理及其潜在优势,要开发出一个爬虫也并非易事。网站有许多方法可以识别并阻止机器人访问其数据。

例如:

  • 地理位置屏蔽:当您查询其他地区的资讯(例如机票价格)时,可能会看到针对特定地区的搜索结果。
  • IP封锁:当网站检测到您从特定IP地址频繁发起请求时,可能会封锁您的访问或限制访问速度;
  • 蜜罐:人类无法看到蜜罐链接,但机器人可以;一旦机器人中计,其IP地址就会被封锁;
  • 验证码(CAPTCHA):人类能相对快速地解决这些简单的逻辑问题,但爬虫往往难以应对;

要克服所有这些障碍绝非易事。构建一个简单的机器人并不难,但创建一个优秀的网页抓取工具则要困难得多。因此,在过去的十年里,用于网页抓取的API已成为最热门的话题之一。

使用 WebScrapingAPI 可以收集任何网站的 HTML 内容,并且我们之前提到的所有问题都将自动得到解决。此外,我们使用亚马逊网络服务(AWS)来确保速度和可扩展性。听起来很有意思,对吧?别光听听而已!利用 WebScrapingAPI 免费试用版提供的 5000 次免费 API 调用,亲自试一试吧。

理解网络

要理解网络,必须先了解超文本传输协议(HTTP)。该协议阐明了服务器与客户端之间的通信方式。一条消息包含描述客户端及其数据处理方式的信息:方法、HTTP版本和头部。

对于 HTTP 请求,网页爬虫通常使用 GET 方法从服务器获取数据。此外,还有一些高级方法,如 POST 和 PUT。此处详细介绍了 HTTP 方法,供您参考。

在 HTTP 头部中,可以找到关于请求和响应的各种附加信息。对于网页抓取而言,以下这些头部尤为重要:

  • User-Agent:网络爬虫依赖此标头使请求看起来更真实;它包含应用程序、操作系统、软件及版本等信息。
  • Cookie:服务器与请求方可通过该字段交换机密信息(如认证令牌)。
  • Referrer:包含用户访问的来源网站;因此,必须考虑这一因素。
  • Host:用于标识您正在连接的主机。
  • Accept:向服务器提供响应类型(例如 text/plain、application/json)。

了解 Ruby

Ruby 是一种高级的多范式编程语言,同时也是一种完全可解释的语言。这意味着程序代码以纯文本形式存储,并传输给解释器进行执行。

1995年,松本行弘(在Ruby社区中也被称为Matz)融合了Perl、Lisp和Smalltalk等不同编程语言的特性,创建了一种专注于简单性和生产力的新语言。

这是一种小众编程语言,其天然应用领域是 Web 应用程序。在您的项目中使用该语言,您将获得以下显著优势:

  • 它能快速见效。结合 Rails 框架,您可以相对快速地开发软件;正因如此,初创公司通常更倾向于使用 Ruby 来迅速构建他们的 MVP(最小可行产品)。
  • 它由不断壮大的 Ruby 社区精心开发并维护。
  • 丰富的实用工具和库(称为 gems)确保您几乎在任何情况下都能轻松遵循最佳编码规范。

另一方面,这些优势并不能使 Ruby 成为适用于所有新软件的万能解决方案。在做出决定前,您还应考虑该语言的以下特性:

  • 随着规模扩大,基于 Ruby 构建的应用程序运行速度会变慢,这会导致可扩展性问题。
  • 其天然适用领域是 Web 应用程序。因此,它并不适合桌面/移动应用程序
  • 由于采用解释器机制,面向对象的代码运行速度可能较慢

制作自己的网页爬虫

现在我们可以开始讨论数据提取了。首先,我们需要一个提供有价值信息的网站。

步骤 1:搭建环境

要构建我们的 Ruby 网页爬虫,首先需要确保具备所有必要条件:

  • Ruby 的最新稳定版本:请查阅其官方安装指南,选择适合您操作系统的最佳安装方式。
  • 集成开发环境(IDE):本指南将使用 Visual Studio Code,因其轻量且无需额外配置,但您也可以选择自己喜欢的任何 IDE。
  • Bundler:一款 Ruby 依赖管理工具(也称为 gem);
  • Watir:一款基于 Selenium 的 gem,用于自动化测试,可模拟用户在浏览器上的操作;
  • Webdrivers:由 Watir 推荐的 gem,可自动为浏览器实例下载最新驱动程序;
  • Nokogiri:一款以简化网页分析而闻名的 gem。它能解析 HTML、XML,检测损坏的 HTML 文档,并支持通过 XPath 和 CSS3 选择器访问元素。

配置好 Ruby 环境后,在电脑任意位置创建一个新目录,并使用您喜欢的 IDE 打开它。然后在终端窗口中运行以下命令来安装我们的第一个 gem:

> gem install bundler

现在在项目根目录下创建一个名为 Gemfile 的文件。我们将在此添加其余 gem 作为依赖项:

source 'https://rubygems.org'

gem 'watir', '~> 6.19', '>= 6.19.1'
gem 'webdrivers', '~> 4.6'
gem 'nokogiri', '~> 1.11', '>= 1.11.7'

现在回到终端窗口,运行以下命令安装我们声明的 gems:

> bundle install

配置完成!最后,只需创建一个名为“scraper.rb”的文件来存放我们的网页抓取代码。无论我们在此编写什么内容,都可以通过以下命令执行:

> ruby scraper.rb

步骤 2:检查要抓取的页面

太棒了,继续吧!访问您想要抓取的页面,在页面任意位置右键点击,然后选择“检查元素”。开发者控制台将弹出,您应该能看到该网站的 HTML 代码。

步骤 3:发送 HTTP 请求并抓取 HTML

现在,为了将该 HTML 获取到本地机器上,我们需要使用 Watir 发送一个 HTTP 请求来获取文档。让我们回到 IDE 中,将这个想法转化为代码。

首先,编写我们需要的导入语句:

require 'watir'
require 'webdrivers'
require 'nokogiri'

接着初始化一个浏览器实例,并导航至要抓取的网站。随后获取 HTML 内容并将其传递给 Nokogiri 构造函数,该函数将帮助我们解析结果。

browser = Watir::Browser.new
browser.goto 'https://blog.eatthismuch.com/latest-articles/'
parsed_page = Nokogiri::HTML(browser.html)

File.open("parsed.txt", "w") { |f| f.write "#{parsed_page}" }

browser.close

我们还将结果写入名为“parsed.txt”的文本文件中以便查看 HTML。收到响应后务必关闭连接,因为进程会继续运行。

步骤 4:提取特定部分

现在我们已获得 HTML 文档,但我们需要的是数据,这意味着应将之前的响应解析为人类可读的信息。

让我们从小处着手,先提取网站的标题。Ruby 有一个显著特点:除极少数例外,一切皆为对象,这意味着即使是简单的字符串也能拥有属性和方法。

因此,我们只需通过 parsed_page 对象的属性即可直接获取网站标题的值。

puts parsed_page.title

接下来,让我们从网站中提取所有链接。为此,我们将使用一种更通用的方法来解析特定标签,即 `css` 方法。

links = parsed_page.css('a')
links.map {|element| element["href"]}

puts links

我们还使用 map 方法,仅保留 HTML 中带有 href 属性的链接。

让我们来看一个更贴近实际的例子。我们需要从博客中提取文章、其标题、地址和元描述。

如果你检查其中一张文章卡片,会发现可以通过链接的属性获取地址和文章标题。此外,元描述位于一个具有特定类名的 <div> 标签内。

当然,实现这一搜索的方法有很多。我们将采用的方法是:先查找所有具有 td_module_10 类名的 <div> 标签,然后遍历每个标签,从中提取 <a> 标签以及内部具有 td-excerpt 类名的 标签

article_cards = parsed_page.xpath("//div[contains(@class, 'td_module_10')]")

article_cards.each do |card|
    title = card.xpath("div[@class='td-module-thumb']/a/@title")
    link = card.xpath("div[@class='td-module-thumb']/a/@href")
    meta = card.xpath("div[@class='item-details']/div[@class='td-excerpt']")
end

没错,正如您可能已经猜到的,XPath表达式正是实现这一目标的关键,因为我们需要根据类名及其父元素来查找HTML元素。

步骤 5:将数据导出为 CSV

当数据需要传递给另一个应用程序(在本例中是文章聚合器)时,这种提取方式会非常有用。因此,我们需要将解析后的数据导出到外部文件中。

我们将创建一个 CSV 文件,因为它既能被其他应用程序轻松读取,也能通过 Excel 打开以进行进一步处理。首先,再进行一次导入:

require 'csv'

然后我们将以“追加”模式创建 CSV 文件,并将之前的代码封装起来,这样我们的爬虫代码现在看起来像这样:

CSV.open("articles.csv", "a+") do |csv|
    csv << ["title", "link", "meta"]

    article_cards = parsed_page.xpath("//div[contains(@class, 'td_module_10')]")
    article_cards.each do |card|

        title = card.xpath("div[@class='td-module-thumb']/a/@title")
        link = card.xpath("div[@class='td-module-thumb']/a/@href")
        meta = card.xpath("div[@class='item-details']/div[@class='td-excerpt']")

        csv << [title.first.value, link.first.value, meta.first.text.strip]
    end
end

太棒了,就这样!现在我们可以以一种整洁、直观且便于转发的形式查看所有解析后的数据。

总结与替代方案

至此,本教程已全部完成。恭喜!希望本文能为你提供大量关于网页抓取的信息,并帮助你更好地理解这一技术。

显然,这项技术不仅能驱动文章聚合器,还能做更多事情。关键在于找到正确的数据并进行分析,从而发掘新的可能性。

不过,正如我在文章开头所言,网络爬虫面临着诸多挑战。除了推动业务发展外,对于开发者而言,利用自建的网络爬虫解决问题也是一次绝佳的学习机会。尽管如此,如果您需要完成某个项目,可能仍希望节省成本(时间、金钱、人力)。

专为解决这些难题而设计的API始终更易于使用。即使面临JavaScript渲染、代理服务器、验证码(CAPTCHA)及其他阻碍因素,WebScrapingAPI也能克服所有障碍,并提供可定制的体验。如果您仍存疑虑,何不尝试一下免费试用?

关于作者
Raluca Penciuc, 全栈开发工程师 @ WebScrapingAPI
Raluca Penciuc全栈开发工程师

Raluca Penciuc 是 WebScrapingAPI 的全栈开发工程师,主要负责开发爬虫、优化规避机制,并探索可靠的方法以降低在目标网站上的被检测概率。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。