WebFinal

WebFinal

项目功能

  1. 【功能0】爬虫定时工作:后台定时更新爬虫数据库✅
  2. 【功能1】登陆注册:用户可注册登录网站,非注册用户不可登录查看数据
    ✅:
    1. 登陆【功能1.1】
    2. 注册【功能1.2】
  3. 【功能2】操作日志存入:用户注册、登录、查询等操作记入数据库中的日志–session✅
  4. 【功能3】数据展示分页排序:爬虫数据查询结果列表支持分页排序
    1. 分页【功能3.1】
    2. 按发布时间排序【功能3.2】
  5. 【功能4】管理端:可以查看(查看用户的操作记录)✅
  6. 【功能5】Echarts图表:用Echarts或者D3实现3个以上的数据分析图表展示在网站中✅
  7. 扩展【功能6】
    1. 【功能6.1】中文分词查询:实现对爬虫数据中文分词✅
    2. 【功能6.2】布尔查询AND/OR✅
    3. 【功能6.3】实现查询结果按照主题词打分的排序✅
      1. Elastic Search TF-IDFS方法(用Elastic Search+Kibana展示爬虫的数据结果✅))
      2. Tf-idf python实现✅
    4. 【功能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的用户名和密码以属性名usernamepassword绑定到当前作用域中,以便$scope对象在控制器和视图之间传递数据;当按钮事件被触发时,函数check_pwd()会被调用。

angular.js(直接嵌入index.html)

控制器app.controller(loginCtrl)

  • 初始化视图中输入的数据,作为存储数据的容器;
  • 同时通过$scope对象把函数行为暴露给视图;
  • 监视模型的变化,做出相应的逻辑处理。
var app = angular.module('login', []);
app.controller('loginCtrl', function ($scope, $http, $timeout) {});

通过 $scope对象的usernamepassword属性获取绑定的用户名和密码,生成json对象传给router

此时我们需要对返回结果是进行判断:

  • 如果结果是OK,则修改 window对象的location.href属性,将当前页面跳转至新闻查询和echarts图操作前端页面 news.html
  • 否则,则通过预先定义在前端页面index.html里的 $scope 对象属性 msg 显示警告。

Route/user.js

实现Todo将用户名传入数据库,以获取对应的密码。

  • 如果返回的用户名长度为零,说明用户不存在;
  • 如果获取到密码,检查和用户输入的密码是否匹配:
    • 若匹配则发送 json 响应,生成json对象传给router,此时msg 赋值为OK,并且把用户名保存到服务器内存中,以便记录用户登录操作日志和检查用户对页面进行操作时的登录状态;
    • 否则 msg为错误提示。
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.jsnewsDao.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

Reference

JDK1.8

我是本机在IDEA安装的jdk1.8在这里插入图片描述

安装ES

  1. Home-brew YYDS:brew install elasticsearch

在这里插入图片描述

启动elastic search
在这里插入图片描述

在这里插入图片描述

Kibana

  1. brew install kibana

Data Analysis

在这里插入图片描述

Todo:爬虫搜索引擎的搭建–Scrapy+redis+ElasticSearch+Kibana

reference

尝试follow steps运行截图如下:

在这里插入图片描述

爬取的数据结果展示

在这里插入图片描述

总结

这次web编程的期末项目,是一直对前端略有排斥的我的一次很大的鼓励与挑战。前端的实时展示总是令人欣喜和鼓舞的。

具体的过车已经展示在项目完成中了,此次项目收获颇丰,受益匪浅。

大三的web课果然和大一课程的感触是十分不同的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二二子030

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值