爬虫期末作业


基于第一个项目爬虫爬取的数据,完成数据展示网站。
在这里插入图片描述


一、基本要求

1.用户可注册登录网站,非注册用户不可登录查看数据

这里有几个分任务:

(1)前端建立登录和注册网页(运用html和css)

我学习了一波大神分享的网页设置,做了个动态毛玻璃样式的网页:

在这里插入图片描述
底下框起来的两行分别是 找回密码 和 注册账号,

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Glassmorphism Login Form</title>
    <link rel="stylesheet" href="style.css">
    <script type="text/javascript" src="login.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</head>
<body>
    <section>
        <div class="color"></div>
        <div class="color"></div>
        <div class="color"></div>
        <div class="box">
            <div class="square" style="--i:0;"></div>
            <div class="square" style="--i:1;"></div>
            <div class="square" style="--i:2;"></div>
            <div class="square" style="--i:3;"></div>
            <div class="square" style="--i:4;"></div>

            <div class="container">
                <div class="form">
                    <h2>Login Form</h2>
                    <form>
                        <div class="inputBox">
                            <input id="uname" type="text" name="user" placeholder="Username">
                        </div>
                        <div class="inputBox">
                            <input id="upass" type="password" name="psw" placeholder="Password">
                        </div>
                        <div class="inputBox">
                            <input type="submit" value="Login">
                        </div>
                        <p class="forget">Forget password ? <a href="#">Click Here</a></p>
                        <p class="forget">Don't have an account ? <a href="sign.html">Sign up</a></p>
                    </form>
                </div>
            </div>
        </div>
    </section>
</body>
</html>

点击注册账号的话会转入注册界面👇

在这里插入图片描述
主要提供了输入用户名和密码部分的输入框以及一个注册按钮。

sign.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>注册界面</title>
    <script type="text/javascript" src="login.js"></script>
    <link rel="stylesheet" href="style.css">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</head>
<body>
    <section>
        <div class="color"></div>
        <div class="color"></div>
        <div class="color"></div>
        <div class="box">
            <div class="square" style="--i:0;"></div>
            <div class="square" style="--i:1;"></div>
            <div class="square" style="--i:2;"></div>
            <div class="square" style="--i:3;"></div>
            <div class="square" style="--i:4;"></div>

            <div class="container">
                <div class="form">
                    <h2>Signup Form</h2>
                    <form>
                        <div class="inputBox">
                            <input id="uname" type="text" name="user" placeholder="Create username">
                        </div>
                        <div class="inputBox">
                            <input id="upass" type="password" name="psw" placeholder="Password">
                        </div>
                        <div id="error_box"></div>
                        <div class="inputBox">
                            <input type="submit" value="Sign up" onclick="Regist()" class="btn btn-primary">
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </section>
</body>
</html>

(css的具体代码实现放在文件夹里了)

(2)后端实现
/*
在点击注册按钮之后,会调用Regist函数,函数全部存储在login.js中。
会先检查用户名以及用户密码的长度,是否符合规范,如果不符合,则会进行提示,并且之间返回。
代码如下:
*/
var oUname = document.getElementById("uname");
var oUpass = document.getElementById("upass");
var oError = document.getElementById("error_box")
var isError = true;
console.log(oUname.value);

if (oUpass.value.length > 10 || oUpass.value.length < 3) {
    oError.innerHTML = "密码请输入6-20位字符"
    isError = false;
    return;
}
if (oUname.value.length > 10 || oUname.value.length < 3) {
    oError.innerHTML = "用户名请输入3-10位字符";
    isError = false;
    return;
}

/*
检查之后,将表单进行提交提交,代码如下:
*/
var params = '/process_regist';
$.post(params, {name: oUname.value,passwd: oUpass.value},function(text, status) {
    console.log(text);
    JSON.parse(text, function(k,v) {
        if(v == true) {
            window.alert("注册成功");
        }else{
            window.alert("已经注册过");
        }
        window.location.href = "login.html";
        // location.reload();
    })
})

