Nodejs爬虫(高级爬)

205 阅读2分钟

前言:

提起爬虫,大家马上能想到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("全部结束")})

未来可期,一起加油吧 (忽而夏逝,却已立秋。)