前言:
提起爬虫,大家马上能想到python,其实任何一种可以发起http请求的脚本都是ok的,如果ajax不存在跨域问题,完全可以单独用js写爬虫程序。
本篇文章讲解两种形式的爬虫过程,通俗来说就是抓取服务端渲染和客户端渲染的页面。
一、准备工作
- 安装nodejs(百度搜索nodejs,根据系统下载安装即可)
- 打开终端,输入node -v检测nodejs是否安装成功
- 替换镜像源
npm config set registry http://registry.npm.taobao.org/
- 创建项目目录,新建client.js
二、客户端渲染
nodejs作为客户端发送请求可以使用内置http模块,但是使用起来不太方便,所以咱们选用request模块
npm i request
基础使用:
var request = require("request");
var fs = require("fs");
request("https://www.baidu.com", function (error, response, body) {
if (!error && response.statusCode == 200) {
//输出返回的内容 百度首页内容
console.log(body);
}});
// 下载百度logo到本地request("https://www.baidu.com/img/bd_logo1.png").pipe(fs.createWriteStream("logo.png"))
运行脚本,控制台打印百度首页内容,百度logo存储到当前目录下。
目前只是拿到了页面内容,咱的目的是解析页面中包含的数据,下载cheerio模块,它的作用是将html字符串转化成类似虚拟DOM树,我们可以使用jQuery一样的语法获取任意标签的属性和内容
npm i cheerio
分析body结构,提取想要抓取的内容
client.js改为:
var request = require("request");
var fs = require("fs");
var cheerio=require("cheerio");
request("https://www.baidu.com", function (error, response, body) {
if (!error && response.statusCode == 200) {
// body为请求的页面内容,如你在浏览器右键查看源代码看到的东西
var $ = cheerio.load(body) //load方法返回类jQuery $函数
// 抓取导航链接
var list=[];
$("#u1 a").each(function(){
list.push({
href:$(this).text(),
text:$(this).attr("href")
})
})
console.log(list);
}});
结果:
[
{ href: '新闻', text: 'http://news.baidu.com' },
{ href: 'hao123', text: 'http://www.hao123.com' },
{ href: '地图', text: 'http://map.baidu.com' },
{ href: '视频', text: 'http://v.baidu.com' },
{ href: '贴吧', text: 'http://tieba.baidu.com' },
{
href: '登录',
text: 'https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F' },
{ href: '设置', text: '//www.baidu.com/gaoji/preferences.html' },
{ href: '更多产品', text: '//www.baidu.com/more/' }]
抓取到的内容,可以存储到文件或数据库中
上面的抓取形式只能拿到服务器端渲染的内容(右键查看源代码可以看到的内容),但是目前大部分网站内容使用的是js渲染(ajax、jsonp请求,然后插入页面)框架单页应用更是如此。当然你也可以network找到相关接口,这种形式通用性不太强。如何抓取网页异步渲染内容呢?答案:phantom
phantom是一个基于webkit的JavaScript API。它使用QtWebKit作为它核心浏览器的功能,使用webkit来编译解释执行JavaScript代码。你可以理解为它是一个没有界面的浏览器,调用相关方法,会等待页面中初始代码执行完毕,然后将渲染的结果返回给你。
npm i phantom //注意不是phantomjs
获取完整内容:
var phantom = require("phantom");
let sitepage = null; //创建网页对象实例
let phInstance = null; //创建phantom实例对象
phantom.create()
.then(instance => {
phInstance = instance;
return instance.createPage();
})
.then(page => {
sitepage = page;
return page.open("https://www.baidu.com");
})
.then(status => {
return sitepage.property('content'); //获取相应的属性内容
})
.then(content => {
console.log(content)//获取最终的页面结构
sitepage.close();
phInstance.exit();
})
.catch(error => {
console.log(error);
phInstance.exit();
});
client.js改为:
var cheerio = require("cheerio");
var getPage = require("./getPage");
getPage("https://www.baidu.com", body => {
var $ = cheerio.load(body)//load方法返回类jQuery $函数
// 抓取导航链接
var list = [];
$("#u1 a").each(function () {
list.push({
href: $(this).text(),
text: $(this).attr("href")
})
})
console.log(list);
})
注意:下载phantom的时候默认会下载phantomjs-prebuilt会特别慢,可以自行去github下载然后拷贝到node_modules,或者找我要。
如果需要爬的页面比较多,电脑会特别卡,因为内部打开了很多页面,提供以下流程控制代码参考使用:
module.exports = function (start, end, f, endHandle) {
function next() {
start++;
start < end ? f(start, next) : endHandle();
}
start--;
next();
}
// 用法var loop = require("./loop");
loop(0, 100, (index, next) => {//进入循环执行此函数
setTimeout(() => {
console.log(index);
next();//主动调用next开始下轮循环
}, 1000)}, () => {
//循环结束 执行此函数
console.log("全部结束")})
未来可期,一起加油吧 (忽而夏逝,却已立秋。)