结对第二次作业——顶会热词统计的实现
这个作业属于哪个课程 | 2021春软件工程实践 | W班 (福州大学) |
---|---|
这个作业要求在哪里 | 结对第二次作业——顶会热词统计的实现 |
结对学号 | 111801429 & 221801139 |
这个作业的目标 | 实现顶会热词统计的相关功能 |
其他参考文献 | elementUI |
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 10 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 10 |
Development | 开发 | 3190 | 2745 |
• Analysis | • 需求分析 (包括学习新技术) | 30 | 60 |
• Design Spec | • 生成设计文档 | 10 | 10 |
• Design Review | • 设计复审 | 10 | 5 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 10 | 30 |
• Design | • 具体设计 | 60 | 60 |
• Coding | • 具体编码 | 3000 | 2520 |
• Code Review | • 代码复审 | 60 | 30 |
• Test | • 测试(自我测试,修改代码,提交修改) | 10 | 30 |
Reporting | 报告 | 50 | 45 |
• Test Report | • 测试报告 | 30 | 30 |
• Size Measurement | • 计算工作量 | 10 | 5 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 3270 | 2800 |
Github仓库地址
https://github.com/lilith0120/PairProject
项目访问地址
成果展示
1. 本项目
whichpage
的项目首页,显示已导入的论文列表,以及数据库爬取的总Top10热词排行:
2. 对已导入的论文列表进行模糊查询:
3. 点击右侧Top10热词,展示相关已导入的论文:
4. 点击删除图标,可对被选中论文进行删除操作,删除成功后会给予相应提示:
5. 点击详细页图标,可进入被选中论文详细页面(点击返回按钮,即可返回首页):
6. 在主页面点击修改图标,或在论文详细页点击修改按钮,均可进入被选中论文的修改页面:
7. 在修改页面点击保存修改按钮,将提示修改成功信息,并返回该论文的详细页面:
8. 在论文导入页面搜索相关论文题目,显示已爬取的相关性最高的前6条论文列表(鼠标悬停导航栏可出现高亮):
9. 点击导入可将被选中论文导入至首页(已导入论文列表)内:
10. 使用饼图、雷达图、折线图对近十年间、不同顶会的热词呈现热度走势对比,并以动图的形式呈现:
结对过程
基于第一次结对作业的原型设计,初步决定使用vue编写前端,使用python编写后端,并双双激情购入服务器(x2)。PS: 笑死,根本不够用!
通过在同一个工位的编程,方便了两人互相逼逼赖赖,如图所示:
在工作初期发现如果文件夹名为学号,笑死,vue根本跑不了 :/
另外由于第一次使用github高级功能,前期的github commit
记录总是奇奇怪怪的,且有自己的想法(大无语事件发生)
最后通过不是那么万能的百度发现了宝藏语句git pull --rebase
前期工作准备完毕后,火速完成前端页面的编写,并双双阵亡在了爬取数据上。离谱,八爪鱼是什么垃圾!还是
python
大法好 :)
于是经过了坎坷的爬取数据后,收获到了1500+的论文数据,以及若干的关键词。数据库内容如下(由于篇幅有限,此处每个表只展示1000条数据):
由于不知道服务器怎么同时运行两个服务,于是两台服务器双双上岗(PS: 一个拿去极限编程了,哭哭)
实现过程
- 前端:
- 使用
vue-cli
框架+ElementUI
实现基本的项目框架的搭建,并使用vue-router
、axios
来实现路由跳转以及与后端交互,并通过echarts
来展示相关数据。- 通过将右侧的Top10列表和顶部的导航栏复用,减少了不必要的代码冗余。并分别用三个页面展示论文列表、导入论文以及本站焦点模块。
- 后端:
- 使用
python
的flask
框架进行接口的编写,并通过postman
进行相关的接口测试。- 主要通过每个论文独有的
isbn
,对论文进行删除、更改操作。- 对
tag_list
表进行相关的数据排序与获取,用于前端图标的显示。
功能结构图
代码说明
1. 前端导入依赖如下:
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5",
"echarts": "^4.8.0",
"element-ui": "^2.15.1",
"vue": "^2.6.11",
"vue-router": "^3.5.1"
},
2. 前端路由设置如下:
const router = new VueRouter({
mode: 'history',
base: '',
routes: [
{
path: '/',
redirect: { name: 'home' },
},
{
path: '/home',
component: home,
name: 'home',
redirect: { name: 'listpage' },
children: [
{
path: 'listpage',
component: listpage,
name: 'listpage',
},
{
path: 'insertpage',
component: insertpage,
name: 'insertpage',
},
{
path: 'detailpage/:isbn',
component: detailpage,
name: 'detailpage',
},
{
path: 'editpage/:isbn',
component: editpage,
name: 'editpage',
}
]
},
{
path: '/hotpage',
component: hotpage,
name: 'hotpage',
},
]
})
3. 前端主页面如下:
<template>
<div id="home">
<router-view></router-view>
<toplist></toplist>
</div>
</template>
4. 前端图标页面如下:
<template>
<div id="hot_page">
<div id="chart_part">
<div id="pie_chart" ref="pie"></div>
<div id="radar_chart" ref="radar"></div>
</div>
<div id="line_chart" ref="line"></div>
</div>
</template>
5. 前端导航栏页面如下:
<template>
<div id="navbar">
<div id="logo">
<img id="nav_logo" src="../assets/logo.png" alt="" />
</div>
<div>
<div id="nav_button">
<div class="nav_button_item" @click="go_home">
<i class="iconfont icon-home"></i>
<span>首页</span>
</div>
<div class="nav_button_item" @click="go_insert">
<i class="iconfont icon-insert"></i>
<span>论文导入</span>
</div>
<div class="nav_button_item" @click="go_hot">
<i class="iconfont icon-data"></i>
<span>本站聚焦</span>
</div>
</div>
</div>
</div>
</template>
6. 后端爬取论文数据(部分代码):
# 获取数据
def get_message(num):
if len(br.find_elements_by_xpath('//div[@class="u-mb-1"]/div')):
abstract = br.find_elements_by_xpath(
'//div[@class="u-mb-1"]/div')[0].text
else:
return
if len(
br.find_elements_by_xpath(
'//div[@class="u-pb-1 doc-abstract-dateadded"]')):
date = br.find_elements_by_xpath(
'//div[@class="u-pb-1 doc-abstract-dateadded"]')[0].text
date = date.split(r': ')[1]
else:
return
link = br.find_elements_by_xpath(
'//div[@class="u-pb-1 stats-document-abstract-doi"]/a')
if len(link):
link = link[0]
link = link.get_attribute('href')
if len(br.find_elements_by_xpath('//h1[@class="document-title"]')):
title = br.find_elements_by_xpath(
'//h1[@class="document-title"]')[0].text
else:
return
if len(br.find_elements_by_xpath('//div[@class="u-pb-1"]')) >= 4:
isbn = br.find_elements_by_xpath('//div[@class="u-pb-1"]')[3].text
isbn = isbn.split(r': ')[1]
elif len(br.find_elements_by_xpath('//div[@class="u-pb-1"]')) >= 3:
isbn = br.find_elements_by_xpath('//div[@class="u-pb-1"]')[2].text
isbn = isbn.split(r': ')[1]
else:
return
pointer_url = "https://ieeexplore.ieee.org/document/67511" + str(
num) + "/keywords#keywords"
br.get(pointer_url)
time.sleep(2)
key_list = br.find_elements_by_xpath(
'//ul[@class="u-mt-1 u-p-0 List--no-style List--inline"]/li')
key_word = ""
for k in key_list:
key_word += k.text
key_list = key_word.split("\n,")
key_word = key_word.split("\n")
key_word = "".join(key_word)
save_data(isbn, key_word, title, link, date, abstract)
save_tag(key_list)
7. 后端实现模糊搜索接口:
# 搜索论文
@pages.route('/page/search/<num>', methods=['POST'])
def searchPages(num):
re_dict = request.get_json()
isbn = re_dict.get('isbn')
title = re_dict.get('title')
tag = re_dict.get('tag')
pages = models.User_page.query.filter(
models.User_page.isbn.like('%{isbn}%'.format(isbn=isbn)),
models.User_page.title.like('%{title}%'.format(title=title)),
models.User_page.tag.like('%{tag}%'.format(tag=tag))).paginate(
int(num), 6)
result = {}
data = []
for p in pages.items:
d = {}
d['isbn'] = p.isbn
d['title'] = p.title
d['tag'] = p.tag
data.append(d)
result['total_num'] = pages.pages
result['pages'] = data
return jsonify(errno=0, data=result)
8. 后端获取Top10热词排行接口:
# 获取top10热词
@pages.route('/tag', methods=['GET'])
def showTopTags():
result = db.session.query(
func.sum(models.Tag_list.num).label('total_num'),
models.Tag_list.name).group_by(models.Tag_list.name).order_by(
text("total_num desc")).limit(10).all()
data = []
for r in result:
d = {}
d['title'] = r.name
data.append(d)
return jsonify(errno=0, data=data)
心路历程,队友评价
第二次结对的心路历程与收获
小皮(221801139):
心路历程:
第一次接触vue感觉很新鲜也很好用(虽然一开始不太懂,但后面越来越好上手,开心!),在本次实践中也很享受做前端页面的工作,elementUI真是个宝藏网址,完美的实现了我们的原型和需求,爱了爱了。
收获:
- 被强行安利一嘴的
vue
,并成功上手- 学到了前后端交互的
axios
编写方式- 代码规范得到救治,并受到了夸奖
九歌(111801429):
心路历程:
最开始的时候,很担心两只咸鱼做不完这项艰巨的任务。但是随着前端框架的搭建以及静态界面的完成,感觉事情似乎又好起来了。虽然在爬取论文数据的时候遇到了比较大的挫折,但是磋磨磋磨,总能盘活这件事情。最后,通过接口测试以及部署到服务器后的页面测试,圆满完成了这项任务。好耶!!!!!
收获:
- 重新拾起
python
的爬取技能点- 重新拾起
python
的接口编写技能点- 巩固了
vue
框架的使用并成功安利出去- 对小皮同志的代码起到了一定的规范作用
队友评价
小皮(221801139)=>九歌(111801429):
被九歌同志成功安利
vue
和python
,做出来的爬虫也太酷了吧,果然强行和九歌同志绑定是个正确的决定!虽然在部署服务器的过程中,经历了好多困难,但是还是被她成功攻破,棒!如果她不逼逼赖赖就更好了...好想上手痛击怎么办,在线等,挺急的 :)一起加油吧,勇敢的狗狗们!诶嘿!
PS: 熬到凌晨的感觉也太开心了吧,我很快乐,真的 :)
九歌(111801429)=>小皮(221801139):
小皮同志是一个好同志,能容忍我一直逼逼赖赖的吐槽(并且不会下手痛击她的队友)。并且小皮同志吃苦耐劳,大家一起加班,并拖延到了很晚。笑死,根本不困。:)在小皮同志的工位上,定点上下班(吗?)让我有体会了结对编程带来的变化,一直碎碎念,根本停不下。小皮同志在我的带领下,口音逐渐走上了一条不归路。笑死,根本改不回来。
PS: 快跑!小皮同志带着口音过来了!jiú命!!!