nodejs抓取动态网页(一个网络爬虫的开发过程及实现过程原理目标分析)
优采云 发布时间: 2021-10-14 22:14nodejs抓取动态网页(一个网络爬虫的开发过程及实现过程原理目标分析)
Nodejs 将前端开发语言移植到了服务端。如今,前端开发者可以轻松地使用 Nodejs 实现网络爬虫,这在以前是不可想象的。本文介绍了一个简单的Nodejs爬虫开发过程,只想看代码拉到最后。
爬行原理目标分析
这次爬取的目标选择是观察cnBeta的新闻详情页收录到相邻页面的链接,但是通过查看源码发现这个链接是由Js生成的:
这是一种常见的反爬虫措施。关联的页面链接通过异步请求获取,然后由js动态生成。检查网络面板,您可以看到该页面确实发送了一个异步请求。结果具有我们想要的关联页面 ID:
接下来分析这个请求,可以发现有两个参数,这两个参数都可以在HTML中找到:
第一个参数_csrf很容易直接在源码中搜索:
第二个参数全文搜索找不到:
观察这个参数的结构,发现数据被两个逗号分隔成三段,所以猜测数据是由于多部分拼接造成的,单独搜索真的找到了:
但是只找到了最后两段数据,开头是1,不知道是哪来的。由于只有一个字符,检索起来比较困难,观察到这个请求在很多页面中都是以1开头的,所以这里干脆写死了。. .
至此,对目标的分析结束,下面将执行爬虫。
实施过程程序结构
大体思路是从起始页开始爬取,异步获取上一个新闻页面的链接继续爬取,并设置最大爬取次数,防止陷入死循环。伪代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let fetchLimit = 50; //最大抓取条数
let fetched = 0; //计数器
let getNext = function(_csrf, op){ //获取下一篇文章ID
return Promise(function(resolve,reject){
let nextID;
...
resolve(nextID);
})
}
let fetchPage = function(ID){ //抓取程序
let _csrf = ...;
let op = ...;
save(ID); //保存内容
fetched++; //计数器累加
getNext(_csrf, op).then(function(nextID) {
fetchPage(nextID); //获取下一篇ID并进入循环
});
}
fetchPage('STARTID'); //开始抓取
功能点
关键是保存内容。首先,获取页面的 HTML 代码。主要使用http模块,如下:
1
2
3
4
5
6
7
8
9
10
11
const http = require('http');
http.get(pageUrl, function(res){
let html='';
res.setEncoding('utf8');
res.on('data', (chunk) => {
html += chunk;
});
res.on('end', () => {
console.log(html); //这里得到完整的HTML字符串
});
})
要从 HTML 获取信息,您可以使用常规匹配,或使用cheerio。Cheerio 可以说实现了一个 Nodejs 端的 jQuery。它和jQuery的区别在于它需要先生成一个实例,然后像jQuery一样使用它:
1
2
3
const cheerio = require('cheerio');
const $ = cheerio.load(html);
let news_title = $('.cnbeta-article .title h1').text().trim().replace(/\//g, '-');
fs模块主要用于保存文件,如下:
1
2
3
4
5
6
const fs = require('fs');
fs.writeFile(FilePath, FileContent, 'utf-8', function(err) {
if (err) {
console.log(err);
}
});
这里有个坑。我们希望将文章的文本保存为与标题同名的txt文本,但标题可能收录斜线(/)。保存这样的文件时,程序会误认为标题斜线之前的部分。把它看成是路径,报错,所以需要替换标题中的斜线。
保存图片与保存文本大致相同。主要区别在于写入格式,需要以二进制方式写入:
1
2
3
4
5
6
7
8
9
10
11
12
13
http.get(img_src, function(res) {
let imgData = "";
res.setEncoding("binary"); //注意格式
res.on("data", function(chunk) {
imgData += chunk;
});
res.on("end", function() {
fs.writeFile(imgSavePath, imgData, "binary", function(err) { //注意格式
if (err) {
console.log(err);
}
});
});
程序的结构和主要功能基本是这样的。
后记
实现爬虫说起来容易,但是健壮性真的很难保证。在爬cnBeta的过程中,又发现了一个301跳坑。URL跳转时,程序抓取的HTML为空,无法获取。因此,请求得到响应后,需要判断响应头是否为301,如果是,则需要从响应信息中找到重定向的URL,重新发起请求。好在cnBeta是不需要用户登录的,如果是必须登录才能访问的网站,爬虫会很麻烦。
本项目完整代码见Nodejs爬虫,感谢cnBeta^^。
前路原创技术文章,转载请注明出处:爬虫练习笔记/
不甘平庸的你,快来和我一起充电,关注风景,获取更多精彩内容。