项目要求
(基于第一个项目爬虫爬取的数据,完成数据展示网站)
基本要求(必须):
- [√] 用户可注册登录网站,非注册用户不可登录查看数据
- [√] 用户注册、登录、查询等操作记入数据库中的日志
- [√] 爬虫数据查询结果列表支持分页和排序
- [√] 用Echarts或者D3实现3个以上的数据分析图表展示在网站中
- [loading] 实现一个管理端界面,可以查看(查看用户的操作记录)和管理(停用启用)注册用户。
扩展要求(非必须): - 用Elastic Search+Kibana展示爬虫的数据结果
- 实现查询结果按照主题词打分的排序
- [?]实现对爬虫数据中文分词的查询
实现查询结果的分页和排序
排序
在index.js文件中写入
var fetchSql = "select url,source_name,title,author,publish_date " +"from fetches where title like '%" + request.query.title + "%'"+"order by author";
分页
在search.html文件中写入
$.get('/process_get?title=' + $("input[name='title_text']").val()+"&author="+$("input[name='author_text']").val(), function(data) {
$("#record2").bootstrapTable({
search:true, //加上搜索控件
method: 'get', //请求方式(*)
pagination: true, //是否显示分页(*)
striped: true, //是否显示行间隔色
uniqueId: "userId", //每一行的唯一标识,一般为主键列
pageSize: 10, //每页的记录行数(*)
sidePagination : 'client',
columns:[{
field:'url', //对应数据库字段名
title:'链接',
},{
field:'source_name',
title:'来源'
},{
field:'title',
title:'标题'
},{
field:'author',
title:'作者'
},{
field:'publish_date',
title:'发布时间',
}],
data: data,
});
});
效果呈现
(ps:keywords不知道哪里出了问题,没有办法对应,嗯,就算是之前提供的参考代码也不可以,所以,就把他省略掉了)
ps:前期在第一次作业时实现了分页和排序(忘了提交 wu~),后面的代码基于老师提供的示例,有些不同。
用户注册与登录
主函数
$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;
});
}
};
<div class="form-group">
<input ng-model="username" tabindex="1" class="form-control" placeholder="Username" value=""/>
</div>
<div class="form-group">
<input type="password" ng-model="password" tabindex="2" class="form-control" placeholder="Password">
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<button id="login-submit" tabindex="4" class="form-control btn btn-login" ng-click="check_pwd()">LOG IN</button>
</div>
</div>
</div>
</form>
<form id="register-form" method="post" role="form" style="display: none;">
<div class="form-group">
<input ng-model="add_username" tabindex="1" class="form-control" placeholder="Username" value=""/>
</div>
<div class="form-group">
<input type="password" ng-model="add_password" tabindex="2" class="form-control" placeholder="Password">
</div>
<div class="form-group">
<input type="password" ng-model="confirm_password" tabindex="2" class="form-control" placeholder="Confirm Password">
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<button tabindex="4" class="form-control btn btn-register" ng-click="doAdd()">Register Now</button>
</div>
</div>
</div>
</form>
用户注册与登录的提示
<div id="head-div">
<h3>你好,<span id="user_name">访客</span></h3>
<div id="user-login" hidden="true">
<form id="login-form" action="/login" method="get">
<p>用户名: <input id="form-name" type="text" name="name" /></p>
<p>密 码: <input id="form-pwd" type="password" name="pwd" /></p>
<button onclick="loginForm()">登录</button>
<input type="reset" value="重置" />
<p>还没有账号?点击这里<a href="/new">注册</a></p>
</form>
</div>
<div id="user-logout">
<form action="/logout" method="get">
<input type="submit" value="退出" />
</form>
</div>
(ps:初衷是在于,如果第一次点进网页的时候直接进入了news.js,可以有提示注册和登录,从而不至于让用户自己胡乱尝试,由于实在是太丑了,还是决定放弃)
登录页面的一些小改动
(ps:进入页面后,即提示需要注册后再登录,从而减少用户的尝试次数)
(ps:初衷在于,能够提醒用户密码错误或者用户不存在,弹框能够比较主观的起作用,而且用户需要先关闭弹框才能继续下一步动作,后考虑到太繁琐了,故舍弃)
数据库信息的存储
建表(数据库准备)
第一步,创建用户信息数据表
CREATE TABLE `craw`.`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;
第二步,记录用户的登录、查询(具体查询语句)操作(包括用户id、昵称、密码、权限、账户余额等)
CREATE TABLE `craw`.`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;
!!!这里注意建表的名字要和后面的对应,不然就会错误
效果呈现
三种图表展示数据分析
管理端页面的实现
(本来是直接做了一个新的网站的,然后通过链接转跳,但是这样所有的人都可以管理权限了,还是老老实实重写)
网站搭建(首先是一个静态的)
1、reset.css(主要使用模板,将默认标签重置)
/*不同的浏览器解析标签的时候,可能看到的效果会是一致的,但是赋予的样式可能不一样,如果我们直到了url具有一些间距效果,这种间距效果,有的浏览器是通过margin实现的,有的是通过padding来实现的,所以通过这个文件把标签的默认效果都重置*/
blockquote,body,button,dd,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,hr,input,legend,li,ol,p,pre,td,textarea,th,ur{
margin:0;
padding:0;
}
body,button,input,select,textarea{
font: 12px/1.5 tohoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif;
}
h1,h2,h3,h4,h5,h6{
font-size:100%;
}
/*font用来设置字体,有字体的大小和系列*/
address,cite,dfn,em,var{
font-style: normal;
}
code,kbd,pre,samp{
font-family:'Courier New', Courier, monospace;
}
small{
font-size:12px;
}
ol,ul{
list-style: none;
}
a{
text-decoration: none;
}
a:hover{
text-decoration: underline;
}
sup{
vertical-align: text-top;
}
sub{
vertical-align: text-bottom;
}
legend{
color:#000;
}
fieldset,img{
border:0;
}
button,input,select,textarea{
font-size:100%;
}
button{
border-radius: 0;
}
table{
border-collapse: collapse;
border-spacing: 0;
}
2、empManage.css主要是设置页面
section{
width:1145px;
margin:0 auto;
}
.header{
height:160px;
margin-top:25px;
}
.header>h1{
font-size:36px;
}
/*表单搜索框和添加*/
.header>div:nth-child(2){
height:40px;
background:gray;
border-radius:5px 5px 0 0;
font-size:16px;
color:white;
line-height: 40px;
padding-left: 15px;
}
.header>div:nth-child(3){
height:66px;
border:1px solid gray;
border-radius: 0 0 5px 5px;
padding:0 15px;
font-size:14px;
font-weight: bold;
}
.header>div:nth-child(3) input{
width: 180px;
height: 36px;
border-radius: 5px;
border:1px solid black;
}
/*添加用户*/
.add{
width:800px;
height:66px;
float:left;
line-height: 66px;
}
.add>button{
height:44px;
width: 44px;
background:gold;
color:white;
border:1px solid black;
border-radius: 5px;
}
/*搜索区域*/
.search{
width:44px;
height:66px;
float: left;
line-height: 66px;
}
.data{
height:320px;
margin-top:20px;
}
.data>table{
width:1145px;
border:1px solid black;
}
.dataTable td,.dataTable th{
padding:0 5px;
border:1px solid black;
}
.dataTable th{
text-align: left;
}
.dataTable tr{
height:40px;
}
.dataTable tbody tr:nth-child{
background:rgb(232, 233, 235);
}
.dataTable button{
width:36px;
height:38px;
border-radius: 5px;
color:rgb(226, 21, 21);
}
/*给所有的按钮添加鼠标手性*/
button{
cursor:pointer;
}
3、empManage.js 后端执行
/*关于数据操作的业务逻辑 */
//窗口内容加载完毕事件,当内容加载完毕之后,我们再去执行js代码,肯定没有问题
var data = require('../dao/manegeDAO')
window.onload=function(){
//获取页面中的数据表格
var dataTable = document.getElementById("dataTable");
//通过dataTable获取到tbody
//alert(dataTable);
var tbodyEle = dataTableEle.tBodies[0];
//数据渲染,把data.js中的数据显示在表格里面
for(var i=0;i<empData.length;i++){
//每有一个用户信息,就在tbody里面创建一个tr
var newTr = tbodyEle.insertRow(i);
//给newTr创建单元格
newTr.insertCell(0).innerText=empobj.id;
newTr.insertCell(1).innerText=empobj.username;
newTr.insertCell(2).innerText=empobj.password;
newTr.insertCell(3).innerText=empobj.registertime;
newTr.insertCell(4).innerHTML = "<button>修改</button><button>删除</button>";
}
}
4、empManage.html 前端网页
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户管理系统</title>
<!--引入css reset-->
<link rel="stylesheet" href="css/reset.css">
<!--引入本页面的样式-->
<link rel="stylesheet" href="css/empManage.css">
<script type="text/javascript" src="../dao/manegeDAO.js"></script>
<script type="text/javascript" src="../routes/empManage.js"></script>
</head>
<body>
<section class="header">
<!--大标题-->
<h1>用户信息管理</h1>
<!--添加标题-->
<div>添加用户</div>
<!--添加表单和搜索表单区域-->
<div>
<div class="add">
用户id:<input type="number" name="id">
用户名:<input type="text" name="username">
密码:<input type="text" name="password">
<button type="submit">添加</button>
</div>
<div class="search">
<input type="search" name="search" placeholder="搜索">
</div>
</div>
</section>
<section class="data">
<table class="dataTable" id="dataTable">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>密码</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<button>删除</button>
<button>修改</button>
</td>
</tr>
</tbody>
</table>
</section>
</body>
</html>
网站初效果
管理员转跳
(直接建立了一个和用户一样的页面,再创建一个管理员数据库,将管理员数据存储好后,将管理员注册栏抹掉,或者是直接在数据库中直接输入管理员信息,并在登录成功后转调至用户信息管理页面)
管理员界面处理
由于在自己写的网页上转跳后,点击按钮和输入数据后没有改变,套用之前爬虫展示的模板,在之前的爬虫中简单修改后,结果如图,发现是数据库没能导入
改进后
然后引入到我自己的网站
(注:由于插入一直报错,多方查资料、咨询未果,决定放弃最后的联动,不过可以在MySQL中实现管理员添加和删除,我觉得more than enough了)
关于分词操作的尝试
1、在数据库中建立新的表存储分词的结果
CREATE TABLE Splitwords (
id_fetches int,
word varchar(50) DEFAULT NULL
);
2、分词处理:将爬虫的内容,先用正则表达式去掉一些无用的字符与高频但无意义的词;进行分此后,逐个处理词条判断是否存在停用此表当中,将有效词条存储到数据库中的splitwords中
const regex = /[\t\s\r\n\d\w]|[\+\-\(\),\.。,!?《》@、【】"'::%-\/“”]/g;
var fetchSql = "select id_fetches,content from fetches;";
newsDAO.query_noparam(fetchSql, function (err, result, fields) {
result.forEach(function (item){
var segmenter = new Segmenter();
var newcontent = item["content"].replace(regex,'');
if(newcontent.length !== 0){
var words = segmenter.analyze(newcontent).split(' ');
var id_fetch = item["id_fetches"];
words.forEach(function(word){
if(!stop_words.has(word)&&word.length>1){
var insert_word_Sql = 'INSERT INTO Splitwords2(id_fetches,word) VALUES(?,?);';
var insert_word_Params = [id_fetch, word];
newsDAO.query(insert_word_Sql, insert_word_Params, function(err){
if(err)console.log(err);
});
}
});
}
});
});
注:自己尝试了很久,但都没有很功的显示出分词的效果
写在最后
虽然做了很多尝试,也失败了很多,js这门语言也没有学得特别精通,但是能够在各界的帮助下做出以上已经很不容易了,有时间还是会继续研究,争取把每个任务可以独立完成!