使用 C++ 进行网络抓取的终极指南
Raluca Penciuc,2021 年 7 月 5 日
200 万年前,一群穴居人发现棍子上的石头可能很有用。事情从那时起开始变得一发不可收拾。现在,我们的问题不再是躲避剑齿虎,而是队友给他们的队员起名叫 "did sutff"。
虽然困难已经改变,但我们对创造工具克服困难的痴迷却没有改变。网络刮擦工具就是最好的证明。它们是为解决数字问题而设计的数字工具。
今天,我们将从头开始制作一个新工具,但我们使用的不是石头和木棍,而是 C++,这可以说是难上加难。所以,请继续关注我们,学习如何制作 C++ 网络刮刀以及如何使用它!
了解网络搜索
无论选择哪种编程语言,都需要了解网络刮擦工具的工作原理。这些知识对于编写脚本和最终拥有一个实用的工具至关重要。
网络搜索的好处
不难想象,一个机器人为你完成所有的研究工作比手工复制信息要好得多。如果你需要大量数据,那么它的优势就会成倍增长。例如,如果你正在训练一种机器学习算法,网络搜索器就能帮你省下几个月的时间。

为了清楚起见,让我们来介绍一下网络刮擦器能帮助你的每一种方式:
- 减少繁琐的工作时间--这是最明显的优势。抓取程序提取数据的速度与浏览器加载页面的速度相当。给机器人一个 URL 列表,你就能立即获得它们的内容。
- 获得更高的数据准确性--人为操作不可避免地会导致人为错误。相比之下,机器人将始终准确地获取所有信息,并根据您的指示进行解析。
- 保持有序的数据库--当你收集数据时,跟踪所有数据会变得越来越难。搜刮工具不仅能获取内容,还能以任何格式存储这些内容,让您的工作更轻松。
- 使用最新信息 --在许多情况下,数据每天都在变化。举个例子,看看股票市场或在线商店列表就知道了。只需几行代码,您的机器人就能以固定的时间间隔抓取相同的页面,并用最新信息更新您的数据库。
WebScrapingAPI 的存在就是为了给你带来所有这些好处,同时还能绕过刮擦人员在网络上经常遇到的各种障碍。所有这些听起来都很棒,但它们如何转化为实际项目呢?
网络搜刮使用案例
使用网络搜刮工具的方法多种多样。天马行空!不过,有些使用情况还是比其他使用情况更常见。

让我们来详细了解每种情况:
- 搜索引擎优化- 通过搜索结果页面中的关键字,可以方便快捷地确定您需要在排名上超越谁,以及什么样的内容可以帮助您实现这一目标。
- 市场调研--在了解了竞争对手的搜索情况后,你可以进一步分析他们的整体数字表现。使用网络搜索器查看他们如何使用 PPC、描述他们的产品、使用何种定价模式等等。基本上,任何公开信息都唾手可得。
- 品牌保护- 外面的人都在谈论你的品牌。理想情况下,这都是好事,但这并不能保证。机器人可以很好地浏览评论网站和社交媒体平台,只要有人提到您的品牌,它就会向您报告。无论他们在说什么,您都可以随时代表您的品牌利益。
- 潜在客户生成--在互联网上为您的销售团队和可能的客户之间架起桥梁绝非易事。使用网络搜索机器人在黄页或 Linkedin 等在线商业注册表中收集联系信息后,这就变得容易多了。
- 内容营销--毫无疑问,创建高质量的内容需要大量的工作。你不仅要找到可靠的信息来源和丰富的信息,还要了解受众喜欢什么样的语气和方式。幸运的是,如果有机器人帮你完成这些繁重的工作,这些步骤就变得微不足道了。
其他例子还有很多。当然,您也可以开发一种全新的方式,将数据提取用于您的优势。我们始终鼓励创造性地使用我们的 API。
网络搜索的挑战
虽然网络刮擦工具很有价值,但它并不都是阳光和彩虹。有些网站不喜欢机器人访问。要避免给被访问网站造成严重压力,并不难对你的刮擦程序进行编程,但它们对机器人的警惕性是值得肯定的。毕竟,网站可能无法区分有礼貌的机器人和恶意机器人。
因此,铲运机在外出时会遇到一些挑战。

