Nodejs写一个网页爬虫

Nodejs写一个网页爬虫

需求背景

喜欢唯美的句子,喜欢抒发情感的文章,经常去短文学网上看别人些的优美词句。有时候想找特定关键词的文章,避免一篇一篇滚动查找,然后用Node写了一个简单的爬虫工具。

功能需求

  1. 输入域名,点击“确定”按钮列出当前域名下的文章标题列表
  2. 可以选择是否输入关键字,输入了关键字,可以查找出文章标题包含该关键字的列表

功能演示

使用技术

  1. Nojejs+Koa框架 搭建项目
  2. koa-ejs模板引擎 渲染页面

项目结构

api

index.js

router

home.js

static

js

css

index.css

utils

request.js

view

home.html

index.js

项目大致结构按上述文件夹划分,api(前台页面发送ajax请求的路由地址)、router(页面路由)、static(静态文件)、utils(工具类)、view(模板文件)、index.js(入口文件)

模板引擎 koa-ejs

koa-ejs是中间件,它支持ejs所有的特性。

npm install --save-dev koa-ejs

用法:

const ejs = require('koa-ejs');
const Koa = require('koa');
const app = new Koa();
ejs(app,{
    root:'./view',
    layout:false,
    viewExt:'html'
});

koa-ejs参数配置

  • root:模板文件根目录
  • layout:全局模板文件,设置为false禁用全局布局
  • viewExt:指定模板文件后缀名
  • cache:缓存编译模板,默认为true
  • debug:是否开启debug调试,默认为false

语法:

  1. 判断语句 <% if(...){ %><% } %>

  2. 变量输出<%= 变量名 %>

  3. 循环语句

    <% list.forEach(function(item){ %>
          <p><%= item.title %></p>
    <% }) %>
    

路由 koa-router

npm install --save-dev koa-router

用法:

const Koa = require('koa');
const Router = require('koa-router');
const router = new Router();
const app = new Koa();
router.get('/',async (ctx,next) => {
    ctx.body = {
        msg:'hello'
    }
})
app.use(router.routes())

API:

  1. router.get()
  2. router.post()
  3. router.put()
  4. router.del()
  5. router.all()

传递参数和接收参数

router.all('/a/:id',(ctx,next) => {
    console.log(ctx.params)		//ctx.params接收参数
    ctx.body = 'dso';
})

网络请求 request

npm install --save-dev request

用法:

request('http://www.google.com',(err,response,body) => {
    if(response.statusCode === 200){
        console.log(body)
    }else{
        console.error(error)
    }
})

如上代码可以很方便的请求一个域名的信息

使用promise特性封装请求,解决异步回调的问题,在utils文件下创建request.js文件,输入以下代码

const request = require('request');
const iconv = require('iconv-lite');

const requestPromise = (url) => {
    return new Promise((resolve,reject) => {
        request(url,{encoding:null},(err,response,body) => {
            if(response.statusCode === 200){
                const bufs = iconv.decode(body,'gb2312');
                const html = bufs.toString('uft8');
                resolve(html);
            }else{
                reject(err)
            }
        })
    })
}

module.exports = requestPromise;

上述代码中有一行const iconv = require('iconv-lite');这里所使用到的npm包是解决请求回来的数据可能出现乱码问题的。 既然我们使用到了它,当然需要先引入它

npm install --save-dev iconv-lite

有可能元网站的charset设置的不是utf8编码,那么我们取回来的页面信息,中文会是乱码的。 此时我们需要使用这个包来处理取回来的网页信息。

const bufs = iconv.decode(body,'gb2312');
const html = bufs.toString('uft8');

cheerio

cheerio可以想jquery一样操作DOM元素,需要对网页信息进行分析,哪些信息是我们所需要的,比如我们需要 文章的标题信息、文章列表等等。我们就可以使用cheerio操作DOM元素进行筛选。

npm install --save-dev cheerio

用法:

const cheerio = require('cheerio');

