WebFinal
项目功能
- 【功能0】爬虫定时工作:后台定时更新爬虫数据库✅
- 【功能1】登陆注册:用户可注册登录网站,非注册用户不可登录查看数据
✅:- 登陆【功能1.1】
- 注册【功能1.2】
- 【功能2】操作日志存入:用户注册、登录、查询等操作记入数据库中的日志–session✅
- 【功能3】数据展示分页排序:爬虫数据查询结果列表支持分页和排序✅
- 分页【功能3.1】
- 按发布时间排序【功能3.2】
- 【功能4】管理端:可以查看(查看用户的操作记录)✅
- 【功能5】Echarts图表:用Echarts或者D3实现3个以上的数据分析图表展示在网站中✅
- 扩展【功能6】
- 【功能6.1】中文分词查询:实现对爬虫数据中文分词✅
- 【功能6.2】布尔查询AND/OR✅
- 【功能6.3】实现查询结果按照主题词打分的排序✅
- Elastic Search TF-IDFS方法(用Elastic Search+Kibana展示爬虫的数据结果✅))
- Tf-idf python实现✅
- 【功能6.3】用Elastic Search+Kibana展示爬虫的数据结果✅
项目展示
话不多说先来demo~
DaSEWeb编程期末项目Demo
项目结构
后端mysql数据库
user
表
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;
但是在这里,为了实现功能6.扩展-2.实现查询结果按照主题词打分的排序,所以需要之前
fetches
表结构进行修改。
user表修改
新增flag字段0–后续停用和启用和isadmin字段
db = MySQLdb.connect("localhost", "root", "root", "crawl", charset='utf8' )
cursor=db.cursor();
sql_usr="ALTER TABLE user ADD isadmin integer(5) not null default 0;"
sql_usr_="ALTER TABLE user ADD flag integer(5) not null default 0;"
try:
cursor.execute(sql_usr)
db.commit()
except:
print("ERRR")
db.rollback()
修改后的user表格如下:
user.action
表
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;
fetches
表修改–使用python操作后端mysql数据库
db = MySQLdb.connect("localhost", "root", "root", "crawl", charset='utf8' )
sql="ALTER TABLE fetches ADD marks float(6,2) not null default 0.00"
cursor=db.cursor()
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
注意对数据库的操作不要忘记
db.commit()
数据库配置文件
module.exports = {
mysql: {
host: 'localhost',
user: 'root',
password: 'root',
database:'crawl',
// 最大连接数,默认为10
connectionLimit: 10
}
};
功能0:后端爬取的数据源更新–node.js定时爬虫
为了更符合真实的新闻数据爬虫系统的分析,现在已有基础上引入node.js
定时爬虫,定时爬取的核心代码如下。
爬虫定时工作需要引入第三方包node-schedule
npm install node-schedule
修改代码:
var schedule = require('node-schedule');
//!定时执行
var rule = new schedule.RecurrenceRule();
var times = [0,1,2,3,4,5,6,7,8,9,10,11 ,12]; //每天2次自动执行
var times2 = 5; //定义在第几分钟执行
rule.hour = times;
rule.minute = times2;
//定时执行httpGet()函数
schedule.scheduleJob(rule, function() {
seedget();
});
Angular.js
AngularJS 是一个 JavaScript 框架,是一个以 JavaScript 编写的库。它以JavaScript 文件形式发布的,可通过 script 标签添加到网页中。
AngularJS 通过 ng-directives 扩展了 HTML。
- ng-app 指令定义一个 AngularJS 应用程序。
- ng-model 指令把元素值(比如输入域的值)绑定到应用程序。
- ng-bind 指令把应用程序数据绑定到 HTML 视图。
AngularJS应用组成:
- View(视图), 即 Html。
- Model(模型), 当前视图中可用的数据。
- Controller(控制器), 即 JavaScript 函数,可以添加或修改属性。
Angular.Js --$Scope
在使用 AngularJS 创建控制器时,你可以将 $scope 对象当作一个参数传递。
Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。Scope 是一个对象,有可用的方法和属性,它可以应用在视图和控制器上。
功能1:用户可注册登录网站,非注册用户不可登录查看数据
用户注册登陆界面,如下,在老师给的基础上,我使用了别的前端美化方法:
在前端中,分别设置了管理员登陆和用户登录。
所以需要修改user
表,默认一般注册用户都不是管理员。
功能1.1登陆实现
功能实现——对用户有适当提示:
- 提示用户名或密码输错
- 用户不存在
前端index.html
首先在根元素上定义 AngularJS 应用“login”,相关代码即<html ng-app="login">
,指定AngularJS
应用程序管理的边界,使得在ng-app
内部的指令起作用。
它实现的功能是:通过 ng-model 指令,把输入域$scope
的用户名和密码以属性名username
和 password
绑定到当前作用域中,以便$scope
对象在控制器和视图之间传递数据;当按钮事件被触发时,函数check_pwd()
会被调用。
angular.js(直接嵌入index.html)
控制器app.controller(loginCtrl)
:
- 初始化视图中输入的数据,作为存储数据的容器;
- 同时通过
$scope
对象把函数行为暴露给视图; - 监视模型的变化,做出相应的逻辑处理。
var app = angular.module('login', []);
app.controller('loginCtrl', function ($scope, $http, $timeout) {…});
通过 $scope
对象的username
和 password
属性获取绑定的用户名和密码,生成json
对象传给router
。
此时我们需要对返回结果是进行判断:
- 如果结果是
OK
,则修改window
对象的location.href
属性,将当前页面跳转至新闻查询和echarts
图操作前端页面news.html
; - 否则,则通过预先定义在前端页面
index.html
里的$scope
对象属性msg
显示警告。
Route/user.js
实现Todo
将用户名传入数据库,以获取对应的密码。
- 如果返回的用户名长度为零,说明用户不存在;
- 如果获取到密码,检查和用户输入的密码是否匹配:
- 若匹配则发送 json 响应,生成
json
对象传给router
,此时msg
赋值为OK
,并且把用户名保存到服务器内存中,以便记录用户登录操作日志和检查用户对页面进行操作时的登录状态; - 否则
msg
为错误提示。
- 若匹配则发送 json 响应,生成
var userDAO = require('../dao/userDAO');
router.post('/login', function(req, res) {
var username = req.body.username;
var password = req.body.password;
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'});
}else{
res.json({msg:'用户名或密码错误!请检查后输入'});
}
}
});
});
Dao层/userDAO.js & userSqlMap.js
MVC架构
Service是业务层,Dao是数据访问层,这样的分层是基于MVC架构来说的,将这些进行分层的主要作用是解耦。
对于Spring这样的框架,(View\Web)表示层调用控制层(Controller),控制层调用业务层(Service),业务层调用数据访问层(Dao)。
具体起来,Dao的作用是封装对数据库的访问:增删改查,不涉及业务逻辑,只是达到按某个条件获得指定数据的要求;
而Service层,则是专注业务逻辑,对于其中需要的数据库操作,都通过Dao层去实现;
userDAO
下面代码展示的是userDAO
的代码逻辑
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);
});
},
};
userSqlMap.js
注意,在userSqlMap.js
和newsDao.js
中体现了两种不同的SQL
查询逻辑。
这里执行pool.getConnection(function(){conn.query(sql)});
。
var sql = 'select * from Splitwords ';
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); //事件驱动回调
});
}
});
而userSQLMap中则是处理了一种映射。
这里则更直接一些,执行pool.query
。
var userSqlMap = {
add: 'insert into user(username, password) values(?, ?)',//注册时用
getByUsername: 'select username, password from user where username = ?'//登陆时用
};
module.exports = userSqlMap;
pool.query(userSqlMap.add, [user.username, user.password], function (error, result) {
if (error) throw error;
callback(result.affectedRows > 0);
});
功能1.2 注册实现
功能实现——对用户有适当提示:
- 两次密码不一致
- 用户已存在
- 注册成功跳转登陆页面
angular.js
先检验两次输入密码是否一致,如果不一致,直接显示警告
$scope.doAdd = function () {
if($scope.add_password!==$scope.confirm_password){
$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;
});
}
Route/user.js
router.post('/register', function (req, res) {
var add_user = req.body;
userDAO.getByUsername(add_user.username, function (user) {
if (user.length != 0) {
res.json({msg: '用户已存在!'});
}else {
userDAO.add(add_user, function (success) {
res.json({msg: '成功注册!请登录'});
})
}
});
});
功能2: 用户注册、登录、查询等操作记入数据库中的日志
Morgan(logger)
这里借助 Express 框架记录日志的中间件 morgan
,而且在 app.js 文件中已经默认引入了该中间件 var logger = require('morgan');
(使用 app.use(logger('dev'))
, 可以将请求信息打印在控制台)
参照 morgan官方说明文档,获取所要存储的相关信息,直接将用户操作记入 mysql 中。
Morgan-logger-Demo
var express = require('express');
var app = express();
var morgan = require('morgan');
app.use(morgan('short'));
app.use(function(req, res, next){
res.send('ok');
});
app.listen(3000);
Morgan-logger-结果
node bin\www 运行程序,并在浏览器里访问 http://127.0.0.1:3000
控制台即可看到打印的日志如下
::ffff:127.0.0.1 - GET / HTTP/1.1 304 - - 3.019 ms
::ffff:127.0.0.1 - GET /favicon.ico HTTP/1.1 200 2 - 0.984 ms
Route/logDAO.js
代码如下
// 用于存放用户操作记录 日志
var mysql = require('mysql');
var mysqlConf = require('../conf/mysqlConf');
var pool = mysql.createPool(mysqlConf.mysql);
// 使用了连接池,重复使用数据库连接,而不必每执行一次CRUD操作就获取、释放一次数据库连接,从而提高了对数据库操作的性能。
// 记录用户操作
module.exports = {
userlog :function (useraction, callback) {
pool.query('insert into user_action(username,request_time,request_method,request_url,status,remote_addr) values(?, ?,?,?,?,?)',
useraction, function (error, result) {
if (error) throw error;
callback(result.affectedRows > 0);
});
},
};
存储部分session信息的app.js
部分session信息的存储代码,逻辑上讲应该保存在app.js
中
//设置session信息
var logger = require('morgan');//借助中间件保存的信息
app.use(session({
secret: 'sessiontest',//与cookieParser中的一致
resave: true,
saveUninitialized: false, // 是否保存未初始化的会话
cookie : {
maxAge : 1000 * 60 * 60, // 设置 session 的有效时间,单位毫秒
},
}));
app.use(logger(function (tokens, req, res) {
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';
}
if(username!='notlogin'){
logDAO.userlog([username,request_time,request_method,request_url,status,remote_addr], function (success) {
console.log('成功保存!');
})
}
}, ));
从管理员界面可以查看的用户操作信息表格如下:
表格显示的具体逻辑详见新闻搜索功能。
控制台打印的session信息如下所示:
功能3 爬虫数据查询结果列表支持分页和排序
该功能展示如下:
因为css
前端太菜的缘故尽力了也无法使表格对齐QAQ【太菜了请见谅
在用户点击搜索前无表格显示:
逻辑也同样由angular.js
实现
功能3.1分页
分页的功能实现也在news.js
的代码中,而本质仍是在DAO层展示时与数据的交互。都由$scope
实现
$scope.initPageSort=function(item){
$scope.pageSize=5; //每页显示的数据量,可以随意更改
$scope.selPage = 1;
$scope.data = item;
$scope.pages = Math.ceil($scope.data.length / $scope.pageSize); //分页数
$scope.pageList = [];//最多显示5页,后面6页之后不会全部列出页码来
$scope.index = 1;
// var page = 1;
// for (var i = page; i < $scope.pages+1 && i < page+5; i++) {
// $scope.pageList.push(i);
// }
var len = $scope.pages> 5 ? 5:$scope.pages;
$scope.pageList = Array.from({length: len}, (x,i) => i+1);
//设置表格数据源(分页)
$scope.items = $scope.data.slice(0, $scope.pageSize);
};
//打印当前选中页
$scope.selectPage = function (page) {
//不能小于1大于最大(第一页不会有前一页,最后一页不会有后一页)
if (page < 1 || page > $scope.pages) return;
//最多显示分页数5,开始分页转换
var pageList = [];
if(page>2){
for (var i = page-2; i <= $scope.pages && i < page+3; i++) {
pageList.push(i);
}
}else {
for (var i = page; i <= $scope.pages && i < page+5; i++) {
pageList.push(i);
}
}
$scope.index =(page-1)*$scope.pageSize+1;
$scope.pageList = pageList;
$scope.selPage = page;
$scope.items = $scope.data.slice(($scope.pageSize * (page - 1)), (page * $scope.pageSize));//通过当前页数筛选出表格当前显示数据
console.log("选择的页:" + page);
};
//设置当前选中页样式
$scope.isActivePage = function (page) {
return $scope.selPage == page;
};
//上一页
$scope.Previous = function () {
$scope.selectPage($scope.selPage - 1);
};
//下一页
$scope.Next = function () {
$scope.selectPage($scope.selPage + 1);
};
功能3.2排序
按时间排序
在UI中点击按时间排序即可选择ASC或者DESC的顺序
因为sql语句就很好的支持order by
所以只需要在数据层进行排序即可。
首先在news.js
里面传入FLAG=$scope.sorttime='1'/'2'
,然后用一标识SQL
中是否还需要加额外的东西
$scope.searchsortASC = function () {
$scope.sorttime = '1';
$scope.search();
};
$scope.searchsortDESC = function () {
$scope.sorttime = '2';
$scope.search();
};
newsDAO.js
的代码如下:
if(searchparam['stime']!="undefined"){
if(searchparam['stime']=="1"){
sql+='ORDER BY publish_date ASC ';
}else {
sql+='ORDER BY publish_date DESC ';
}
}
功能4.用户管理
用户端界面首页
管理端界面首页
从UI界面设计中可以看出,用户端和管理端界面的用户内容不同。
我在设计用户端的时候,返回的是热门新闻榜单。
而管理端则更注重用户管理,用户使用吞吐量,爬取的URL数目的角度。
这里也是一个echarts
图表。
在管理端界面中,可以查看用户操作记录表格
功能5.用Echarts或者D3实现3个以上的数据分析图表展示在网站中
图表显示端的逻辑与新闻端的逻辑显示类似。
同样由ng-show/ng-hide决定一开始是否显示。
柱状图
词云
折线面积图
代码实现逻辑(histogram as an example)
调用 show_search_historgram() 函数
点击搜索框即调用此函数
$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: {
trigger: 'axis'
},
legend: {
data: ['新闻发布数']
},
xAxis: {
data: newdata["xdata"]
},
yAxis: {},
series: [{
name: '新闻数目',
type: 'bar',
data: newdata["ydata"]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
},
function (err) {
$scope.msg = err.data;
});
};
前端代码
<div ng-show="isShowtext" style="width: 1300px;position:relative; top:70px;left: 80px">
<form>
查询词: <input type="text" ng-model="searchline">
<button type="submit" ng-click="line()">查询</button>
</form>
</div>
路由
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:'/login.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();
});
}
});
功能6. 中文分词查询
在已有基础上使用分词查询:
分词查询的意义
用一个直观的方式,先看结果
没有分词前
使用分词查询,即会提高我们的召回率来判断。
存储分词结果
Javascript/news.js修改实现
$scope.search=function(){
//这里只需要先修改myurl链接。
var myurl = `/news/search?t1=${title1}&ts=${selectTitle}&t2=${title2}&c1=${content1}&cs=${selectContent}&c2=${content2}&stime=${sorttime}&stopic=${sorttopic}&splitflag=${issplit}`;
}
$scope.searchsplit=function(){
$scope.issplit='true';
$scope.search();
}
DAO/newsDAO.js
if(searchparam["splitflag"]!="undefined"){
if(searchparam["splitflag"]=="true"){
sql='select * from fetches_split'
}
}
对搜索词进行分割
cursor=db.cursor()
try:
cursor=db.cursor()
sql_fetch="select * from fetches;"
cursor.execute(sql_fetch)
res=cursor.fetchall()
for row in res:
fetches_id=int(row[0])
content_raw=row[9]
print("************")
# print(row)
# print(len(row))
# break
cursor=db.cursor()
seq_list=jieba.cut(content_raw)#精确模式
# print(len(list(seq_list)))
seq_list_=list(seq_list)
for seq_word in seq_list_:
print("*******++++??????WTF")
# re.sub('[^\u4e00-\u9fa5]+', '', seq_word)
print("seq_word: ",seq_word)
print("fetches_id: ",fetches_id)
if seq_word=='':
continue
elif seq_word!=None:
sql_insert="UPDATE fetches_copy SET title_split = '%s' WHERE id_fetches = '%d';" % (seq_word,fetches_id)
print(sql_insert)
print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=")
try:
cursor=db.cursor()
cursor.execute(sql_insert)
db.commit()
except:
print("insert ERR!")
except:
print("SOS SOS SOS!")
功能7. Tf-idf评分排序查询
tf-idf
定义
Tf-idf 是一种统计方法,用来衡量自此对于文本的重要程度。一个单 词的重要性与它在当前文本中出现的频率成正比,与它在其它语料库出 现的频率成反比,如,中文文本中常见的“的了呢”等停用词因为在语 料库的大部分中文文本中都出现,所以这一类词对于文本特征贡献性的 程度就没有这么重要。
图片Reference:我个人的算法报告
TF:IDF 的理解:
TF 即 term frequency,表示某一个单词在某一个文档中出现的频率 (次数/总词数),很自然的可以理解,当单词在某一个文档中出现的 频率很高的时候,我们可以认定其是这篇文档的关键词的可能性相应的 增大。但是,作为停用词,它在每一篇文档都会出现,且频率都很高, 这一类的噪音词会很大的影响我们的判断。
所以,引入 inverse document frequency 去达成一个平衡,如果包 含一个词语的文档越多,那么该词语对特征的贡献度即降低,该词语就 不再具有特征的代表性。
Tf-idfTransformer in python
必要的包和库
import os
import sys
import jieba
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
Get_mark()
def get_mark(test_data):
try:
all_txt_cut=""
seq_list=jieba.cut(test_data)#精确模式
title_seq_list=jieba.cut(title_data)
for word in list(seq_list):
all_txt_cut+=word+" "
all_txt_cut=[all_txt_cut]
vectorizer=CountVectorizer()#该类会将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频
transformer=TfidfTransformer()#该类会统计每个词语的tf-idf权值
tfidf=transformer.fit_transform(vectorizer.fit_transform(all_txt_cut))#第一个fit_transform是计算tf-idf,第二个fit_transform是将文本转为词频矩阵
word=vectorizer.get_feature_names()#获取词袋模型中的所有词语
# print(word)
weight=tfidf.toarray()#将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重
words_tfidf={}
for i in range(len(word)):
words_tfidf[word[i]]=weight[0][i]
words_tfidf_order=sorted(words_tfidf.items(),key=lambda x:x[1],reverse=True) #字典排序,生成元组
# print(type(words_tfidf_order))
s_list=[]
for k in range(len(words_tfidf_order)):
return words_tfidf_order[k][1]
except:
print("ERRRR")
Mysql_db()-操作数据库
db = MySQLdb.connect("localhost", "root", "root", "crawl", charset='utf8' )
sql="SELECT * from fetches;"
cursor=db.cursor()
try:
cursor.execute(sql)
results=cursor.fetchall()
print(len(results))
for row in results:
test_data=row[9]
print(row[-1])
if(row[-1]!=0):
print("already have marks!")
continue
else:
if(len(test_data.strip())==0):
print(test_data)
print("No content")
continue
else:
mark_to_insert=get_mark(test_data.strip())
# print(mark_to_insert)
if (mark_to_insert==None):
mark_to_insert=0.0068
id_=int(row[0])
print(id_)
sql_2 = "UPDATE fetches SET marks = '%f' WHERE id_fetches = '%d';" % (mark_to_insert,id_)
cursor_2=db.cursor()
try:
cursor_2.execute(sql_2)
db.commit()
except:
print("UPDATEING ERR!")
except:
print("ERROR! why?")
###数据库展示
评分查询排序
注意,这里在UI中,只默认tf-idf评分高的,毕竟没人会对评分低的感兴趣吧。
功能8ElasticSearch+Kbana 展示爬虫结果结果
ElasticSearch是一个基于Lucene的搜索服务器。
它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch由Java开发,如果将其设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
当我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,ElasticSearch能够简单地使用JSON通过HTTP来索引数据,且搜索服务器始终可用。
同时,ElasticSearch提供高可扩展性,能够从一台开始并扩展到数百台,可以实时搜索,简单的多租户,在更真实的业务场景中,ElasticSearch可以帮我们建立一个云的解决方案。
因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。
Elastic Search Reference Official Documents
Mac 平台本地搭建ElasticSearch+Kbana
JDK1.8
我是本机在IDEA
安装的jdk1.8
安装ES
- Home-brew YYDS:
brew install elasticsearch
启动elastic search
Kibana
brew install kibana
Data Analysis
Todo:爬虫搜索引擎的搭建–Scrapy+redis+ElasticSearch+Kibana
尝试follow steps运行截图如下:
爬取的数据结果展示
总结
这次web编程的期末项目,是一直对前端略有排斥的我的一次很大的鼓励与挑战。前端的实时展示总是令人欣喜和鼓舞的。
具体的过车已经展示在项目完成中了,此次项目收获颇丰,受益匪浅。
大三的web课果然和大一课程的感触是十分不同的。