Node.js实现网络爬虫

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

 

文章目录

  • 前言
  • 一、必要工具安装
  • 二、爬取前操作
  • 三、爬取新闻数据
  • 四、建立个人网页展示爬取内容
  • 总结

 


前言

网络爬虫是按照一定规则自动获取网络信息数据的一种程序

本次爬虫实验项目目标是选取新闻网站建立爬虫,对新闻页面进行分析,爬取出编码、标题、作者、时间、关键词、摘要、内容、来源等结构化信息并存储在数据库中,再建立个人网页提供对爬取内容的分项全文搜索。

 

一、必要工具安装

1.Node.js安装

Node.js是一个让 JavaScript 运行在服务端的开发平台,本次要使用Node.js实现网络爬虫。

官方网址https://nodejs.org/en/

选择合适的版本下载,然后不断next到选定地址安装。

判断安装成功:打开cmd,输入node -v与npm -v,若输出版本号即表示安装成功。

2.安装vscode插件

打开vscode应用商城下载node.js相关插件

3.安装数据库

这里我下载了phpstudy,使用里面自带的数据库进行后续操作

二、爬取前操作

为了使后端代码更加规范,这里使用了express框架

创建reptile文件夹存放代码模块等,用cmd运行express reptile来创建后端express项目

然后进入reptile目录下运行npm install,安装依赖包,生成package.json与package-lock.json。

打开package.json文件,修改node为nodemon,使得代码每次修改后自动重新启动服务器,之后安装nodemon模块并启动服务器。

成功创建express项目:

之后需创建爬虫路由,先创建爬虫代码(newsList.js)并在app.js中添加代码

var newsListRouter = require('./routes/newsList');

app.use('/newsList', newsListRouter)

页面内容如下:

var express = require('express');

var router = express.Router();

/* GET users listing. */

router.get('/', function(req, res, next) {

    res.send('reptile List');

});

module.exports = router;

添加爬虫需要的模块,通过npm install… -s 安装

其中cheerio是模块库,可从html的片断中构建DOM结构,然后提供像jquery一样的css选择器查询,快速、灵活、实施的jQuery核心实现。

request也是一个node.js的模块库,用于获取网页内容,即页面数据请求模块。

let cheerio = require('cheerio'); //爬虫模块

var request = require('request') //页面数据请求模块

const uk = require("unique-keygen")//生成唯一id,作为数据库id

接下来创建数据库连接,将之后爬取的新闻数据保存到数据库中

const mysql = require('mysql');

const pool = mysql.createPool({

    host: "localhost",//数据库主机

    user: "root",//用户名

    password: "root",//密码

    database: "news"//数据库名

});



function query(sql, params, callback) {

    pool.getConnection(function(err, connection) {

        if (err) {

            console.log('数据库连接出错:' + err)

            return

        }

        connection.query(sql, params, function(err, result) {

            if (err) {

                console.log('数据库查询出错:' + err)

                return

            }

            callback(err, result);

        })

        connection.release(); //释放

    })

}

exports.query = query;

三.爬取新闻数据

现在要正式开始爬取新闻数据了,先安装需要的包

可通过npm install...进行安装

若之后运行显示Error: Cannot find module 'XXX'时,说明没有安装

本项目选取了网易新闻、腾讯新闻与新浪新闻三个网站作为爬取对象,爬取方式近乎相同,这里以新浪新闻为例:

http://culture.sina.cn/

打开网页源代码分析页面结构

然后使用cheerio与request模块获取内容,爬取内容的同时将数据存至mysql,数据库表:

爬虫代码如下:

//新浪新闻

router.get('/xinlang_new', (req, res) => {

    let url = 'https://culture.sina.cn/'

    request({

        method:'GET',    

        url:url,   

        },function (error, response, body) {

            if (!error && response.statusCode == 200) {

                console.log(body);

                var $ = cheerio.load(body);

                var newsList = $('.card_module section')

 var sql = `insert into news(id,title,detailLink,img,keyWords,type,source,publishTime) values(?,?,?,?,?,?,?,?)`

                new Promise((resolve, reject) => {

                    newsList.each((i, ele) => {

                        var $ = cheerio.load(ele)

                        let id = uk(8)

                        let title = $('.m_f_con h2').text()

                        let source = $('.m_f_con_add').text()

                        let time = moment().format('YYYY-MM-DD HH:mm:ss')

                        let describe = ''

                        let img = $('section a img').attr('data-src') == undefined ? '' : $('section a img').attr('data-src')

                        let link = $('section a:first').attr('href')

                        db.query(sql, [id, title, link, img, describe, source, source, time], (err, row) => {

                            if (err) {

                                console.log(err)

                                return

                            }

                            console.log(row.affectedRows)

                        })

                        console.log(link)

                    })

                    resolve()

                }).then(() => {

                    res.send({

                        flag: true,

                        msg: "爬取完毕"

                    })

                })

            }else{

                console.log("error");

            }

        });

})