const $ = cheerio.load(html);

//选择器 找对目标元素 遍历
$("body > div.row.inner-row > div.row-left > div.list-base-article > ul > li a").each((i,item) => {
    const textStr = $(item).text()

})

需求代码

上面篇幅介绍了完成该需求所涉及到的一些技能点后,下面就开始正式撸代码啦。

流程

  1. 确定爬取目标域名
  2. 查看所需要爬取的信息所在的DOM元素信息标识
  3. 根据DOM元素信息标识筛选目标信息
  4. ajax请求得到目标信息渲染页面

入口文件index.js,配置静态文件,引入页面路由,api接口路由

const koa = require('koa')
const path = require('path')
const render = require('koa-ejs');
const static = require('koa-static');
const parser = require('koa-bodyparser');

const home =  require('./router/home');
const qinggan = require('./api/index')

// koa
const server = new koa();

server.use(parser());

render(server,{
    root:path.join(__dirname,'view'),
    layout:false,
    viewExt:'html'
});

server.use(static(__dirname+'/static'));

// router
server.use(home.routes());
server.use(qinggan.routes());


server.listen(3000);

api 接口index.js,定义前端请求的接口地址,处理爬取的目标信息

const Router = require('koa-router');
const cheerio = require('cheerio');
const requestPromise = require('../utils/request');

const router = new Router({
    prefix:'/api'
});

const host = 'https://www.duanwenxue.com'

// https://www.duanwenxue.com/sanwen/shuqing/

// https://www.duanwenxue.com/jingdian/shenghuo/

// https://www.duanwenxue.com/qinggan/meiwen/

// https://www.duanwenxue.com/sanwen/suibi/

//https://www.duanwenxue.com/shanggan/ganrengushi/

router.post('/getQinggan',async (ctx,next) => {
    const {website,keywords} = ctx.request.body;
    const html = await requestPromise(website);
    const $ = cheerio.load(html);

    let arr = []
    $("body > div.row.inner-row > div.row-left > div.list-base-article > ul > li a").each((i,item) => {
        const textStr = $(item).text()

        if(textStr.indexOf(keywords) > -1){
            arr.push({
                src:host + $(item).attr('href'),
                name:$(item).text()
            })
        }
    })

    ctx.body = {
        data:arr
    }
})
module.exports = router;

模板文件home.html,模板文件中使用ajax技术请求接口地址

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/index.css">
</head>
<body>
    
    <% if(name){ %>
        <h1><%= name %></h1>
    <% } %>
    <% list.forEach(function(item){ %>
        <p><%= item.title %></p>
    <% }) %>
    <div class="wrapper">
        <p class="input-item">
            <input type="text" class="website" placeholder="请输入网址">
        </p>
        <p class="input-item">
            <input type="text" class="keywords" placeholder="请输入关键词">
        </p>
        <p class="input-item">
            <button class="btn">点击</button>
        </p>
    </div>

    <div class="wrapper-data">

    </div>

    <script src='js/jquery.1.8.2.min.js'></script>
    <script>
        $('.btn').click(function(){
            const param = {
                website:$('.website').val()
            }

            $('.wrapper-data').html('');
            $.ajax({
                url:'http://localhost:3000/api/getQinggan',
                type:'post',
                data:{
                    website:$('.website').val(),
                    keywords:$('.keywords').val()
                },
                dataType:'json',
                success:function(res){
                    var html = '';
                    res.data.forEach(item => {
                        html += `<p><a href="${item.src}">${item.name}</a></p>`
                    })

                    $(".wrapper-data").append(html)
                }
            })
        })
    </script>
</body>
</html>

以上,把自己学习的知识点做个总结,实现一个简单的网页爬虫,不足之处请各位大佬指正。虚心学习,快乐进步。
点击这里看项目源代码 欢迎star

posted on 2020-07-14 11:09  乘风归去来  阅读(185)  评论(0)    收藏  举报

导航