Loading...

使用NodeJS爬取知乎热榜

发布者 milleros - 7 个月前

之前用Python写过一些小爬虫,但是作为前端,我还是对Nodejs比较熟悉,由于最近大量的APP下架,想看很多咨询都看不来,遂便想着利用Nodejs写一个爬虫,爬取我想要看的网站的热门内容。

本文所述的内容需建立在您对Nodejs有一定了解,能独立编写一些简单的请求响应功能,高级部分则要求更高

废话不多说,具体流程请看下面

1. 准备工作

在工作开始之前我们需要准备以下几个条件:

1.1 基础软件

  • Nodejs v8.9.3
  • npm v6.7.0

以上软件的安装可以查看Nodejs官网

1.2 npm软件包

  • koa //Nodejs的框架,和express类似
  • iconv-lite //用来转换网站字符编码
  • axios //用来请求目标网站/接口
  • cheerio //用来解析目标网站返回的html页面,使得可以在服务端类似客户端用jQuery操作DOM一样操作解析后的html元素

关于以上的软件包具体的使用方法可以去google搜索官方文档查看

2. 开始

2.1 安装依赖

首先我们建立一个项目文件夹NodejsFetchZhihu.com

$ mkdir NodejsFetchZhihu.com
$ cd NodejsFetchZhihu.com/

$ npm init -y //初始化此文件夹为Nodejs项目文件夹,生成一个package.json 文件

$ npm install koa iconv-lite axios cheerio --save //安装1.2内的依赖

2.2 建立http服务

新建文件server.js

const Koa = require('koa');
const app = new Koa();

app.use(async ctx => { //此拦截器表示所有请求进来我们都返回hello World
  ctx.body = 'Hello World';
});

console.log('站点建立在http://localhost:3000上');
app.listen(3000);

2.3 运行

到这里,我们已经初步建立了一个可访问的http站点

$ node server.js //运行
站点建立在http://localhost:3000上

访问 http://localhost:3000 我们就可以看到页面返回了hello World

hello-world

3. 爬取

开始前我们要先打探好我们要爬取的网页的地址,例如我们此刻要爬取的是知乎热榜,那么可以从下图看到知乎热榜的页面地址是 https://www.zhihu.com/hot

-

3.1 修改中间件并爬取

我们刚刚server.js设定的所有请求都会直接返回“hello world”,现在将它修改成请求知乎热榜页面

此处我们使用axios请求目标地址,具体文档请参考axios官网

const Koa = require('koa');
const axios = require('axios');
const app = new Koa();

app.use(async ctx => { //此拦截器表示所有请求进来我们都返回hello World
    let _res = await axios.get('https://www.zhihu.com/hot').then((res) => {
        return res
    });

    ctx.body = JSON.stringify(_res.data);
});

console.log('站点建立在http://localhost:3000上');
app.listen(3000);

运行后我们可以看到我们的站点返回了以下内容

-

我们可以看到返回结果里面有一些登录字样,这说明知乎热榜是需要登录才能查看的,所以这里我们需要设定以下axios的请求头

我们将代码修改成下面所示

const Koa = require('koa');
const axios = require('axios');
const app = new Koa();

app.use(async ctx => { //此拦截器表示所有请求进来我们都返回hello World
    let _headers = {};
    _headers.cookie = '你的cookie';

    let _res = await axios.get('https://www.zhihu.com/hot', { headers: _headers }).then((res) => {
        return res
    });

    ctx.body = JSON.stringify(_res.data);
});

console.log('站点建立在http://localhost:3000上');
app.listen(3000);

这里涉及到一个概念,就是网站cookie,但是在这我就不赘述这个是什么,以及原理,我们只需要知道这个cookie是用来记录我们是否登录了zhihu.com的标记。

那么怎么获取cookie呢?这里我们首先打开并登录https://www.zhihu.com/hot 然后打开开发者工具,切换到Network面板,随便点击一个请求(如果没有则刷新一下页面),在右侧的headers里面往下翻可以看到我们的cookie

cookie-

复制这段cookie,粘贴到代码里面的“你的cookie”处,然后保存运行。

-

我们可以看到,这里的红线处已经有了知乎热榜上的内容了

3.2 解析网页结果

首先我们先分析知乎热榜的页面结构:

-

从上图我们可以看到,知乎热榜,用来显示热榜数据的div类名叫做HotList-list,单个知乎热榜信息的条目类名是HotItem,所以我们先获取条目列表

const cheerio = require("cheerio"); //用于解析html文本
//取基本数据
const _list = $('html').find('HotList-list');

然后遍历条目,假设这里我们有需求取知乎热榜记录中的标题和热度

let _dataTmp = []; //下发到客户端的数据
await _list.each((_index, _el) => {
    const _item = $(_el);

    let _itemTmp = {}; //存储类目值

    let _title = _item.find('.HotItem-title').text().replace(/[\r\n]/g, ''); //标题
    let _Hot = _item.find('.HotItem-metrics').text().replace(/[\r\n]/g, ''); //热度

    _itemTmp = {
        title: _title,
        hot: _Hot
    };

    _dataTmp[_index] = _itemTmp; //下发到客户端的数据
});