此外为了防止新闻网站屏蔽爬虫,需要进行伪装

function request(url, callback) {
    var options = {
        url: url,
        encoding: null,
        headers: headers,
        timeout: 10000 
    }
    myRequest(options, callback)
}

在页面执行:http://localhost:8880/newsList/xinlang_new,就开始自动爬取信息并保存到数据库中

 

四.建立个人网页展示爬取内容

如此爬取完网易腾讯新浪三个新闻网站后,需要建立个人网站展示爬取内容。

创建reptitle目录,并引入bootstrap文件和jquery,然后创建index.html

静态页面代码:

<!doctype html>

<html>

<head>

    <meta charset="utf-8">

    <title>XXX的爬虫网页</title>

</head>

<link rel="stylesheet" href="css/bootstrap.min.css">

<script src="js/jquery-3.5.0.js"></script>

<script src="js/bootstrap.min.js"></script>

<body>

    <div class="container" id="container">

        <div class="jumbotron py-5">

            <h1>XXX的爬虫网页</h1>

        </div>

        <!--搜索-->

        <div style="padding: 30px 0px;">

            <form class="bs-example bs-example-form" role="form">

                <div class="row">

                    <div class="col-lg-6">

                        <div class="input-group">

                            <input type="text" id="keyWord" class="form-control" placeholder="请输入搜索关键词">

                            <span class="input-group-btn">

                                <button class="btn btn-success" type="button" onclick="search()">搜索</button>

                            </span>

                            <span class="input-group-btn px-3">

                                <button class="btn btn-success" type="button" onclick="update()">刷新</button>

                            </span>

                        </div>

                    </div>

                </div>

            </form>

        </div>

        <div class="w-100">

            <div id="list" class="w-75 card px-2">

                <h2 class="fw-bolder py-3">新闻列表</h3>

                    <ul>

                        <!-- <a id="link" href="https://culture.sina.cn/2021-03-22/detail-ikkntiam6259503.d.html?vt=4">

                    <div class="new_list">

                        <div class="item-img">

                            <img id="item-img" src="https://k.sinaimg.cn/n/news/transform/56/w550h306/20210331/e901-knaqvqn7373581.png/w160h120l1t12b3.jpg" alt="">

                        </div>

                        <div class="item-right">

                            <div class="title">

                                <p>学的不仅是技术,更是梦想学的不仅是技术,更是梦想!学的不仅是技术,更是梦想!!</p>

                            </div>

                            <div class="item-foot">

                                <p class="">来源:腾讯新闻</p>

                                <p class="">2021-03-30 22:48:21</p>

                            </div>

                        </div>

                    </div>

                      </a> -->

                    </ul>

            </div>

        </div>

    </div>

</body>

</html>

再使用ajax向后台异步请求数据,然后使用jquery动态把内容显示到页面