相关js操作插入在html里:

<!--    <script src="../node_modules/angular/angular.min.js"></script>-->
    <script src="/angular/angular.min.js"></script>

<!--    引入自己的样式与js-->
<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
<script type="text/javascript" src="javascripts/users.js"></script>
<script>
    var app = angular.module('login', []);
    app.controller('loginCtrl', function ($scope, $http, $timeout) {

        // 登录时,检查用户输入的账户密码是否与数据库中的一致
        $scope.check_pwd = function () {
            var data = JSON.stringify({
                username: $scope.username,
                password: $scope.password
            });
            $http.post("/users/login", data)
                .then(
                function (res) {
                    if(res.data.msg=='ok') {
                        window.location.href='/news.html';
                    }else{
                        $scope.msg=res.data.msg;
                    }
                },
                    function (err) {
                    $scope.msg = err.data;
                });

        };
        //增加注册用户
        $scope.doAdd = function () {
            // 检查用户注册时,输入的两次密码是否一致
            if($scope.add_password!==$scope.confirm_password){
                // $timeout(function () {
                //     $scope.msg = '两次密码不一致!';
                // },100);
                $scope.msg = '两次密码不一致!';
            }
            else {
                var data = JSON.stringify({
                    username: $scope.add_username,
                    password: $scope.add_password
                });
                $http.post("/users/register", data)
                    .then(function (res) {
                        if(res.data.msg=='成功注册!请登录') {
                            $scope.msg=res.data.msg;
                            $timeout(function () {
                                window.location.href='index.html';
                            },2000);

                        } else {
                            $scope.msg = res.data.msg;
                        }
                    }, function (err) {
                        $scope.msg = err.data;
                    });
            }
        };
    });
</script>

之后会用users.js调用信息:

var express = require('express');
var router = express.Router();
var userDAO = require('../dao/userDAO');

router.post('/login', function(req, res) {
  var username = req.body.username;
  var password = req.body.password;
  // var sess = req.session;

  userDAO.getByUsername(username, function (user) {
    if(user.length==0){
      res.json({msg:'用户不存在!请检查后输入'});

    }else {
      if(password===user[0].password){
        req.session['username'] = username;
        res.cookie('username', username);
        res.json({msg: 'ok'});
        // res.json({msg:'ok'});
      }else{
        res.json({msg:'用户名或密码错误!请检查后输入'});
      }
    }
  });
});


/* add users */
router.post('/register', function (req, res) {
  var add_user = req.body;
  // 先检查用户是否存在
  userDAO.getByUsername(add_user.username, function (user) {
    if (user.length != 0) {
      // res.render('index', {msg:'用户不存在!'});
      res.json({msg: '用户已存在!'});
    }else {
      userDAO.add(add_user, function (success) {
        res.json({msg: '成功注册!请登录'});
      })
    }
  });

});

// 退出登录
router.get('/logout', function(req, res, next){
  // 备注:这里用的 session-file-store 在destroy 方法里,并没有销毁cookie
  // 所以客户端的 cookie 还是存在,导致的问题 --> 退出登陆后,服务端检测到cookie
  // 然后去查找对应的 session 文件,报错
  // session-file-store 本身的bug

  req.session.destroy(function(err) {
    if(err){
      res.json('退出登录失败');
      return;
    }

    // req.session.loginUser = null;
    res.clearCookie('username');
    res.json({result:'/index.html'});
  });
});

module.exports = router;

(注意要保存session信息,不然记录用户操作日志时,不知道是哪位用户进行的操作。示例的session信息只保存在启动网站内存中,所以网站重启后信息丢失;也可以新建数据库保存session信息。)【这里的session存在app.js里】

在这里插入图片描述

然后调用到userDAO.js:

