js 爬虫抓取网页数据( 2017年02月22日09:30之前简单的爬虫实现原理)
优采云 发布时间: 2021-11-14 05:08js 爬虫抓取网页数据(
2017年02月22日09:30之前简单的爬虫实现原理)
从头开始学习 node.js 的简单网络爬虫(四)
更新时间:2017年2月22日09:30:53 作者:文子
一个简单爬虫的实现原理很简单:向目标地址发送http请求获取HTML页面数据,然后从获取的页面数据中提取需要的数据并保存。下面文章文章主要介绍使用node.js实现一个简单的网络爬虫的相关资料。有需要的朋友可以参考。
前言
之前介绍了node.js的一些基础知识,下面文章我们的目标是在完成本课程后对网页进行简单的分析和抓取,并输出和分析抓取到的信息。文本已保存。
爬虫的思路很简单:
确定要爬取的URL;抓取网址,获取网页内容;分析和存储内容;重复步骤 1
在爬虫的这一部分,我们用到了两个重要的模块:
一、你好世界
说起hello world,其实最简单的爬取就是最先开始的。我们以cnode网站为例(),这个网站的特点是:
您无需登录即可访问主页和其他页面。页面是同步渲染的,异步请求没有问题。DOM 结构清晰。
代码显示如下:
var request = require('request'),
cheerio = require('cheerio');
request('https://cnodejs.org/', function(err, response, body){
if( !err && response.statusCode == 200 ){
// body为源码
// 使用 cheerio.load 将字符串转换为 cheerio(jQuery) 对象,
// 按照jQuery方式操作即可
var $ = cheerio.load(body);
// 输出导航的html代码
console.log( $('.nav').html() );
}
});
这样一段代码就实现了一个简单的网络爬虫。爬取源代码后,对源代码进行反汇编和分析。比如我们要获取首页第一页问题的标题、作者、跳转链接、点击次数、回复数量。通过chrome,我们可以得到这样的结构:
每个 div[.cell] 是一个具有完整主题的单元,其中一个单元暂时称为 $item
{
title : $item.find('.topic_title').text(),
url : $item.find('.topic_title').attr('href'),
author : $item.find('.user_avatar img').attr('title'),
reply : $item.find('.count_of_replies').text(),
visits : $item.find('.count_of_visits').text()
}
因此,循环 div[.cell] 得到我们想要的信息:
request('https://cnodejs.org/?_t='+Date.now(), function(err, response, body){
if( !err && response.statusCode == 200 ){
var $ = cheerio.load(body);
var data = [];
$('#topic_list .cell').each(function(){
var $this = $(this);
// 使用trim去掉数据两端的空格
data.push({
title : trim($this.find('.topic_title').text()),
url : trim($this.find('.topic_title').attr('href')),
author : trim($this.find('.user_avatar img').attr('title')),
reply : trim($this.find('.count_of_replies').text()),
visits : trim($this.find('.count_of_visits').text())
})
});
// console.log( JSON.stringify(data, ' ', 4) );
console.log(data);
}
});
// 删除字符串左右两端的空格
function trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
二、 抓取多个页面
我们只抓取了上面的一页。如何在一个程序中抓取多个页面?我们以 CNode网站 为例。刚刚爬取了第1页的数据,这里我们要请求前6页的数据(不要同时抓取太多页面,IP会被拦截)。每个页面的结构都是一样的,我们只需要修改url地址即可。
2.1 同时获取多个页面
首先,将请求请求封装成一个方法,方便调用。如果还是用console.log的方式,6页的数据都会输出到控制台,看起来很不方便。这里我们使用上一节的文件操作内容,引入fs模块,将获取到的内容写入文件,然后将新创建的文件放到文件目录下(需要手动创建文件目录):
// 把page作为参数传递进去,然后调用request进行抓取
function getData(page){
var url = 'https://cnodejs.org/?tab=all&page='+page;
console.time(url);
request(url, function(err, response, body){
if( !err && response.statusCode == 200 ){
console.timeEnd(url); // 通过time和timeEnd记录抓取url的时间
var $ = cheerio.load(body);
var data = [];
$('#topic_list .cell').each(function(){
var $this = $(this);
data.push({
title : trim($this.find('.topic_title').text()),
url : trim($this.find('.topic_title').attr('href')),
author : trim($this.find('.user_avatar img').attr('title')),
reply : trim($this.find('.count_of_replies').text()),
visits : trim($this.find('.count_of_visits').text())
})
});
// console.log( JSON.stringify(data, ' ', 4) );
// console.log(data);
var filename = './file/cnode_'+page+'.txt';
fs.writeFile(filename, JSON.stringify(data, ' ', 4), function(){
console.log( filename + ' 写入成功' );
})
}
});
}
CNode分页请求链接:,我们只需要修改page的值:
<p>var max = 6;
for(var i=1; i