在前端开发中,经常需要从互联网上获取数据。常用的方法是通过 HTTP 调用 API,收到服务器发回来的数据后进行处理并显示在页面上。然而,在某些情况下,API 并不能满足前端工程师的需求,比如:API 返回数据不完整、API 访问速度慢等等。这时,就需要使用爬虫技术了。
本文将介绍如何使用 Node.js 爬虫技术来抓取网页数据,并使用 cheerio 这个 Node.js 模块来处理 HTML 文档。我们将从以下方面来讲解:
- 爬虫原理
- 使用 Node.js 发送 HTTP 请求
- 使用 cheerio 处理 HTML 文档
爬虫原理
爬虫是指通过程序自动访问和抓取互联网上的信息。其基本原理是从指定的网页 URL 开始,利用 HTTP 请求模拟浏览器发送请求,获取网页源码,然后对源码按需求进行解析和处理。
对于前端工程师而言,爬虫的作用是获取那些无法通过 API 接口获取到的数据,比如爬取京东的价格、抓取虎扑体育的赛事信息。在使用爬虫之前,需要向网站所有者索取正式的 API 接口,并在遵守遵守伦理和法律的基础上进行爬虫操作。
使用 Node.js 发送 HTTP 请求
Node.js 提供了 http 和 https 模块来发送 HTTP/HTTPS 请求。最常用的是 http.request() 方法,该方法接受一个 URL 字符串作为参数,返回一个 http.ClientRequest 类的实例,该实例用于向服务器发送请求,并提供了一些有用的方法和事件来操作和处理请求。
以下是使用 Node.js 发送 HTTP 请求的示例:
// www.javascriptcn.com code example
const http = require("http");
const options = {
hostname: "www.example.com",
method: "GET"
};
// 返回一个 ClientRequest 对象
const req = http.request(options, (res) => {
let data = "";
res.on("data", (chunk) => { // 当有数据到来时,执行该回调函数
data += chunk;
});
res.on("end", () => { // 数据加载结束,执行该回调函数
console.log(data);
});
});
// 发送请求
req.end();在以上示例中,我们发送了一个 GET 请求到 www.example.com 网站,当服务器返回数据时,数据会被存入 data 变量中,并在请求结束后,打印在控制台上。该模式是非常基础的,实际使用中需要添加更多参数来满足不同的需求。
使用 cheerio 处理 HTML 文档
对于前端工程师来说,抓取到的网页源码通常都是 HTML 文档。为了便于处理 HTML 文档,我们可以使用 Node.js 的 cheerio 模块。
cheerio 模块是 jQuery 核心的某些功能的精简实现,可以在服务器端使用 jQuery 样式的语法来操作 HTML 文档,提供了一种快速、灵活和具有表现力的方式来处理 HTML 文档,是 Node.js 中处理 HTML 实时爬取的首选代码库。
以下是使用 cheerio 解析 HTML 文档的示例:
// www.javascriptcn.com code example
const cheerio = require("cheerio");
const html = `
<html>
<body>
<h1>抓取网页标题</h1>
</body>
</html>
`;
const $ = cheerio.load(html); // 通过 cheerio.load() 方法载入 HTML 文档
console.log($("title").text()); // 获取 title 标签文本内容在以上示例中,我们首先将 HTML 文档加载到 cheerio 中,然后使用 jQuery 语法中的 text() 方法获取了 title 标签中的文本内容,并打印在控制台上。
除了使用 text() 方法,我们还可以使用其他 jQuery 样式的语法来操作 HTML 文档,例如:find()、html()、attr() 等方法。cheerio 还具有强大的选择器功能,允许我们使用类似于 CSS 的选择器来查找和定位 DOM 节点,比如 $(".container .item:even") 可以选择所有偶数位置的 .item 元素。学习选择器,可以参考 Cheerio 官方文档。
实战演练:抓取电影排行榜
我们使用 Node.js 爬虫技术和 cheerio 模块来抓取一个电影排行榜网站的数据,过程如下:
第一步:加载网页
首先,我们需要了解电影排行榜网站的数据请求和返回方式,并按照网站的要求获取数据,这里我们使用 http.request() 方法来发送 HTTP 请求,代码如下:
// www.javascriptcn.com code example
const http = require("http");
const options = {
hostname: "movie.douban.com",
port: 80,
path: "/chart",
method: "GET",
headers: {
"Content-Type": "text/html"
}
};
const req = http.request(options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
// 访问网页结束后,解析 HTML 文档
});
});
req.end();注意:由于在 Node.js 中发送 HTTP 请求需要输入完整的 URL 地址,所以需要根据电影排行榜网站的要求,填写合适的参数。
第二步:解析 HTML 文档
将网页源码收集到变量 data 中后,就可以使用 cheerio 模块来解析数据了。在编写代码之前,我们可以先查看一下电影排行榜网站的 HTML 结构,并根据结构来编写代码。
网页结构如下:
// www.javascriptcn.com code example
<h1>豆瓣电影排行榜</h1>
<ol class="grid_view">
<li>
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/" class="">
<img src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg"/>
</a>
</div>
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1292052/" class="">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港) / 刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
导演: 弗兰克·德拉邦特 Frank Darabont 主演: 蒂姆·罗宾斯 Tim Robbins /...
</p>
<div class="star">
<span class="rating_num" property="v:average">9.7</span>
<span> / </span>
<span class="pl">2587458人评价</span>
</div>
</div>
</div>
</li>
...
</ol>解析该 HTML 文档,获取下列信息:
- 电影名字
- 导演姓名
- 主演姓名
- 电影评分
- 评价人数
代码如下:
// www.javascriptcn.com code example
const $ = cheerio.load(data); // 加载 HTML 文档
const list = $("ol.grid_view li"); // 获取所有 li 元素(电影条目)
list.each((index, item) => { // 遍历所有电影条目
const titleNode = $("div.hd > a > .title", item); // 获取电影名字节点
const directorNode = $("div.bd > p:first-of-type", item); // 获取导演姓名节点
const castNode = $("div.bd > p:last-of-type", item); // 获取主演姓名节点
const ratingNode = $("div.star > span.rating_num", item); // 获取电影评分节点
const votingNode = $("div.star > span.pl", item); // 获取评价人数节点
const title = titleNode.text(); // 获取电影名字
const director = /\s(.*?)\s\s/.exec(directorNode.text())[1]; // 获取导演姓名
const casting = /\s(.*?)\s\s/.exec(castNode.text())[1].split(" / "); // 获取主演姓名
const rating = ratingNode.text(); // 获取电影评分
const voting = votingNode.text().replace(/[^\d]/g, ""); // 获取评价人数,将非数字字符替换为空字符串
console.log(`${title},导演:${director},主演:${casting.join(",")},评分:${rating},评价人数:${voting}`);
});以上代码首先利用 cheerio.load() 方法将抓取的 HTML 文档载入节点,然后使用 list.each() 方法遍历每个电影条目,按照查询节点的方式找到网页中需要的信息,并在控制台上打印。
到此,我们已经学会了如何使用 Node.js 和 cheerio 模块来实现爬虫,在实际使用中可以根据不同的需求进行调整和优化。在操作上,爬虫有很多细节需要注意,比如网站反爬虫技术、多次请求频率过高导致被封 IP 等,需要综合考虑遵守商业道德和相关法律法规。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/67c014ba314edc2684629dd3