var mysql = require('mysql');
var mysqlConf = require('../conf/mysqlConf');
var userSqlMap = require('./userSqlMap');
var pool = mysql.createPool(mysqlConf.mysql);
// 使用了连接池,重复使用数据库连接,而不必每执行一次CRUD操作就获取、释放一次数据库连接,从而提高了对数据库操作的性能。

module.exports = {
    add: function (user, callback) {
        pool.query(userSqlMap.add, [user.username, user.password], function (error, result) {
            if (error) throw error;
            callback(result.affectedRows > 0);
        });
    },
    getByUsername: function (username, callback) {
        pool.query(userSqlMap.getByUsername, [username], function (error, result) {
            if (error) throw error;
            callback(result);
        });
    },

};


2.用户注册、登录、查询等操作记入数据库中的日志

在这里插入图片描述
在这里插入图片描述

先在mysql里建两个表,分别用来存用户信息和日志信息,其中用户信息表中存储了用户名以及用户的密码,日志中存储了用户名、操作时间和具体操作。

在这里插入图片描述


3.爬虫数据查询结果列表支持分页和排序

这里用到了Bootstrap Table : https://www.bootstrap-table.com.cn/doc/getting-started/introduction/ 👈学习地址。
一定记得在代码最上面header里加上:

    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">

在代码最下面script下方加上:

    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>

在这里插入图片描述

(除了在查询的时候进行排序,还可以通过bootstrap table 提供了一个前端排序的方法,用户能够通过指定列旁边的小箭头,来对该列值进行升序或降序排序)

$('#record2').bootstrapTable({
   url:params,
   method:'GET',
   pagination:true,
   sidePagination:'client',
   pageSize:5,
   striped : true,
   sortable : true,
   sortOrder:"asc",
   showRefresh:true,
   search:true,
   showToggle: true,
   toolbar: '#toolbar',
   showColumns : true,
   columns:[{
       field :'url',
       title : 'url',
       sortable : true
   }, {
       field:'title',
       title:'title'
   }, {
       field:'source_name',
       title:'source_name',
       sortable : true
   },{
       field:'author',
       title:'author'
   },{
       field:'publish_date',
       title:'publish_date',
       sortable : true

   }]
})

整体代码:

    <form>
        <!-- <marquee><font color="#8B008B">建议查询: 新闻/中国...</font></marquee> -->
        <body background="2.jpg"
            style=" background-repeat:no-repeat ;
            background-size:100% 100%;
            background-attachment: fixed;"
        >
        <br> 
        <select class="SearchOptions" name = "sort" id = "sortid" style ="float: left; ">
            <option value="title">标题 (title)</option>
            <option value="keywords">新闻来源 (author)</option>
            <option value="publish_time">发布日期 (publish_date)</option>
            <option value="source_name">内容 (content)</option>
        </select>
        <div class="container" style ="float: left; width: 100%;">
            <form action="" class="parent">
                <input type="text" class="search" name="title_text" placeholder="请输入查询关键字" style="border-radius: 8px; ">
                <input type="button" class="form-submit" style = "float:left; " value="查询">
            </form>
        </div>

    </form>

在这里插入图片描述
👆基础的表格结果展示

<script>
        $(document).ready(function() {
            $.get('/check', function(data) {
                console.log(data);
                if(data == false) {
                    window.alert("用户未登录");
                    window.location.href = "login.html";
                }
            });

            $("input:button").click(function() {
                var title = $("input:text").val();
                var sort = $('#sortid').val();
                console.log("title = " + title);
                console.log("sort = " + sort);
                var params = '/process_get?title=' + $("input:text").val() + '&sort=' + sort +'&order=asc';

                $(function(){
                    console.log(params);
                    $("#record2").empty();
                    $('#record2').bootstrapTable({
                        url:params,
                        method:'GET',
                        pagination:true,
                        sidePagination:'client',
                        pageSize:5,
                        striped : true,
                        sortable : true,
                        sortOrder:"asc",
                        showRefresh:true,
                        search:true,
                        showToggle: true,
                        toolbar: '#toolbar',
                        showColumns : true,
                        columns:[{
                            field :'url',
                            title : 'url',
                            sortable : true
                        }, {
                            field:'title',
                            title:'title'
                        }, {
                            field:'source_name',
                            title:'source_name',
                            sortable : true
                        },{
                            field:'author',
                            title:'author'
                        },{
                            field:'publish_time',
                            title:'publish_time',
                            sortable : true

                        }]
                    })
                });
            });

        });
    </script>

