很多时候我们需要爬取一些公开的网页内容来做一些数据分析和统计。而多数时候,大家会用到python ,因为实现起来很方便。但是其实Node.js 用来爬取网络内容,也是非常强大的。
今天我向大家介绍一下我自己写的一个百度新闻的爬虫,可以根据关键词爬取相应的资讯,并将内功格式化。
源码已经发布在github上:GitHub - guangboshushu/getBaiduNews: A crawler to fetch Baidu News data
代码可直接使用,但仅供大家学习使用。
这个爬虫的代码是用来爬取百度新闻的,使用了 axios
和 cheerio
这两个库来处理请求和解析 HTML 页面。下面是分段介绍每个部分的功能:
1. 引入依赖包
const axios = require('axios');
const cheerio = require('cheerio');
axios
: 用于发送 HTTP 请求,这里用来向百度发送 GET 请求获取新闻页面内容。cheerio
: 用于解析返回的 HTML 内容,类似于 jQuery,可以通过选择器查找元素并提取数据。-
Cheerio 是一个强大的 HTML 解析工具,它类似于 jQuery,可以通过选择器来查找元素并提取数据。
cheerio
会将返回的 HTML 内容解析成一个类似 DOM 的结构,并将其转化为一个 jQuery 风格的对象,可以使用标准的 DOM 操作方法(如.find()
、.text()
、.attr()
等)对 HTML 元素进行操作和提取。由于它基于 jQuery 的 API,使用起来非常直观,且性能上比浏览器中的 DOM 操作要高效很多,特别适合用于服务器端的 HTML 内容解析。更准确的细节:
- HTML 解析:
cheerio
并不像浏览器中的DOM
那样提供完整的浏览器环境,它专注于快速解析 HTML 文本,并提供类似 jQuery 的接口供操作。这使得它在 Node.js 环境中非常轻量且高效。 - 对象模型:
cheerio
并不会生成完整的 DOM 树,而是将 HTML 解析成一个类似 DOM 结构的对象,便于操作和查询。它的 API 是基于 jQuery 核心的,使用方法和操作非常熟悉。 - 序列化和提取:你可以通过
cheerio
序列化或遍历 HTML 标签,提取你需要的数据,比如文本、属性值,或者修改 HTML 元素。
2. 自定义函数 findParentDivOfH3
这个函数是用来解析百度新闻的内容的。在解析内容前,需要分析百度的网页结构,打开浏览器访问网页,然后查看源码即可。这里需要稍微有一点html的尝试,比如dom的结构 css的标签等等。这些挺简单的。
比如按照关键词查找 小米手机
网页结构如下,这里现找到标题<h3>的标签,再往上找到它的父DOM,就是一条完整的News DOM。
需要注意的是如果以后百度新闻网页结构变化了 需要调整。
下面是函数源码:
function findParentDivOfH3(html) {
const $ = cheerio.load(html);
const results = [];
$('h3').each(function () {
const parentDiv = $(this).closest('div');
if (parentDiv.length > 0) {
const title = $(this).find("a[aria-label^='标题:']").text().trim();
const titleUrl = $(this).find("a[aria-label^='标题:']").attr("href");
const leftImgSrc = parentDiv.find("img").first().attr("src");
const hasImg = leftImgSrc ? true : false;
const summary = parentDiv.find(".c-font-normal.c-color-text").text().trim();
const dispTime = parentDiv.find(".c-color-gray2.c-font-normal").text().trim();
const sourceIcon = parentDiv.find(".source-img_33bs5").attr("src");
const sourceName = parentDiv.find(".news-source_Xj4Dv span.c-color-gray").text().trim();
const rtses = parentDiv.find(".news-source_Xj4Dv span.c-color-gray").text().trim();
results.push({
title,
titleUrl,
leftImgSrc,
hasImg,
summary,
dispTime,
sourceIcon,
rtses,
sourceName
});
}
});
return results;
}
功能:
- 该函数接收一个 HTML 字符串,使用
cheerio
来解析 HTML 内容。 - 查找所有
<h3>
标签,通过.closest('div')
获取每个<h3>
标签的父级<div>
元素。 - 从每个父
<div>
元素中提取出以下信息:- 新闻标题(
title
) - 新闻链接(
titleUrl
) - 左侧图片的
src
(leftImgSrc
) - 是否有图片(
hasImg
) - 摘要(
summary
) - 发布时间(
dispTime
) - 来源图标(
sourceIcon
) - 来源名称(
sourceName
) - 转载数(
rtses
)
- 新闻标题(
- 将这些信息存入
results
数组,并返回。
3. 获取百度新闻的函数 getBdiduNews
const getBdiduNews = (keyWord) => {
const _keyWord = encodeURIComponent(keyWord);
const cookies = 'Here are your cookies if necessary'
const url = `https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word=${_keyWord}`;
return axios.get(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Cookie': cookies
}
})
.then(response => {
return (findParentDivOfH3(response.data));
})
.catch(error => {
console.error('Error:', error);
});
}
功能:
getBdiduNews
函数接收一个关键词keyWord
,然后将其进行 URL 编码(encodeURIComponent
),用于构造百度新闻的查询 URL。- 发送一个 GET 请求到百度新闻搜索页面,使用
axios
发送请求,设置User-Agent
和Cookie
作为请求头(其中Cookie
是用于模拟浏览器请求的,避免百度反爬虫机制的限制)。 - 请求成功后,调用
findParentDivOfH3
函数来解析返回的 HTML 内容,并提取新闻信息。 - 如果请求出错,则在控制台输出错误信息。
4. 导出模块
module.exports = getBdiduNews;
- 这行代码将
getBdiduNews
函数导出,使得其他文件可以使用require
引入并调用这个函数。
5. 调用示例
getBdiduNews('小米手机').then(res => {
console.log(res)
});
- 这里调用
getBdiduNews
函数,传入关键词'小米手机'
,然后使用.then()
获取爬取结果并打印出来。 - 结果就出来了:
总结:
- 该爬虫的功能是从百度新闻中抓取关键词相关的新闻信息,并提取每条新闻的标题、链接、摘要、图片、发布时间、来源等信息。
- 使用了
axios
发送请求,cheerio
解析 HTML 内容,且通过自定义函数处理页面中的数据提取。
希望这个分段介绍能帮助你更好地理解代码。这个爬虫是给你用来学习的,记得要注意合法性,避免侵犯百度的服务条款。