不是从零开始的Web开发(二)
本篇的主要内容是新闻爬虫的实现
在完成了前期的部署之后,接下去就是愉快地开发过程了。node.js 的语法就是 js 的语法,没有什么介绍的必要,基础语法看教程即可。node.js 的特色是函数回调,如果不把这个问题处理好的话,就会像我一样陷入回调地狱之中(跑。
回到正题,爬虫的实现主要分成两个部分。一个是请求网页数据,一个是解析网页。
配置环境
请求网页和解析网页的包都有不止一个,但大家都是大同小异的。在本文中,请求网页数据用的是 request
包,解析网页用的是 cheerio
包,所以在使用之前先导入相应的包。
var myRequest = require("request");
var myCheerio = require("cheerio");
假如没有就用 npm 下载。
请求网页数据
请求网页数据的本质就是把 js 的访问包装成一个浏览器访问,让网站正常地给你返回一个完整的网页。本来,因为大量的爬虫会拖慢服务器,所以爬虫和网站的反爬要不断地斗智斗勇,但据我实验,似乎因为我爬的数量太少了,根本没有触发任何机制,直接拿一个裸的访问请求抓到了需要的数据……
首先对 request
包再包装一下。
function request(url, callback) {
var options = {
url: url,
encoding: null,
headers: null,
};
myRequest(options, callback);
}
正常来说,options
里的参数不可能只填一个 url
,应该要把 headers
补充完整,以伪装成一个浏览器请求。但既然爬虫没被反制,也不费这个心思处理了。
需要注意的是函数的第二个参数,callback
即回调函数,顾名思义,callback
会在访问请求返回之后被调用,而在这个时间段内,程序并没有等着回调函数的结束,而是自顾自的继续运行了。这种异步的操作减少了大量阻塞的时间,但也给初学者造成了一些上手的困难,因为回调函数和后续内容的执行顺序是不好确定的。举个例子:
var a = 2;
request(url, function () {
a = 1;
});
console.log(a);
此时输出的结果并不能很好地确定,因为拿不准回调内的赋值语句是否会在输出之后再执行(一般是会的,因为网络 IO 的延时比本地执行大得多)。所以为了保证回调得到的数据能够被正确地处理,只能把对这个数据的处理逻辑全部放在回调函数里面。层层套娃,就变成了回调地狱。
但总之,我们可以在回调函数里拿到 request
请求的数据,并在函数里对数据做处理。
request(url, function (err, res, body) {
var html = body;
/*
处理逻辑
*/
});
解析网页数据
做新闻爬虫大概需要爬取两个类型的网页,一种是目录网页,也就是导航页;一种是新闻的主体网页。首先从目录网页上获取主体网页的链接,再逐个访问主体网页,从网页里获取新闻的具体信息。
解析目录网页
目录网页的网址一般需要自己确定,比如这里以新浪新闻的首页为例,在爬取了新浪新闻的首页之后。使用 cheerio
解析网页的内容,这个包的基本使用方法和 jQuery
的解析方法是类似的,只要读取所有链接标签 <a>
的链接就能获取主体网页的链接。
var $ = myCheerio.load(html, { decodeEntities: false });
hrefArr = $("a");
当然,这些链接中有许多都不是新闻的链接,可以通过正则表达式对链接做一个初步的筛选。这里的正则表达式筛选出的是 https://news
开头的 html 文件。
var exr = /https:\/\/news.*html/;
for (var i = 0; i < hrefArr.length; i++) {
hrefURL = hrefArr[i].attribs.href;
if (exr.test(hrefURL)) {
urlArr.push(hrefURL);
}
}
解析主体网页
在获取了主体网页的地址之后,仿照上面的方法,可以得到主体网页的内容。但要从中分析出需要的内容,相对会比较困难。一个比较好的办法是随便用浏览器打开一个主体网页,F12,然后拿元素检查在网页上戳,一般用标签加上 CSS 类加上 id 足够确定对应的元素了。多试几遍就能正确地锁定目标文本。
var ans = {};
ans["title"] = $("title").text();
// 对中文日期格式做处理
ans["date"] = new Date(
Date.parse(
$("span.date")
.text()
.replace("年", "-")
.replace("月", "-")
.replace("日", "")
)
);
ans["content"] = $("#article p").text();
总结
爬取网页的重点在于对请求的伪装和回调函数,解析网页的重点在于正确地分析出所需要的数据的位置然后提取。至于提取出来的数据怎么保存,那又是另一个故事了。如果只是想用来提取自己想看的新闻,直接输出就可以了。
- 本文作者: wengsy150943
-
版权声明: 本博客所有文章除特别声明外,均采用
BY-NC-SA
许可协议。转载请注明出处!