👆通过js来以表格的形式显示数据
(通过GET方法访问给定的url,并且将返回的json文件,解析生成表格,注意下面field的值应该和返回的json文件对应属性的keyvalue相同。)

下面就是运行search.html后的结果:

在这里插入图片描述
查询总页面👆


在这里插入图片描述

这里可以选择要从哪里寻找查询关键字👆


在这里插入图片描述

这里可以分页查询👆


在这里插入图片描述

这里是鼠标移到相应新闻上会有加暗效果出现👆


在这里插入图片描述

这里可以选择查询表格里显示哪些表头👆


在这里插入图片描述

这里选择一页里包括多少条新闻行数👆


在这里插入图片描述

如果按下右上角那个Toggle,可以更改页面样式,由纵分割变成横分割👆


在这里插入图片描述
👆对 index.js 做的相应更改!!【这里一定记住要改,我一开始就是忘记了这块儿,一直显示不出来数据 /(ㄒoㄒ)/~~】


4.用Echarts或者D3实现3个以上的数据分析图表展示在网站中

这里我用ECharts来实现:下载地址

实现四个图的展示代码放在news.js里:

    $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;
                });

    };
    $scope.pie = function () {
        $scope.isShow = false;
        $http.get("/news/pie").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    let newdata = [];

                    var pattern = /责任编辑:(.+)/;//匹配名字
                    res.data.result.forEach(function (element) {
                        // "x":  责任编辑:李夏君 ,对x进行处理,只取 名字
                        newdata.push({name: pattern.exec(element["x"])[1], value: element["y"]});

                    });

                    var myChart = echarts.init(document.getElementById('main1'));
                    var app = {};
                    option = null;
                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '作者发布新闻数量',
                            x: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: "{a} <br/>{b} : {c} ({d}%)"
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left',
                            // data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
                        },
                        series: [
                            {
                                name: '访问来源',
                                type: 'pie',
                                radius: '55%',
                                center: ['50%', '60%'],
                                data: newdata,
                                itemStyle: {
                                    emphasis: {
                                        shadowBlur: 10,
                                        shadowOffsetX: 0,
                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
                                    }
                                }
                            }
                        ]
                    };
                    // myChart.setOption(option);
                    app.currentIndex = -1;

                    setInterval(function () {
                        var dataLen = option.series[0].data.length;
                        // 取消之前高亮的图形
                        myChart.dispatchAction({
                            type: 'downplay',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                        app.currentIndex = (app.currentIndex + 1) % dataLen;
                        // 高亮当前图形
                        myChart.dispatchAction({
                            type: 'highlight',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                        // 显示 tooltip
                        myChart.dispatchAction({
                            type: 'showTip',
                            seriesIndex: 0,
                            dataIndex: app.currentIndex
                        });
                    }, 1000);
                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                    ;
                }
            });
    };
    $scope.line = function () {
        $scope.isShow = false;
        $http.get("/news/line").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    var myChart = echarts.init(document.getElementById("main1"));
                    option = {
                        title: {
                            text: '"疫情"该词在新闻中的出现次数随时间变化图'
                        },
                        xAxis: {
                            type: 'category',
                            data: Object.keys(res.data.result)
                        },
                        yAxis: {
                            type: 'value'
                        },
                        series: [{
                            data: Object.values(res.data.result),
                            type: 'line',
                            itemStyle: {normal: {label: {show: true}}}
                        }],

                    };

                    if (option && typeof option === "object") {
                        myChart.setOption(option, true);
                    }
                }

            });
    };
    $scope.wordcloud = function () {
        $scope.isShow = false;
        $http.get("/news/wordcloud").then(
            function (res) {
                if(res.data.message=='url'){
                    window.location.href=res.data.result;
                }else {
                    var mainContainer = document.getElementById('main1');

                    var chart = echarts.init(mainContainer);

                    var data = [];
                    for (var name in res.data.result) {
                        data.push({
                            name: name,
                            value: Math.sqrt(res.data.result[name])
                        })
                    }

                    var maskImage = new Image();
                    maskImage.src = './images/logo.png';

                    var option = {
                        title: {
                            text: '所有新闻内容 jieba分词 的词云展示'
                        },
                        series: [{
                            type: 'wordCloud',
                            sizeRange: [12, 60],
                            rotationRange: [-90, 90],
                            rotationStep: 45,
                            gridSize: 2,
                            shape: 'circle',
                            maskImage: maskImage,
                            drawOutOfBound: false,
                            textStyle: {
                                normal: {
                                    fontFamily: 'sans-serif',
                                    fontWeight: 'bold',
                                    // Color can be a callback function or a color string
                                    color: function () {
                                        // Random color
                                        return 'rgb(' + [
                                            Math.round(Math.random() * 160),
                                            Math.round(Math.random() * 160),
                                            Math.round(Math.random() * 160)
                                        ].join(',') + ')';
                                    }
                                },
                                emphasis: {
                                    shadowBlur: 10,
                                    shadowColor: '#333'
                                }
                            },
                            data: data
                        }]
                    };

                    maskImage.onload = function () {
                        // option.series[0].data = data;
                        chart.clear();
                        chart.setOption(option);
                    };

                    window.onresize = function () {
                        chart.resize();
                    };
                }

            });
    }