var page = 1 //页码

    function getNews() {

        $.ajax({

            url: "http://localhost:8880/client_news/get_news?page=" + page,

            type: "get",

            success: function(obj) {

                //把数据放到数组中

                var data = obj.data

                console.log(obj)

                const list = document.getElementById('list')

                for (let i = 0; i < data.length; i++) {

                    //添加结点

                    const a = document.createElement('a');

                    const new_list = document.createElement('div');

                    const item_img = document.createElement('div');

                    const ul = document.createElement('ul')

                    const img = document.createElement('img');

                    const item_right = document.createElement('div');

                    const title = document.createElement('div');

                    const item_foot = document.createElement('div');

                    const source = document.createElement('p');

                    const time = document.createElement('p');

                    const hr = document.createElement('hr');

                    //给结点添加内容

                    a.href = data[i].detailLink

                    img.src = data[i].img

                    title.innerHTML = data[i].title

                    source.innerHTML = data[i].source

                    time.innerHTML = crtTimeFtt(data[i].publishTime)



                    a.appendChild(new_list)

                    new_list.appendChild(item_img)

                    new_list.appendChild(item_right)

                    item_img.appendChild(img)

                    item_right.appendChild(title)

                    item_right.appendChild(item_foot)

                    item_foot.appendChild(time)

                    item_foot.appendChild(source)

                    item_right.appendChild(item_foot)

                    ul.appendChild(a)

                    ul.appendChild(hr)

                    list.appendChild(ul)



                    //给结点添加样式

                    addClass(new_list, 'new_list')

                    addClass(item_img, 'item-img')

                    addClass(item_foot, 'item-foot')

                    addClass(item_right, 'item-right')

                    addClass(title, 'title')



                }

            },

            error: function(obj) {

                console.log(obj)

            }

        });

}

    //添加样式

    function addClass(ele, str) {

        if (ele.className) {

            var oriName = ele.className;

            var newClass = oriName + "" + str;

            ele.className = newClass;



        } else {

            ele.className = str;

        }

    }

类似于创建newsList路由,现创建client_news.js来使后台服务器获取数据并返回前端

const { query } = require('express');

var express = require('express');

var router = express.Router();

var db = require('../db/db')

    /* GET users listing. */

router.get('/', function(req, res, next) {

    res.send('respond with a resource');

});



router.get('/get_news', (req, res) => {

    let page = req.query.page

    if (page == 1) {

        var pageIndex = 0

    } else {

        var pageIndex = (page - 1) * 10 + 1

    }

    let sql = `select * from news order by publishTime DESC limit ${pageIndex},10`

    db.query(sql, (err, data) => {

        if (err) {

            console.log(err)

            return

        } else if (data.length > 0) {

            res.send({

                flag: true,

                data: data

            })

        } else {

            res.send({

                flag: false,

                data: '没有更多数据'

            })

        }

    })

})

module.exports = router;

页面打开后执行getNews函数,最后呈现的页面效果:

 

接下来要实现网页搜索功能

//搜索

router.post('/searchNews', (req, res) => {

    let { keyWords } = req.body

    console.log(req.body)

    keyWords = "%" + keyWords + "%"

    let sql = `select * from news where title like '${keyWords}' or keyWords like '${keyWords}'`

    db.query(sql, (err, data) => {

        if (err) {

            console.log(err)

            return

        } else if (data.length > 0) {

            console.log(data)

            res.send({

                flag: true,

                data: data

            })

        } else {

            res.send({

                flag: false,

                msg: "没有更多数据"

            })

        }

    })

})

搜索后台代码:

//搜索

router.post('/searchNews', (req, res) => {

    let { keyWords } = req.body

    console.log(req.body)

    keyWords = "%" + keyWords + "%"

    let sql = `select * from news where title like '${keyWords}' or keyWords like '${keyWords}'`

    db.query(sql, (err, data) => {

        if (err) {

            console.log(err)

            return

        } else if (data.length > 0) {

            console.log(data)

            res.send({

                flag: true,

                data: data

            })

        } else {

            res.send({

                flag: false,

                msg: "没有更多数据"

            })

        }

    })

})

还要实现页面滚动到底加载更多数据

  //滚动到底部加载更多信息

    $(window).scroll(function() {

        var scrollTop = $(this).scrollTop();

        var scrollHeight = $(document).height();

        var windowHeight = $(this).height();

        if (scrollTop + windowHeight+50>scrollHeight) {

            page += 1

            if (!isSearch) {

                getNews()

            }

        }

        console.log("lower")

    });

效果如下

最后要实现能够刷新页面

  //刷新

    var isSearch = false //是否有进行搜索操作

    function update() {

        isSearch = false

        getNews()

    }

如此就实现了可搜索、刷新的新闻页面,项目基本完成

 


总结

基本了解了实现网络爬虫的步骤及部分原理,但对代码的具体编写仍有所欠缺,部分代码参考了老师以及网上的内容。css方面知识尤其欠缺使得网页略单调,并且使用了express框架(要求中尽量不使用框架)。感觉爬取数据本身难度不是很大,主要是后续难度较大且过程繁琐,从网上查阅了很多爬虫案例和代码才得以实现,日后仍需加强对这部分的练习理解。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值