结对作业二

作业基本信息

这个作业属于哪个课程 2021春软件工程实践|W班(福州大学)
这个作业要求在哪里 作业要求
结对学号 221801406李荣臻 221801426林泽坤
这个作业的目标 用web技术实现论文爬取网站:对已爬取的论文列表进行操作,分析已爬取到的论文信息,提取top10个热门领域或热门研究方向并用动态图谱展示,部署项目到云服务器上
其他参考文献 Yii 2.0 权威指南,csdn

1.git仓库链接

点击进入

2.代码规范链接

codestyle.md

3.PSP表格

PSP2.1 [Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 60
•Estimate •估计这个任务需要多少时间 30 60
Development 开发 2970 3530
•Discuss •结对讨论 90 120
•Analysis •需求分析 60 60
•document •生成文档 60 60
•Studying •学习新技术 100 150
• Design Spec • 生成设计文档 20 20
• Design Review • 设计复审 10 10
• Coding Standar • 代码规范 (为目前的开发制定合适的规范) 20 20
• Design • 具体设计 60 60
• Coding • 具体编码 1800 2000
• Code Review • 代码复审 600 650
• Test • 测试(自我测试,修改代码,提交修改) 150 180
Reporting 报告 90 110
•Test Report 测试报告 30 30
•Size Measurement 计算工作量 30 30
•Size Measurement 事后总结, 并提出过程改进计划 30 50
合计 3090 3700

4.成品展示

BookStore Freeloader

主页。点击“开始查找”按钮即可前往论文查找页。主页左侧是词云,右侧是论文列表。

点击词云上的关键字会在右侧显示含有关键字的论文。

词云下方是一个轮播图和视频。

主页的论文显示分页。

论文显示页。

模糊搜索。可通过标题、摘要、会议年份、关键词或者发表日期进行查询。

表格显示论文列表,最右侧点击可进行查看、修改、删除功能。

点击查看论文详情,点击update按钮可以修改论文,点击delete按钮可以删除论文

点击修改进入论文修改页

点击删除可以删除论文

论文分析页。论文总量对比。使用鼠标滚轮可动态展示。

论文分析页。Top10热词。

5.结对讨论过程

在宿舍遇到难点电脑搬到一起协作讨论

远程协作时解决git提交冲突
image

6.设计实现过程

  • 功能结构图

  • 具体实现

  1. 基于wamp集成环境搭建,优点:Apache是最通用的网络服务器;mySQL是带有基于网络管理附加工具的关系数据库;PHP是流行的对象脚本语言,它包含了多数其它语言的优秀特征来使得它的网络开发更加有效。
  2. 使用yii2.0高级模板制作一个简易网页用MVC(Model-View-Controller)模式修改/删除/新增页面,使得模板接近于目标网站。
  • 修改:修改Gridview控件让它适合搜索论文结果的呈现。修改对关系型数据库关联的ActiveForm来实现修改对论文的修改。
  • 删除:删除不要的新增页面。
  • 新增:在view中新增analysis页面,同时在model和controller新加模型与控制器;首页新增listview部件来进行对关键词云的展示与详情页跳转;搜索页面重建搜索框。
  1. 编写简单的nodejs语句插入json数据到mysql中完成对paper数据库的建立
  2. 使用火狐的调试模式调试网页css样式
  3. 预计使用highcharts展示图谱,实现过程中发现echarts的图谱更具有动态性,最终选择引用后者的代码作为模板。
  4. 最终使用阿里云服务器ecs部署线上环境

7.关键代码说明

1、词云实现
关键词模型类

class KeywordCloud extends widget
{
public $keywords;
public function init()
{
    parent::init();
}
public function run()
{//关键词区分
    $keywordString='';
    $fontStyle=array("6"=>"danger",//红色
                    "5"=>"info",//浅蓝色
                    "4"=>"warning",//黄色
                    "3"=>"primary",//蓝色
                    "2"=>"success",//绿色
);
foreach ($this->keywords as $keyword=>$weight)
{//根据点击事件显示
    $url = Yii::$app->urlManager->createUrl(['site/index','PaperSearch[keywords]'=>$keyword]);
    $keywordString.='<a href="'.$url.'">'.
            ' <h'.$weight.' style="display:inline-block;"><span class="label label-'
            .$fontStyle[$weight].'">'.$keyword.'</span></h'.$weight.'></a>';
}
sleep(3);
return $keywordString;
}
}

首页显示关键词云

<li class="list-group-item">
    <?= KeywordCloud::widget(['keywords'=>$keywords])?>
</li>
  1. gridview展示论文列表

     <?= GridView::widget([
     'dataProvider' => $dataProvider,
     'pager' => [//页面跳转快捷键
         'firstPageLabel' => '第一页',
         'lastPageLabel' => '最后一页',
     ],
     'columns' => [
         ['class' => 'yii\grid\SerialColumn'],//表头
         [
             'attribute' => 'title',
             'format'=>'raw',
             'value'=>function($model){
                 return "<div style=\"width:150px;display: -webkit-box;//文本溢出处理
                                     -webkit-box-orient: vertical;
                                     -webkit-line-clamp: 3;
                                     overflow: hidden;\">".$model->title."</div>";
             },
         ],
         [
             'attribute' => 'abstract',
             'format'=>'raw',
             'value'=>function($model){
                 return "<div style=\"width:300px;display: -webkit-box;
                                     -webkit-box-orient: vertical;
                                     -webkit-line-clamp: 4;
                                     overflow: hidden;\">".$model->abstract."								</div>";
             },
    
         ],
         [
             'attribute' => 'typeandyear',
             'format'=>'raw',
             'value'=>function($model){
                 return "<div style=\"width:110px;white-	                   space:nowrap;overflow:hidden;text-overflow:ellipsis\">".$model->typeandyear."</div>";
             },
    
         ],
         [
             'attribute' => 'keywords',
             'format'=>'raw',
             'value'=>function($model){
                 return "<div style=\"width:150px;display: -webkit-box;
                                     -webkit-box-orient: vertical;
                                     -webkit-line-clamp: 3;
                                     overflow: hidden;\">".$model->keywords."</div>";
             },
    
         ],
         [
             'attribute' => 'releasetime',
             'format'=>'raw',
             'value'=>function($model){
                 return "<div style=\"width:120px;white-	space:nowrap;overflow:hidden;text-overflow:ellipsis\">".$model->releasetime."</div>";
             },
    
         ],
         [
             'attribute' => 'link',
             'value' => function ($model) {
                 return Html::a($model->link, "{$model->link}", ['target' => '_blank']);
             },
             'format' => 'raw',
         ],
    
         ['class' => 'yii\grid\ActionColumn'],//分页
     ],
    
     ]); ?>
    

3、分析图表

<div class="site-index">

<div class="container">
    <script type="text/javascript"	src="https://cdn.bootcss.com/echarts/3.7.0/echarts.min.js"></script>//外部js表

    <div class="chart">
        <div id="chart1" style="width: 800px;height:400px;float: left">
        <script type="text/javascript">
            // 基于准备好的dom,初始化echarts实例
            var chartDom = document.getElementById('chart1');
            var myChart = echarts.init(chartDom);
            var option;
            var meeting = 3;//三大会议
            var categoryCount = 18;//年份

            var xAxisData = [];
            var customData = [];
            var legendData = [];
            var dataList = [];

            legendData.push('trend');//趋势展示
            var encodeY = [];
            for (var i = 0; i < meeting; i++) {
                legendData.push(('ICCV') + '');
                legendData.push(('ECCV') + '');
                legendData.push(('CVPR') + '');
                dataList.push([]);
                encodeY.push(1 + i);
            }

            for (var i = 0; i < categoryCount; i++) {
                var val = Math.random() * 1000;
                xAxisData.push(i+2003);
                var customVal = [i];
                customData.push(customVal);

                for (var j = 0; j < dataList.length; j++) {
                    var value = j === 0
                        ? echarts.number.round(val, 2)
                        : echarts.number.round(Math.max(0, dataList[j - 1][i] + (Math.random() - 0.5) * 200), 2);
                    dataList[j].push(value);
                    customVal.push(value);
                }
            }

            function renderItem(params, api) {
                var xValue = api.value(0);
                var currentSeriesIndices = api.currentSeriesIndices();
                var barLayout = api.barLayout({
                    barGap: '30%', barCategoryGap: '20%', count: currentSeriesIndices.length - 1
                });

                var points = [];
                for (var i = 0; i < currentSeriesIndices.length; i++) {
                    var seriesIndex = currentSeriesIndices[i];
                    if (seriesIndex !== params.seriesIndex) {
                        var point = api.coord([xValue, api.value(seriesIndex)]);
                        point[0] += barLayout[i - 1].offsetCenter;
                        point[1] -= 20;
                        points.push(point);
                    }
                }
                var style = api.style({
                    stroke: api.visual('color'),
                    fill: null
                });

                return {
                    type: 'polyline',
                    shape: {
                        points: points
                    },
                    style: style
                };
            }


            option = {
                title: {
                    text: '论文数量对比',
                },
                tooltip: {
                    trigger: 'axis'
                },
                legend: {
                    data: legendData
                },
                dataZoom: [{
                    type: 'slider',
                    start: 50,
                    end: 70
                }, {
                    type: 'inside', 
                xAxis: {
                    data: xAxisData
                },
                yAxis: {},
                series: [{
                    type: 'custom',
                    name: 'trend',
                    renderItem: renderItem,
                    itemStyle: {
                        borderWidth: 2
                    },
                    encode: {
                        x: 0,
                        y: encodeY
                    },
                    data: customData,
                    z: 100
                }].concat(dataList.map(function (data, index) {
                    return {
                        type: 'bar',
                        animation: false,
                        name: legendData[index + 1],
                        itemStyle: {
                            opacity: 0.5
                        },
                        data: data
                    };
                }))
            };
            option && myChart.setOption(option);
        </script>
        </div>
    </div>

</div>
4. nodejs代码
const axios = require('axios');
const cheerio = require('cheerio');
const getPostTitles = async () => {
try {
	const { data } = await axios.get(
		'https://dblp.uni-trier.de/db/conf/iccv/index.html'
	);
	const $ = cheerio.load(data);
	const postTitles = [];
	$('span.title').each((_idx, el) => {
		const postTitle = $(el).text()
		postTitles.push(postTitle)
	});
	return postTitles;
} catch (error) {
	throw error;
	}
};
getPostTitles()
.then((postTitles) => console.log(postTitles));

5.视频播放代码

<iframe width="355" height="300"
                        src="https://www.youtube.com/embed/ZoWKrxNC3QM"
                        title="YouTube video player"
                        frameborder="0"
                        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                        allowfullscreen></iframe>

8.心路历程和收获

221801406李荣臻:

  1. 刚看到这份作业的时候以为它只是一份普通的两个人短时间内可以完成的作业。可是当同学们一致反对的时候我回头再细读作业要求和时间规定才明白里面竟暗藏玄机。许多功能并没有像我第一次查阅的那样浅显。还是同学们一针见血指出难点。我对作业量还不够敏感,或许只有踏上山巅站在一定的高度上才能仰望到更高的山峰。这就是庄子所追求的“吾生也有涯,而知也无涯,以有涯随无涯,殆已。”
  2. 除了满课,实训,每天都花了的大把时间在学习和实践上,很累很充实。
  3. 本来想按原计划用python实现附加爬取功能,最终选择了更熟悉的nodejs爬取文章到数据库
  4. 对Yii2.0有了更深刻的理解,学习了能够在服务器端运行 JavaScript 的开放源代码、跨平台 JavaScript 运行环境的nodejs.每天5小时+的编码量使我的编程能力有了很大的提升.
    5.现在就想睡个好觉image

221801426林泽坤:

  1. 我和队友的理解一样,古希腊哲学家芝诺说过,人的知识好比一个圆圈,圆圈里面是已知的,圆圈外面是未知的。你知道的越多,圆圈就越大,你不知道的也就越多。但小圆也在不断变大。
  2. 实现关键词云是本次作业中较难的部分,在上面花了很久的时间,最终词云的浮现和点击相应的分类文章能跳转到对应页面很感动。
  3. 和队友研究了好几天的根据关键词直接从论文网站新增爬取文章无果,攻克失败只好放弃。
  4. MVC的框架的反复使用修改让我受益匪浅。这和我本学期的学习目标javaee的三层架构有点类似:都是为了解耦和、提高代码复用。此外,用git协作模式合作过程虽然曲折但结果还是令人满意的。

9.评价结对队友

林评价李:
队友的学习能力很强,搭建服务器大部分工作都给他完成了。我以为开学更忙他只剩更少的时间编程。但没想到催他开始以后就停不下来了,之后每天高强度编程让我看到了压力就是动力。这只能用一张图概括image
李评价林:
很快啊,我还在看checklist林某唰的一下就把环境搭建完成并且开始基本框架的整理。image之后的分工也完成得十分迅速。我第一天根本不想动但是被逼着开始了项目。如果有机会下次还希望跟这样执行力强的队友合作

posted @ 2021-03-31 22:28  至沁  阅读(146)  评论(8编辑  收藏  举报