最棘手的障碍是
- IP 阻止- 有几种方法可以确定访客是人类还是机器。不过,在确定是机器人后,采取的行动要简单得多,那就是阻止 IP。虽然如果采取必要的预防措施,这种情况并不会经常发生,但最好还是准备一个代理池,这样即使一个 IP 被封禁,也能继续提取数据。
- 浏览器指纹识别--您向网站发送的每个请求都会泄露您的部分信息。IP 是最常见的例子,但请求头也会告诉网站你的操作系统、浏览器和其他小细节。如果网站利用这些信息来识别发送请求的人,并发现你的浏览速度比正常人快,那么你就会立即被屏蔽。
- Javascript 渲染--大多数现代网站都是动态的。也就是说,它们使用 javascript 代码为用户定制页面,提供更贴身的体验。问题是,简单的机器人由于无法执行这些代码而被卡住。结果就是:刮擦器获取的是 javascript 而不是包含相关信息的 HTML。
- 验证码- 当网站无法确定访客是人类还是机器人时,就会将他们重定向到验证码页面。对我们来说,这充其量只是一个轻微的烦恼,但对机器人来说,这通常是一个完全的停止;除非它们包含验证码解决脚本。
- 请求节流 - 防止访问者压垮网站服务器的最简单方法就是限制单个 IP 在固定时间内可发送的请求数量。达到这个数量后,请求者可能不得不等待计时器,或者不得不解决验证码问题。无论如何,这都不利于你的数据提取项目。
了解网络
如果你要构建一个网络搜刮器,你应该了解互联网工作原理的一些关键概念。毕竟,你的机器人不仅要使用互联网收集数据,还要与其他数十亿用户打成一片。
我们喜欢把网站想象成一本书,一页页地阅读只意味着翻到正确的页码并查看。实际上,这更像是你和书之间的电报。你申请一个页面,它就会发送给你。然后你再订购下一页,同样的事情也会发生。
所有这些来来回回的操作都是通过 HTTP(超文本传输协议)进行的。为了让访客看到页面,浏览器会发送 HTTP 请求,并从服务器接收 HTTP 响应。您想要的内容将包含在该响应中。
HTTP 请求由四个部分组成:
- URL(统一资源定位器)是发送请求的地址。它指向一个唯一的资源,可以是整个网页,也可以是单个文件,或介于两者之间的任何东西。
- 方法(Method)传达了您想要采取的操作类型。最常用的方法是 GET,即从服务器检索数据。下面列出了最常用的方法。
- 标头是一些元数据,用于描述您的请求。例如,如果您必须提供密码或凭证才能访问数据,它们就会出现在特殊的标头中。如果您希望接收 JSON 格式的数据,您可以在标头中提及。User-Agent是网络搜刮中最著名的标头之一,因为网站使用它来对访问者进行指纹识别。
- Body是请求中存储数据的通用部分。如果获取的是内容,这里可能是空的。另一方面,如果要向服务器发送信息,则可以在这里找到。
发送请求后,即使请求未收到任何数据,也会收到响应。其结构如下
- 状态代码是一个三位数代码,可以让你一目了然地知道发生了什么。简而言之,以 "2 "开头的代码通常表示成功,以 "4 "开头的代码表示失败。
- 标头的功能与同类标头相同。例如,如果您收到一种特定类型的文件,标头会告诉您文件的格式。
- 正文也存在。如果您使用 GET 请求内容并成功,您将在这里找到数据。
REST API 使用 HTTP 协议,就像网络浏览器一样。因此,如果你认为 C++ 网络刮擦程序太费事,那么如果你选择使用 WebScrapingAPI,这些信息也会对你有所帮助,因为 WebScrapingAPI 已经可以处理所有数据提取难题。
了解 C++
就编程语言而言,没有比 C 和 C++ 更老派的了。这种语言出现于 1985 年,是 "带类的 C 语言 "的完善版本。
虽然 C++ 被用于通用编程,但它并不是人们考虑用于网络搜刮程序的首选语言。它有一些缺点,但也不是没有优点。让我们来探讨一下,好吗?
C++ 是面向对象的,这意味着它使用类、数据抽象和继承来使你的代码更容易重用和重新用于不同的需要。由于数据被视为一个对象,因此您可以更轻松地存储和解析数据。
很多开发人员至少懂一点 C++。即使你在大学里没有学过 C++,你(或你的队友)也可能懂一点 C++。这一点在整个软件开发社区都得到了体现,因此您不难获得关于代码的第二意见。
C++ 具有高度可扩展性。如果你从一个小项目开始,然后决定使用网络搜索,那么大部分代码都可以重复使用。只需在这里和那里稍作调整,您就可以使用更大的数据量了。
另一方面,C++ 是一种静态编程语言。虽然这能确保更好的数据完整性,但在处理互联网问题时,它不如动态语言有用。
此外,C++ 并不适合构建爬虫。如果你只需要一个刮板,这可能不是问题。但如果要添加一个爬虫来生成 URL 列表,C++ 就不是一个好的选择了。
好了,我们谈了很多重要的事情,但现在让我们进入文章的正题--用 C++ 编写网络搜刮程序。
用 C++ 制作网络搜索器
先决条件
- C++ IDE。在本指南中,我们将使用Visual Studio。
- vcpkg是由 Windows 创建并支持的 C/C++ 软件包管理器。
- cpr是一个用于 HTTP 请求的 C/C++ 库,是经典cURL的封装程序,灵感来自Python 请求库。
- gumbo是一个完全用 C 编写的 HTML 解析器,它为包括 C++ 在内的多种编程语言提供了封装。
设置环境
1.下载并安装 Visual Studio 后,使用控制台应用程序模板创建一个简单的项目。