记住要在项目文件夹下cmd运行node bin/www,我第一次运行出了错误,用npm install xxx(你的报错)就解决了~

在这里插入图片描述
在这里插入图片描述
输入网址:http://127.0.0.1:3000/login.html,发现自己目前还没有账号,于是选择注册账号,转到注册页面:/sign.html。
注册成功之后会再次转回登陆界面,输入刚刚填写的名称和密码就可以进入查询主页了。
此时数据库会记录你的注册信息:

在这里插入图片描述
在这里插入图片描述
查询界面是search.html和news.html的结合
(因为news.html里引入了search.html):

在这里插入图片描述


(前面已经介绍过了search.html的实现效果)
这部分主要介绍转到news.html之后可以进行的操作,那就是选择四种不同的图表来表示出你的查询数据结果。

在这里插入图片描述


柱状图 :
在这里插入图片描述


饼状图 :
在这里插入图片描述

折线图 :
在这里插入图片描述
然后我就遇到了困难,那就是…nodejieba那个词云压根打不开…
这时助教正好在群里发了新的解决方法:

1、把wordcut.js文件替换成以下这个,这个换了一个分词器。

// 载入模块
// var nodejieba = require('nodejieba');
var Segmenter = require('node-analyzer');

//正则表达式去掉一些无用的字符,与高频但无意义的词。
const regex = /[\t\s\r\n\d\w]|[\+\-\(\),\.。,!?《》@、【】"'::%-\/“”]/g;

var wordcut = function(vals) {
    var segmenter = new Segmenter();
    var word_freq = {};
    vals.forEach(function (content){
        var newcontent = content["content"].replace(regex,'');
        if(newcontent.length !== 0){
            // console.log();

            var words = segmenter.analyze(newcontent).split(' ');

            // var words = nodejieba.cut(newcontent);
            words.forEach(function (word){
                word = word.toString();
                word_freq[word] = (word_freq[word] +1 ) || 1;
            });
        };

    });
    return word_freq;
};
exports.wordcut = wordcut;

2、命令行输入npm install node-analyzer -save
在这里插入图片描述

3、freqchange.js中删掉 第2行 var nodejieba = require(‘nodejieba’);
在这里插入图片描述
再运行了一次就成功啦!
(顺便可以检验网站已注册账号的登录和查询情况)

词云 :
在这里插入图片描述


5.实现一个管理端界面,可以查看(查看用户的操作记录)和管理(停用启用)注册用户。

直接在app.js中,引入var logger = require('morgan’);
借助中间件保存的信息

// module.exports = app;
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var logger = require('morgan');
var logDAO = require('./dao/logDAO.js');
// var fs = require('fs');//加了文件操作的模块
// var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), { flag: 'a' });//创建一个写文件流,并且保存在当前文件夹的access.log文件中

// var indexRouter = require('./routes/users');
var usersRouter = require('./routes/users');
var newsRouter = require('./routes/news');


var app = express();

//设置session
app.use(session({
  secret: 'sessiontest',//与cookieParser中的一致
  resave: true,
  saveUninitialized: false, // 是否保存未初始化的会话
  cookie : {
    maxAge : 1000 * 60 * 60, // 设置 session 的有效时间,单位毫秒
  },
}));

// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'ejs');

let method = '';
app.use(logger(function (tokens, req, res) {
  console.log('打印的日志信息:');
  var request_time = new Date();
  var request_method = tokens.method(req, res);
  var request_url = tokens.url(req, res);
  var status = tokens.status(req, res);
  var remote_addr = tokens['remote-addr'](req, res);
  if(req.session){
    var username = req.session['username']||'notlogin';
  }else {
    var username = 'notlogin';
  }

  // 直接将用户操作记入mysql中
  if(username!='notlogin'){
    logDAO.userlog([username,request_time,request_method,request_url,status,remote_addr], function (success) {
      console.log('成功保存!');
    })
  }
  console.log('请求时间  = ', request_time);
  console.log('请求方式  = ', request_method);
  console.log('请求链接  = ', request_url);
  console.log('请求状态  = ', status);
  console.log('请求长度  = ', tokens.res(req, res, 'content-length'),);
  console.log('响应时间  = ', tokens['response-time'](req, res) + 'ms');
  console.log('远程地址  = ', remote_addr);
  console.log('远程用户  = ', tokens['remote-user'](req, res));
  console.log('http版本  = ', tokens['http-version'](req, res));
  console.log('浏览器信息 = ', tokens['user-agent'](req, res));
  console.log('用户 = ', username);
  console.log(' ===============',method);

}, ));


app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/angular', express.static(path.join(__dirname , '/node_modules/angular')));

// app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/news', newsRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  // res.render('error');
});

module.exports = app;

查看用户注册信息:

在这里插入图片描述
查看用户操作信息:

在这里插入图片描述

在这里插入图片描述



二、拓展要求

(因为时间和能力有限,这里先说一下自己的想法好了,日后有机会再回来完善⁽⁽꜀(:3꜂ ꜆)꜄⁾⁾)

1.实现对爬虫数据中文分词的查询

因为不太理解这项任务的具体意思,所以去询问了一下老师,老师说就是对爬虫爬取的文本做中文分词后再做查询,有一些语义不同的查询结果就可以抛弃了,比如“南京市长江大桥”分词结果是“南京市/长江/大桥”,这种情况下查询“市长”就查不到了,而不做分词的时候按照like查询“市长”是可以查到这个语料的。

2.实现查询结果按照主题词打分的排序

估计是按照keyword进行一些相关操作(੭ ᐕ)੭

3.用Elastic Search+Kibana展示爬虫的数据结果

这里可以参考这个博客:干货:Kibana 可视化ElasticSearch数据展示分析


总结

感谢:
https://blog.csdn.net/yc_hong/article/details/105886576
这位大佬的博客!和老师、助教们的帮助与指导,至此web编程课圆满结束!(撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值