查看完整代码

const Koa = require('koa');
const axios = require('axios');
const cheerio = require("cheerio");
const app = new Koa();

app.use(async ctx => { //此拦截器表示所有请求进来我们都返回hello World
    let _headers = {};
    _headers.cookie = '_zap=0b7d5fde-a8b3-4d26-93d6-292ee4aa6488; d_c0="AKDnag8Xcg6PTg2vbEVtmCLLSwxAuwaqJKw=|1540954624"; _xsrf=a5bf2345-7d9d-4e96-82bf-02c7dcb4c9f2; l_n_c=1; q_c1=a47cb58a45fc4185a896490e8ffbd9a1|1563335283000|1546479842000; n_c=1; client_id="MzE2OTQ2Njc0Mw==|1563335331|411d415eb2357dc431e6aa3d30f5a4e8946c467a"; accountcallback=%7B%22status%22%3A%22new%22%2C%22fullname%22%3A%22MillerOS%22%2C%22type%22%3A%22sina%22%7D; tst=h; tshl=; l_cap_id="N2U0ZTNhMjQ3MzIzNGJjNjk1YWQ3OGI1YmRjMThkZWI=|1563516259|3bb9087cb4582ced6da3bf6c94c8b1c4f326e234"; r_cap_id="YzMxYzNiYTg4NzY4NDFlODk1MGY4NTExYmVmNWVlYjE=|1563516259|704737df69afd1df6913062aeb7fdf7155a387ab"; cap_id="MDYzZWIyNzI2ZGIxNDgzZjgzZTcyYTZiNmIyMDg0ZWQ=|1563516259|522c5e94cde2b2e6e4bdbdb5516d26d8e938c89b"; capsion_ticket="2|1:0|10:1563516306|14:capsion_ticket|44:ZjExOTE5NWYyYmQyNDZkMTg2YWIxZjBlOGFhYTJhZmY=|1969f6465d2e739d0d865b28577abcee45b3c54964bec458122582b7a837f8f0"; z_c0="2|1:0|10:1563516317|4:z_c0|92:Mi4xdkUwSUNBQUFBQUFBb09kcUR4ZHlEaVlBQUFCZ0FsVk5uYXNlWGdEYmg5bjJjeGNpZmFMandXVmxHdm9CSW5HN1lR|1b4b01dbfd08aba411b467447ca18ed7334e0a1d2a5e5fb7cd0e1032fa7cc473"; tgw_l7_route=060f637cd101836814f6c53316f73463';

    let _res = await axios.get('https://www.zhihu.com/hot', { headers: _headers }).then(async (res) => {
        const $ = cheerio.load(res.data); //格式化数据

        //取基本数据
        const _list = $('html').find('.HotList-list .HotItem');

        let _dataTmp = []; //下发到客户端的数据
        await _list.each((_index, _el) => {
            const _item = $(_el);

            let _itemTmp = {}; //存储类目值

            let _title = _item.find('.HotItem-title').text().replace(/[\r\n]/g, ''); //标题
            let _Hot = _item.find('.HotItem-metrics').text().replace(/[\r\n]/g, ''); //热度

            _itemTmp = {
                title: _title,
                hot: _Hot
            };

            _dataTmp[_index] = _itemTmp; //下发到客户端的数据
        });

        return _dataTmp
    });

    ctx.body = JSON.stringify(_res);
});

console.log('站点建立在http://localhost:3000上');
app.listen(3000);

保存并运行,查看结果

-

可以看到,在这里我们已经获取到了知乎热榜内的数据,那么拥有这些数据,我们就可以放在自己的网站上,轻松的查看这些内容,亦或者是发送到自己的邮箱。

4. 结语

关于爬虫的学问还有非常深入的,爬虫作为当今领域不可或缺的角色,不管是搜索引擎,还是资讯app,很多地方都又这爬虫的身影,作为这个时代的开发者,我们编写爬虫的时候要注意几个问题

4.1 合法性

不爬取存储触犯法律网站的内容,且如果是需要另外展示出来,最好注明一下内容的来源,某些明确不让爬取的网页就不要爬取了。敏感信息自己看看就行,不要呈现给他人。

4.2 资源

爬取内容时应该注意频率,不能高频检索目标网站,这样不仅会造成目标网站的资源被大大的浪费,而且我们的爬虫也极其容易被目标网站限制

4.3 优质性

如果我们的爬虫爬取的数据是为了提供给我们自己的用户使用,则应该保证爬取内容的优质性,低俗内容就过滤掉为好,要不然咳咳,不就成了百毒那样了吗?

5. 附件

完整的项目代码可以参考这里 https://github.com/MillerO/NodejsFetchZhihu.com

标签纵览

APP(1)SSH(1)Docker(1)Python(1)VueJS(3)Nodejs(2)Linux(5)前端(9)
Loading...