福大软工1816 · 第五次作业 - 结对作业2

软工实践-第五次作业-结对作业2

程晓宏

李翔

github

具体分工如下:

  • 晓宏:爬取论文信息,爬虫实现的代码,程序测试环节,附加功能
  • 李翔:命令行自定义参数,加权统计,词组统计,词频统计的功能代码

PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划6090
· Estimate· 估计这个任务需要多少时间2020
Development开发400160
· Analysis· 需求分析 (包括学习新技术)480540
· Design Spec· 生成设计文档18060
· Design Review· 设计复审60120
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)60100
· Design· 具体设计10090
· Coding· 具体编码300210
· Code Review· 代码复审60180
· Test· 测试(自我测试,修改代码,提交修改)120120
Reporting报告3020
· Test Repor· 测试报告2080
· Size Measurement· 计算工作量1515
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划4060
合计19451765

解题思路描述和设计实现说明

爬虫使用

  • 最开始使用的爬虫工具是八爪鱼,简单上手快。但是爬的好慢,而且结果是导入到Excel文件中。还要对Excel文件进行处理,最终经过漫长的手动排版(吐血),完成了论文爬取。
  • 八爪鱼爬取论文截图
    1400702-20181009212755349-1715200076.png
  • 到学校之后,经过舍友的点拨,在他们推荐下了解使用Java用jsoup包进行爬取,在学习jsoup以及HTML知识之后,参考网络上的爬虫代码,编写了Java爬取论文代码:
  • Java爬虫代码