2. 现在,我们将配置软件包管理器。Vcpkg 提供了一个精心编写的教程,可以让你尽快上手。
注意:安装完成后,最好设置一个环境变量,这样就可以从计算机上的任何位置运行 vcpkg。
3.现在该安装我们需要的库了。如果设置了环境变量,则打开任意终端,运行以下命令:
> vcpkg install cpr
> vcpkg install gumbo
> vcpkg integrate install
如果没有设置环境变量,只需导航到安装vcpkg 的文件夹,打开终端窗口并运行相同的命令即可。
前两个命令会安装构建刮板所需的软件包,第三个命令会帮助我们轻松地将这些库集成到项目中。
选择一个网站并检查 HTML
现在我们已经准备就绪!在构建网络搜刮器之前,我们需要选择一个网站并检查其 HTML 代码。
我们访问了维基百科,并从 "你知道吗...... "部分随机选取了一个页面。因此,今天的刮擦页面将是维基百科中关于罂粟种子防御的文章,我们将提取其中的一些成分。首先,让我们来看看页面结构。右键点击文章的任意位置,然后点击 "检查元素",就可以了!这就是我们的 HTML。

提取标题
现在,我们可以开始编写代码了。为了提取信息,我们必须在本地下载 HTML。首先,导入我们刚刚下载的库:
#include <iostream>
#include <fstream>
#include "cpr/cpr.h"
#include "gumbo.h"
然后,我们向目标网站发出 HTTP 请求,检索 HTML。
std::string extract_html_page()
{
cpr::Url url = cpr::Url{"https://en.wikipedia.org/wiki/Poppy_seed_defence"};
cpr::Response response = cpr::Get(url);
return response.text;
}
int main()
{
std::string page_content = extract_html_page();
}
现在,page_content变量保存了文章的 HTML内容,我们将进一步使用它来提取我们需要的数据。这就是 gumbo 库的用武之地。
我们使用gumbo_parse方法将之前的page_content字符串转换为 HTML 树,然后调用我们为根节点实现的函数search_for_title。
int main()
{
std::string page_content = extract_html_page();
GumboOutput* parsed_response = gumbo_parse(page_content.c_str());
search_for_title(parsed_response->root);
// free the allocated memory
gumbo_destroy_output(&kGumboDefaultOptions, parsed_response);
}
The called function will traverse the HTML tree in-depth to look for the <h1> tag by making recursive calls. When it finds the title, it’s displaying it in the console and will exit the execution.
void search_for_title(GumboNode* node)
{
if (node->type != GUMBO_NODE_ELEMENT)
return;
if (node->v.element.tag == GUMBO_TAG_H1)
{
GumboNode* title_text = static_cast<GumboNode*>(node->v.element.children.data[0]);
std::cout << title_text->v.text.text << "\n";
return;
}
GumboVector* children = &node->v.element.children;
for (unsigned int i = 0; i < children->length; i++)
search_for_title(static_cast<GumboNode*>(children->data[i]));
}
提取链接
同样的主要原则也适用于其他标签,即遍历树并获取我们感兴趣的内容。让我们获取所有链接并提取其 href 属性。
void search_for_links(GumboNode* node)
{
if (node->type != GUMBO_NODE_ELEMENT)
return;
if (node->v.element.tag == GUMBO_TAG_A)
{
GumboAttribute* href = gumbo_get_attribute(&node->v.element.attributes, "href");
if (href)
std::cout << href->value << "\n";
}
GumboVector* children = &node->v.element.children;
for (unsigned int i = 0; i < children->length; i++)
{
search_for_links(static_cast<GumboNode*>(children->data[i]));
}
}
看到了吗?除了我们要找的标签,代码几乎一样。gumbo_get_attribute 方法可以提取我们命名的任何属性。因此,你可以用它来查找类、ID 等。
在显示属性值之前,必须对其进行空检查。在高级编程语言中,这是不必要的,因为它只会显示一个空字符串,但在 C++ 中,程序会崩溃。
写入 CSV 文件
有很多链接,都混杂在内容中。这篇文章也很短。因此,让我们把它们都保存到外部,看看如何区分它们。
首先,我们创建并打开一个 CSV 文件。我们在函数外部,就在导入附近进行这项工作。我们的函数是递归的,这意味着如果每次调用都创建一个新文件,我们就会有很多文件。
std::ofstream writeCsv("links.csv");
然后,在我们的主函数中,我们在第一次调用函数之前写入 CSV 文件的第一行。执行完成后,不要忘记关闭文件。
writeCsv << "type,link" << "\n";
search_for_links(parsed_response->root);
writeCsv.close();
Now, we write its content. In our search_for_links function, when we find a <a> tag, instead of displaying in the console now we do this:
if (node->v.element.tag == GUMBO_TAG_A)
{
GumboAttribute* href = gumbo_get_attribute(&node->v.element.attributes, "href");
if (href)
{
std::string link = href->value;
if (link.rfind("/wiki") == 0)
writeCsv << "article," << link << "\n";
else if (link.rfind("#cite") == 0)
writeCsv << "cite," << link << "\n";
else
writeCsv << "other," << link << "\n";
}
}
我们用这段代码获取 href 属性值,并将其归入 3 个类别:文章、引用和其他。

当然,您还可以更进一步,定义自己的链接类型,例如那些看起来像文章但实际上是文件的链接。
网络搜刮替代方案
现在你知道如何用 C++ 制作自己的网络刮刀了吧。不错吧?
尽管如此,您可能还是会对自己说:"这样做太麻烦了!"我们完全理解您的想法。实话实说,编写刮板程序是一次极好的学习经历,而且这些程序适用于小型数据集,但也仅此而已。
如果你需要一个快速、可靠、可扩展的数据提取工具,Web scraping API 是你的最佳选择。这是因为它具备你所需要的所有功能,如旋转代理池、Javascript 渲染、验证码求解器、地理位置选项等。
不信?那您就亲自体验一下吧!开始免费试用 WebScrapingAPI,看看网络刮削是多么容易使用!
新闻和更新
订阅我们的时事通讯,了解最新的网络搜索指南和新闻。
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.
