0%

Node.js实现简单网页数据抓取

由于自己的小项目需要后台支持,所以前段时间学习了下 Node.js。简单介绍下 Node.js,Node.js 是一个基于 JavaScript 语言和 V8 引擎运行在服务端的并发平台,在 Node.js 出现以后,使得 JavaScrip 不光能写前端的动态效果,交互效果,还能写 web 服务器,从此,前端工程师的触角向后延伸了一大块。Node.js 功能如此强大,但是我今天才初步学习Node.js,对于一个前端人员来说实在是很惭愧。

一. 页面结构分析

话不多说,正式进入主题。今天我们要抓取的网站是笔者的大学校报(校园资讯),首先我们来简单分析下网站的页面结构。

分页规律:

第一页 http://news.ecjtu.jx.cn/1920/list.htm

第二页:http://news.ecjtu.jx.cn/1920/list2.htm

第三页:http://news.ecjtu.jx.cn/1920/list3.htm

由此可以看出,页面都是以list+page作为分页的。

文章列表页分析:

我们可以看到文章列表是以table格式显示的,并且每个class为listName的第一个a标签就是文章详情的入口。

文章详情页分析:


由此可以发现页面规律:

文章标题: .actTitle 文章详情: .postmeta 正文图片:.wp_articlecontent>p>img

浏览次数: .WP_VisitCount

二. 代码编写

在编写代码之前,我们先了解一些需要用到的模块,由于http模块、fs模块都是Node.js内置的包,因此不需要额外添加。

superagent:它是一个强大并且可读性很好的轻量级ajax API,是一个关于HTTP方面的一个库,而且它可以将链式写法玩的出神入化。(这里笔者只是尝试下 superagent 写法,使用http 模块一样效果)

cheerio:可以理解成一个 Node.js 版的 jquery,用来从网页中以 css selector 取数据,使用方式跟 jquery 一模一样。

安装这些模块

1
npm install superagent cheerio url --save
完整代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const superagent = require('superagent');
const cheerio = require('cheerio');
const async = require('async');
const fs = require('fs');
const url = require('url');
const request = require('request');

const urlHead = 'http://news.ecjtu.jx.cn';


let allUrl = []; // 所有文章连接
let imgUrlList = []; // 图片url
//爬取10页
for(let i = 0; i <= 9; i++) {
// 循环请求文章列表页
requestUrl = 'http://news.ecjtu.jx.cn/1920/list' + i + '.htm';
superagent.get(requestUrl)
.end((err,res) => {
if(err) {
return console.error(error);
}
// cherrio模块获取页面内容
let $ = cheerio.load(res.text);
// 获取文章列表所有链接
$('.listName>a:first-child').each((idx,elem) => {
let $elem = $(elem);
let href = url.resolve(requestUrl,$elem.attr('href'));
allUrl.push(href);
// 文章详情页信息
superagent.get(href)
.end((err,res) => {
if(err) {
return console.error(error);
}
let $ = cheerio.load(res.text);
let _href = href;
// 对文章图片url需处理
let imgUrl = $('.wp_articlecontent>p>img').attr('src') ||
"http://xw.ecjtu.jx.cn/_upload/article/images/c7/89/be9f5e4845c69f6991ad006ab241/f2ba53cf-e7f4-497b-bec8-1b254e2b5f6c.jpg";
// 文章信息
let articleInfo = {
"address": _href,
"title": $('.actTitle').text().trim(),
"detail": $('.postmeta').text().trim(),
"view": $('.WP_VisitCount').text(),
"imgSrc": $('.wp_articlecontent>p>img').attr('src') || "",
}
if( imgUrl.indexOf("http") == -1 ) {
imgUrl = urlHead + imgUrl;
}
imgUrlList.push(imgUrl);
console.log(articleInfo);
console.log(imgUrl)
console.log(imgUrlList);
// 注意有些网站需要设置UA才可以爬取网页内容
const options = {
url: imgUrl,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
}
// 数据存储在本地文件中
fs.appendFile('data/result.json', JSON.stringify(articleInfo), 'utf-8',(err) => {
if(err) throw new Error("数据存储失败....");
console.log('存储成功!');
})
// 同步存储图片
request.head(options,(err,res,body) => {
if(err) console.log(err);
})
request(options).pipe(fs.createWriteStream('./ecjtuImages/' + (new Date()).getTime() +'.jpg'));
// 异步获取图片需要使用到async异步下载
/*
const downloadPic = (src,dest) => {
request(src).pipe(fs.createWriteStream(dest)).on('close',function(){
console.log('pic saved!')
})
}
async.mapSeries(imgUrlList,function(item, callback){
setTimeout(function(){
downloadPic(item, './ecjtuimages/'+ (new Date()).getTime() +'.jpg');
callback(null, item);
},400);
}, function(err, results){});
*/
})
})
})
}

代码中使用了 Node.js 中模块的一些基本用法,有不懂的同学可以看看官网

我们将爬取的文章信息储存在本地 result.json 文件中,图片储存在 ecjtuimages 文件夹中。

注意:有些网站需要设置User-Agent才能爬取网页信息哦。并且当你需要下载大量图片时,可以使用async模块的mapSeries方法异步下载哦。

三. 运行程序

完成上述两步操作之后,运行 node index.js ,我们可以看到程序开始爬取了。

打开 result.json 文件和 ecjtuimages 文件夹查看是否存储成功。

到这里,Node.js 简单的爬取网页数据就结束了。有兴趣的同学也可以引入 mysql,将数据直接存储在数据库中。(笔者私下爬取了很多精彩丰富的内容,欢迎来扰)

总结

此次爬取的网站安全性较差,但有些网站的反爬虫技术做的很好,再使用这种方法就无法爬取了哦。 这次只是简单的 Node.js 初试,仅仅是初探,就已经体会到了 Node.Js 的魅力。更多Node.js 强大的功能我们一起学习。如文章有误之处,欢迎指正。

-------------本文结束, 感谢您的阅读-------------