package cpvrpaper;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class CpvrPaper {

    public static void getContent(String URL)
    {
        try 
        {
            File file = new File("C:\\Users\\Administrator\\Desktop\\课程\\软件工程\\result1.txt");
            BufferedWriter bi = new BufferedWriter(new FileWriter(file));
            Document document1 = Jsoup.connect(URL)
                    .maxBodySize(0)
                    .timeout(600000)
                    .get();
            Elements element3 = document1.select("[class=ptitle]");
            Elements hrefs = element3.select("a[href]");
            long count = 0;
            for(Element element6:hrefs)
            {
                String url = element6.absUrl("href");
                Document document2 = Jsoup.connect(url)
                        .maxBodySize(0)
                        .timeout(600000)
                        .get();
                Elements elements1 = document2.select("[id=papertitle]");
                String title = elements1.text();
                bi.write(count+"\r\n");
                bi.write("Title: "+title+"\r\n");
                Elements elements2 = document2.select("[id=abstract]");
                String abstract1 = elements2.text();
                bi.write("Abstract: "+abstract1+"\r\n"+"\r\n"+"\r\n");
                count++;
            }
            bi.close();
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException
    {
        String url = "http://openaccess.thecvf.com/CVPR2018.py";
        getContent(url);
    }
}

代码组织和内部实现设计

类设计和程序框架如图
1092183-20181009001147284-517181280.jpg
1092183-20181009001158561-1834707956.jpg

算法关键及流程图

最主要的三个函数

  • count1()——字符数和行数统计
    大致思路和作业一相同,略微做一些调整

1092183-20181009001313355-997826848.jpg

  • count2()——带权值的词频统计
    增加了权值判断部分,标记sg用来标记当前单词所属哪一度分

1092183-20181009001331523-41359555.jpg

  • count3()——词组频率统计
    思路:逐行读取,将每个单词分开存储到字符串数组中,然后按照所需长度将其取出,合并成词组,再进行统计。
    1092183-20181009001341465-442693306.jpg

附加题设计与展示

  • 在改进了Java代码之后,增加了对作者和PDF下载链接的爬取,结果展示如下,详见GitHub result2.txt

1400702-20181009214012311-1998529585.png

  • 为了直观的看到CVPR论文热点词汇,利用Python生成了热点词汇词云,结果展示如下

1400702-20181009214305740-1166441051.png

1400702-20181009214340610-57441062.png

  • 代码如下:
import wordcloud
from scipy.misc import imread
f = open("test.txt","r",encoding="utf-8")
mask = imread("D:\PCcode\羊.jpg")
t = f.read()
f.close()
w = wordcloud.WordCloud(width = 1000, height = 700 , background_color= "white",stopwords={"based","human","using","well","given","ale",\
   "work","loss","the","for","in","of","with","by","in","and","to","on","are","from","as","is","which","we","that","this","two","it","one","can",\
    "both","an","these","be","all","or","over","make" ,"such","while","use","also" },mask= mask)
w.generate(t)

w.to_file("cvprwordcloud5.png")

关键代码解释

  • 自定义参数部分代码:通过赋值,形成类似开关的功能,将参数传入函数,调用需要的功能。
    for (i = 0; i < nt; i++)
    {
        if ((**(argv + i)) == '-')
        {
            switch (*(*(argv + i) + 1))
            {
            case 'i':
                in.open(argv[i + 1]);
                break;
            case 'o':
                out.open(argv[i + 1]);
                break;
            case 'w': 
                if (argv[i + 1] == "1")
                    weight = 1;
                else
                    weight = 0;
                break;
            case 'n':  
                sscanf_s(argv[i + 1], "%d", &topn);
                break;
            case 'm':  
                sscanf_s(argv[i + 1], "%d", &cpw);
                break;
            }
        }
    }
  • 权重判断部分:设置sg,当读到Title时为1,说明这时读到的单词都是属于Title中的,当读到Abstract时为2,说明这以后读到的单词都是摘要里的。
if (stemp == "Title")
{
    sg = 1;
}
if (stemp == "Abstract")
{
    sg = 2;
}

// 只展示出部分代码
if (sg == 1)
{
    My.insert(unordered_map<string, int>::value_type(stemp, 10));
}
if (sg == 2)
{
    My.insert(unordered_map<string, int>::value_type(stemp, 1));
}
  • 自定义词组长度统计:这一部分因为没有想到更好的办法了就只能暴力了。思路是逐行读取文本,将每个单词分开存储到字符串数组中,然后按照自定义词组长度将其取出,合并成词组,再进行统计。
while (ss >> stemp)
{
    strarr[strnum] = stemp;//将每一行的单词逐个存入字符串数组中
    strnum++;
}
for (int i = 0; i < strnum - cpw + 1; i++) //遍历strarr,每cpw个单词合并
{
    cpwtp = "";
    for (int j = 0; j < cpw; j++)
    {
        cpwtp += strarr[i + j];
        if (j != cpw - 1)
            cpwtp += ' ';
    }
    unordered_map<string, int>::iterator it = My3.find(cpwtp);
    if (it == My3.end())
    {
        My3.insert(unordered_map<string, int>::value_type(cpwtp, 1));
    }
    else
    {
        My3[cpwtp]++;
    }
    for (int z = 0; z < 10000; z++)
        strarr[z].clear();//清空
}

性能分析和改进

改进思路

  • 在整个文本处理过程,最消费时间的就是单词或数组的存入和查询了。对于这一点,采用unordered_map容器进行存储。虽然空间复杂度大,但是时间复杂度低,当对大文本进行处理时,能节省更多的时间
  • 对于词组统计方面,因为才用了二重循环,如果一次读入的单词量太多的话也会消耗大量的时间。这一点就有待改进了。

展示性能分析图和程序中消耗最大的函数

有权重统计时,排序功能函数占了最主要的性能
1092183-20181009221321598-413804764.png

在进行词组统计时,毫无疑问词组的划分和统计占用了绝对的资源
1092183-20181009222531896-1787289134.png

单元测试

  • 在单元测试时,没有在代码编程时就介入编写单元测试用例,导致了函数与单元测试的分离,单元测试编写时有一定困难。
  • 编写了十个用例,分别测试了- w参数权重测试,- n 参数 自定义输出测试,- m 词组测试,字数测试,词数测试,行数测试,空白文档测试
  • 部分代码:
TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(LineCounttest1)
        {
            char f[] = "C://Users//Administrator//source//repos//wordcount//Debug//input.txt";
            ifstream in;
            in.open(f);
            WordCount wfc;
            wfc.count1(in);
            Assert::IsTrue(wfc.numLines == 12);
        }

        TEST_METHOD(CharCounttest1)
        {
            char f[] = "C://Users//Administrator//source//repos//wordcount//Debug//input.txt";
            ifstream in;
            in.open(f);
            WordCount wfc;
            wfc.count1(in);
            Assert::IsTrue(wfc.numChar == 2977);
        }

        TEST_METHOD(WordCounttest1)
        {
            char f[] = "C://Users//Administrator//source//repos//wordcount//Debug//input.txt";
            ifstream in;
            int w = 0;
            in.open(f);
            WordCount wfc;
            wfc.count1(in);
            Assert::IsTrue(wfc.numWords == 281);
        }
  • 截图
    1400702-20181009211959887-660303916.png

GitHub的代签入记录

1092183-20181009220854556-2096044214.jpg

遇到的代码模块异常或结对困难及解决办法

  • 结对过程中没有实现规定好代码规范,源码的注释不够详细

    问题描述

  • 问题1:结对过程中没有实现规定好代码规范,源码的注释不够详细,编码与测试分离
  • 问题2:使用爬虫工具爬取速度慢,数据处理耗费时间,没有找到一款可以符合要求成品爬虫工具
  • 问题3:英文人名分词不熟练,对文本的处理能力太弱

    尝试和结果

  • 针对问题1,在测试的时候,真的很痛苦,首先要理解代码,但是队友给的注释太少了,理解代码花了很久时间,最终还是靠沟通完成,再写单元测试的时候,因为编码和测试的分离,导致了函数的编写没有面对测试单元,函数接口不明显,这给测试带来了很大的麻烦。导致测试不是很全面,只能针对部分功能进行测试。
  • 针对问题2,没有学习爬虫相关知识时,只在网上找了几款爬虫工具,但是效果都不怎么好,最后选择了八爪鱼作为爬虫工具,但是爬取速度太慢,爬了快3个小时,导出数据时不能自定义输出格式。对爬出后的Excel表格还要导出到txt进行数据处理!!天啊,我当时居然傻傻的人工排版,900多条,排到吐血。之后舍友给我介绍了jsoup包让我对照着网络上的爬虫样例学习,刚开始学习爬虫时很吃力,很多不懂,还要学习HTML的相关知识,在写爬虫时,舍友给了我很多帮助,感谢感谢(给你们加鸡腿)。最后用Java实现了爬虫爬取。
  • 针对问题3,最初在考虑拓展功能实现时,有想到用Python的jieba库和wordcloud库进行相关可视化处理。之后发现了一款很有用的可视化工具gephi。这工具真的很强大,本来想把爬取出来的作者信息进行关联度处理,但是之前是做中文分词和中文人物的关系图,到了英文人名,处理就出了问题,想法实现不了,只能作罢。

    收获

  • 终于写出了单元测试!!!!! 太感动了,第一次个人作业时单元测试老是出问题,只能手动测试,这次终于写了出来。
  • 学习了爬虫的相关知识,对爬虫有了一些了解,数据处理能力真的太重要了!!!!特别是当数据量很大的时候,有一项拿得出手的数据处理技术真的重要。
  • 对Python复习了一下,还了解了一款强大的数据可视化处理软件gephi,在以后可以利用这款软件做一些酷炫的图。

    评价队友

  • 队友很好,因为他负责功能模块编写,也是很辛苦,在测试时发现问题跟他反馈,都会认真听取意见并改正。在项目后期总结的时候也尽职尽责,很棒~两个人合作算是很愉快的。

    学习进度条

    第N周新增代码(行)累计代码(行)本周学习耗时(小时)累计学习耗时(小时)重要成长
    12002001313C++基础复习,VS熟悉
    202001023墨刀使用,axure rp8熟悉,了解原型
    3,43005001225了解爬虫,了解测试工作,Python复习,gephi的初级使用

转载于:https://www.cnblogs.com/Yasin-cxh/p/9762731.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值