天天看点

nodejs爬虫项目(二)

之前已经爬取了多个网站的新闻数据,现在要对这些数据进行整理展示,具体要求如下

nodejs爬虫项目(二)

首先第一步要在final-project文件夹下npm install安装依赖包

这里我在安装过程中遇见了问题,安装一直失败而且安装进度非常慢,百度了一下大体了解到这是从国外的镜像服务器下获取包的资源,所以猜测可能和我家的网络有关。果然,在连接了学校的VPN之后再运行npm install很快就安装完成了(有一说一,移动的网真滴不行)。

nodejs爬虫项目(二)

接下来需要访问之前已经安装好的mysql数据库,新建立两个mysql表用来保存用户的操作日志,具体过程和代码如下

nodejs爬虫项目(二)

具体代码

--创建用户信息数据表 CREATE TABLE

crawl

.

user

(

id

INT UNSIGNED NOT NULL AUTO_INCREMENT,

username

VARCHAR(45) NOT NULL,

password

VARCHAR(45) NOT NULL,

registertime

datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (

id

), UNIQUE KEY

username_UNIQUE

(

username`))

ENGINE=InnoDB DEFAULT CHARSET=utf8;

–记录用户的登陆,查询(具体查询语句)操作

CREATE TABLE

crawl

.

user_action

(

id

INT UNSIGNED NOT NULL AUTO_INCREMENT,

username

VARCHAR(45) NOT NULL,

request_time

VARCHAR(45) NOT NULL,

request_method

VARCHAR(20) NOT NULL,

request_url

VARCHAR(300) NOT NULL,

status

int(4),

remote_addr

VARCHAR(100) NOT NULL,

PRIMARY KEY (

id

))

ENGINE=InnoDB DEFAULT CHARSET=utf8;`

然后需要在项目文件夹下建立mysql配置文件

nodejs爬虫项目(二)

接下来需要完全用户可注册登录网站,非注册用户不可登录查看数据,对于登录和注册时的错误也要有适当的提示,例如登陆时

提示用户名或密码输错,用户不存在,注册时,两次密码不一致,用户已存在或者注册成功跳转登陆页.。

首先是登录页面的代码

nodejs爬虫项目(二)

先引入先引入angular.js,这样登陆成功会跳转到news.html页面,然后是注册页的代码

nodejs爬虫项目(二)

用户可注册登录网站,非注册用户不可登录查看数据这一部分用JavaScript来实现,由于代码比较少,就直接写在登录页的html里了

nodejs爬虫项目(二)

在登录页路由中,首先调用userDAO,然后保存session信息,不然记录用户操作日志时,不知道是哪位用户进行的操作。

nodejs爬虫项目(二)

UserDAO的代码实现以及之前提到的session的设置如下

nodejs爬虫项目(二)
nodejs爬虫项目(二)

注册操作和退出登录的实现,注意退出时清除session

nodejs爬虫项目(二)
nodejs爬虫项目(二)

然后实现查询功能,先写好查询页面的代码,然后在news.html里将其引入

<div class="row" style="margin-bottom: 10px;">
    <label class="col-lg-2 control-label">标题关键字</label>
    <div class="col-lg-3">
        <input type="text" class="form-control" placeholder="标题关键字" ng-model="$parent.title1">
    </div>
    <div class="col-lg-1">
        <select class="form-control" autocomplete="off" ng-model="$parent.selectTitle">
            <option selected="selected">AND</option>
            <option>OR</option>

        </select>
    </div>
    <div class="col-lg-3">
        <input type="text" class="form-control" placeholder="标题关键字" ng-model="$parent.title2">
    </div>
</div>



<div class="row" style="margin-bottom: 10px;">
    <label class="col-lg-2 control-label">内容关键字</label>
    <div class="col-lg-3">
        <input type="text" class="form-control" placeholder="内容关键字" ng-model="$parent.content1">
    </div>
    <div class="col-lg-1">
        <select class="form-control" autocomplete="off" ng-model="$parent.selectContent">
            <option selected="selected">AND</option>
            <option>OR</option>
        </select>
    </div>
    <div class="col-lg-3">
        <input type="text" class="form-control" placeholder="内容关键字" ng-model="$parent.content2">
    </div>
</div>


<div class="form-group">
    <div class="col-md-offset-9">
        <button type="submit" class="btn btn-default" ng-click="search()">查询</button>
    </div>
</div>
           
<table class="table table-striped">
    <thead>
        <tr>
            <td>序号</td>
            <td>标题</td>
            <td>作者</td>
           
<td>关键词</td>
            <td>链接</td>
            <td>发布时间</td>
        </tr>

    </thead>
    <tbody>
    <tr ng-repeat="(key, item) in items">
        <td>{{index+key}}</td>
        <td>{{item.title}}</td>
        <td>{{item.author}}</td>
           
<td>{{item.keywords}}</td>
        <td>{{item.url}}</td>
        <td>{{item.publish_date}}</td>
    </tr>

    </tbody>
</table>

<div class="row">
           
<div class="pull-left" style="margin-top: 12px;">
        <button type="submit" class="btn btn-primary" ng-click="searchsortASC()" >发布时间升序</button>
        <button type="submit" class="btn btn-primary" ng-click="searchsortDESC()">发布时间降序</button>
    </div>
           
<div class="pull-right">
        <nav>
            <ul class="pagination">
                <li>
                    <a ng-click="Previous()" role="button"><span role="button">上一页</span></a>
                </li>
                <li ng-repeat="page in pageList" ng-class="{active:isActivePage(page)}" role="button">
                    <a ng-click="selectPage(page)" >{{ page }}</a>
                </li>
                <li>
                    <a ng-click="Next()" role="button"><span role="button">下一页</span></a>
                </li>
            </ul>
        </nav>
    </div>
</div>
           
nodejs爬虫项目(二)
nodejs爬虫项目(二)

第52行,拼路由,get方法传给后端处理。其中排序是按照发表时间排的,也是传的参数,也在路由中,查询页路由的代码如下

nodejs爬虫项目(二)

用newsDAO.search函数实现查询词支持布尔表达式,主要是拼起sql。

var mysql = require(‘mysql’); var mysqlConf = require(’…/conf/mysqlConf’); var pool =

mysql.createPool(mysqlConf.mysql);

module.exports = {

query_noparam :function(sql, callback) {

pool.getConnection(function(err, conn) {

if (err) {

callback(err, null, null);

} else {

conn.query(sql, function(qerr, vals, fields) {

conn.release(); //释放连接

callback(qerr, vals, fields); //事件驱动回调

});

}

});

},

search :function(searchparam, callback) {

// 组合查询条件

var sql = 'select * from fetches ';

if(searchparam["t2"]!="undefined"){
        sql +=(`where title like '%${searchparam["t1"]}%' ${searchparam['ts']} title like '%${searchparam["t2"]}%' `);
    }else if(searchparam["t1"]!="undefined"){
        sql +=(`where title like '%${searchparam["t1"]}%' `);
    };

    if(searchparam["t1"]=="undefined"&&searchparam["t2"]=="undefined"&&searchparam["c1"]!="undefined"){
        sql+='where ';
    }else if(searchparam["t1"]!="undefined"&&searchparam["c1"]!="undefined"){
        sql+='and ';
    }

    if(searchparam["c2"]!="undefined"){
        sql +=(`content like '%${searchparam["c1"]}%' ${searchparam['cs']} content like '%${searchparam["c2"]}%' `);
    }else if(searchparam["c1"]!="undefined"){
        sql +=(`content like '%${searchparam["c1"]}%' `);
    }

    if(searchparam['stime']!="undefined"){
        if(searchparam['stime']=="1"){
            sql+='ORDER BY publish_date ASC ';
        }else {
            sql+='ORDER BY publish_date DESC ';
        }
    }

    sql+=';';
    pool.getConnection(function(err, conn) {
        if (err) {
            callback(err, null, null);
        } else {
            conn.query(sql, function(qerr, vals, fields) {
                conn.release(); //释放连接
                callback(qerr, vals, fields); //事件驱动回调
            });
        }
    });
},;
           

查询结果的展示

nodejs爬虫项目(二)

第47行,ng-show 是在点击显示图表的时候,先隐藏掉这些查询结果再显示图片;也控制先点击图表,再点击查询的时候,将图表显示隐藏掉,再展示查询结果。

当页面列表的爬虫数据过多时,需要对列表内容进行分页,这边使用了angularjs分页的实现,不需要后台配合,前台一次性拿完所有的数据然后进行分页展示。缺点数据量过大的时候页面加载效率比较低,但界面上对用户更加友好。下面是实现分页的代码。

nodejs爬虫项目(二)
nodejs爬虫项目(二)

初始化的时候,首先要显示第一页的内容,同时算好一共分多少页(75行),pageList是一个最多长为5的数组,表示右下角截图的框里最多展示5个页码。

nodejs爬虫项目(二)

当选中其它页面的时候,由于最多显示五个页面,右下角的页面数字也要随之改变,具体代码实现如下。

nodejs爬虫项目(二)
nodejs爬虫项目(二)

下一步是添加数据分析图表,以柱状图的代码为例

前端代码

$scope.histogram = function () {

$scope.isShow = false;

$http.get("/news/histogram")

.then(

function (res) {

if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {

                    // var newdata = washdata(data);
                    let xdata = [], ydata = [], newdata;

                    var pattern = /\d{4}-(\d{2}-\d{2})/;
                    res.data.result.forEach(function (element) {
                        // "x":"2020-04-28T16:00:00.000Z" ,对x进行处理,只取 月日
                        xdata.push(pattern.exec(element["x"])[1]);
                        ydata.push(element["y"]);
                    });
                    newdata = {"xdata": xdata, "ydata": ydata};

                    var myChart = echarts.init(document.getElementById('main1'));

                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '新闻发布数 随时间变化'
                        },
                        tooltip: {},
                        legend: {
                            data: ['新闻发布数']
                        },
                        xAxis: {
                            data: newdata["xdata"]
                        },

                        yAxis: {},
                        series: [{
                            name: '新闻数目',
                            type: 'bar',
                            data: newdata["ydata"]
                        }]
                    };
                    // 使用刚指定的配置项和数据显示图表。
                    myChart.setOption(option);
                }
            },
            function (err) {
                $scope.msg = err.data;
            });

};
           

路由代码

router.get(’/histogram’, function(request, response) {

//sql字符串和参数

console.log(request.session[‘username’]);

//sql字符串和参数
if (request.session['username']===undefined) {
    // response.redirect('/index.html')
    response.json({message:'url',result:'/index.html'});
}else {
    var fetchSql = "select publish_date as x,count(publish_date) as y from fetches group by publish_date order by publish_date;";
    newsDAO.query_noparam(fetchSql, function (err, result, fields) {
        response.writeHead(200, {
            "Content-Type": "application/json",
            "Cache-Control": "no-cache, no-store, must-revalidate",
            "Pragma": "no-cache",
            "Expires": 0
        });
        response.write(JSON.stringify({message:'data',result:result}));
        response.end();
    });
}
           

});

最后将用户注册、登录、查询等操作记入数据库中的日志,直接在app.js中,引入var logger = require('morgan’);

借助中间件保存的信息

nodejs爬虫项目(二)

保存的操作日志可以在mysql数据库中查询,输入select * from user_faction

nodejs爬虫项目(二)

附上完整的演示

在final_project文件夹下cmd运行node bin/www

nodejs爬虫项目(二)

进入http://localhost:3000/,并进行注册

nodejs爬虫项目(二)

搜索疫情,结果如下

nodejs爬虫项目(二)
nodejs爬虫项目(二)

数据分析图表

nodejs爬虫项目(二)
nodejs爬虫项目(二)
nodejs爬虫项目(二)