所屬課程 | 福州大學軟件工程實踐(2019) |
---|---|
做業要求 | 結對第二次—文獻摘要熱詞統計及進階需求 |
結對學號 | 221600330吳可強、221600331向鵬 |
做業目標 | 提升我的編碼能力,查找資料與學習能力,團隊合做與溝通能力 |
本博客連接 | http://www.javashuo.com/article/p-oasqqmbv-nm.html |
隊友博客連接 | http://www.javashuo.com/article/p-vdvakofs-nm.html |
基本需求github地址 | https://github.com/masgak/PairProject1-Java |
進階需求github地址 | https://github.com/masgak/PairProject2-Java |
實現一個可以對文本文件中的單詞的詞頻進行統計的控制檯程序。
第一步、實現基本功能輸入文件名以命令行參數傳入。html
第二步、接口封裝java
新增功能,並在命令行程序中支持下述命令行參數。說明:字符總數統計、單詞總數統計、有效行統計要求與我的項目相同python
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 20 | 45 |
• Estimate | • 估計這個任務須要多少時間 | 20 | 45 |
Development | 開發 | 720 | 900 |
• Analysis | • 需求分析 (包括學習新技術) | 60 | 30 |
• Design Spec | • 生成設計文檔 | 0 | 0 |
• Design Review | • 設計複審 | 120 | 100 |
• Coding Standard | • 代碼規範 (爲目前的開發制定合適的規範) | 0 | 0 |
• Design | • 具體設計 | 60 | 70 |
• Coding | • 具體編碼 | 720 | 900 |
• Code Review | • 代碼複審 | 300 | 240 |
• Test | • 測試(自我測試,修改代碼,提交修改) | 60 | 90 |
Reporting | 報告 | 180 | 240 |
• Test Report | • 測試報告 | 0 | 0 |
• Size Measurement | • 計算工做量 | 0 | 0 |
• Postmortem & Process Improvement Plan | • 過後總結, 並提出過程改進計劃 | 30 | 50 |
合計 | 2270 | 2710 |
爬蟲部分git
- 工具:python3.7
- 首先要求是爬取論文列表,而且將題目摘要等輸出到文件中。由於python是典型的爬取工具,代碼量較少邏輯較簡單所以咱們選擇這個語言。查看cvpr2018年論文網頁,發現論文基本詳情連接都在id=content class=ptitle中(爬取的連接只是完整連接後半部分),論文列表則存儲在content的表格中。
點擊進入詳情頁就能夠直接看到需求中的題目與摘要都分別存儲在content下的id爲papertitle abstract中
所以此次解題思路的流程圖以下:
常見的python網頁解析工具備:re正則匹配、python自帶的html.parser模塊、第三方庫BeautifulSoup以及lxm庫。
由於此次須要爬取的元素都直接代表了id與class,因此使用BeautifuiSoup能夠直接獲取信息,用其餘的解析器反而須要多寫判斷條件。
BeautifulSoup學習參考:http://www.javashuo.com/article/p-dxnsiaxg-c.htmlgithub
java部分正則表達式
- 一開始看到題目後以爲題目好繁雜,看了好多遍才大體抓住重點,又結合羣裏面的討論又注意到一些本來被我忽略的細節。看到基本要求以爲仍是很簡單的,一個個小功能原本一開始也是打算在一次讀取文件時實現,以後發現有點不方便,加上看到把各個功能獨立出來的要求,就分開實現了。在進階要求中,能夠直接使用前面完成的代碼,把論文爬取結果的文件去掉不須要統計的部分造成一個新文件,用這個新文件統計字符數、單詞數和行數,而單詞和詞組的權重詞頻就用原文件統計。
221600330&221600331 |- src |- Main.java(主程序,能夠從命令行接收參數) |- lib.java(包括全部的統計字符,行數,單詞數等程序) |- file.java(與文件流有關的程序) |- cvpr |- result.txt(爬蟲結果) |- cvpr.python(爬蟲程序,能夠爬取CVPR2018論文列表)
基礎需求有兩個類,主類接收命令參數,lib類包括基本的統計函數
進階需求有三個類,主類接收命令參數,file類包括的函數有算法
public static String clear_String() //去除字符串中的非ASCII碼 public static String rewrite_Txt()//去掉爬取結果中例如「Title: 」、「Abstract: 」、換行符等並寫入一個新文件 public static void writeToFile()//寫入文件
lib類包括的函數有數組
public static int count_Lines()//統計行數 public static int get_Words_Num()//統計單詞數 public static Map<String, String> count_Words()//將單詞與出現次數放入map中 public static int count_Characters()//統計字符數 public static Map<String, String> count_Phrase_frequency()//計算詞組詞頻 public static Map<String, String> count_Word_Frequency()//計算單詞詞頻
其中統計詞組與單詞詞頻函數與count_Words息息相關,這兩函數的輸入結果就有上個函數造成的哈希表。只有先將單詞與出現次數造成一個map,才能進行後續的詞頻與詞組頻率統計。echarts
其中消耗最高的函數爲clear_String(),即去除文本中無關的ascii並重寫到新文件爲主要消耗。dom
代碼覆蓋率(分別爲單詞與詞組)
python:爬取詳情頁連接並循環生成新連接
cvprurl='http://openaccess.thecvf.com/CVPR2018.py' response=requests.get(cvprurl) soup=BeautifulSoup(response.text,'html.parser') for links in soup.select('.ptitle'): #返回每一個超連接 newlinks = 'http://openaccess.thecvf.com/'+ links.select('a')[0]['href']
python:在新鏈接中爬取標題與摘要並寫入文檔
response2 = requests.get(newlinks) #打開連接 soup2 = BeautifulSoup(response2.text,'html.parser') #把網頁內容存進容器 Title = soup2.select('#papertitle')[0].text.strip() #找到標題元素爬取 print("Title:",Title,file=txt)
java:首先按行讀取文件,再判斷讀取到的流是否爲單詞(至少以4個英文字母開頭,跟上字母數字符號,單詞以分隔符分割,不區分大小寫),若是是單詞則讀入hashmap中,每多讀一次出現次數加一,造成最初的map數據。
public static Map<String, String> count_Words(String file_path){ ...................... while ((str = bufferedReader.readLine()) != null) { str = str.toLowerCase(); for (int i = 0; i < (str.length() - 3); i++) { if (i > 0) { if (('a' <= str.charAt(i - 1) && str.charAt(i - 1) <= 'z') || (48 <= str.charAt(i - 1) && str.charAt(i - 1) <= 57)) {// 若是前一個字符是字符或數字 continue; } } if ('a' <= str.charAt(i) && str.charAt(i) <= 'z') { if ('a' <= str.charAt(i + 1) && str.charAt(i + 1) <= 'z') { if ('a' <= str.charAt(i + 2) && str.charAt(i + 2) <= 'z') { if ('a' <= str.charAt(i + 3) && str.charAt(i + 3) <= 'z') {// 找到單詞 int j; for (j = i + 4; j < str.length(); j++) {// 看單詞是否結束 if ('a' > str.charAt(j) || str.charAt(j) > 'z') { if (48 > str.charAt(j) || str.charAt(j) > 57)// 不是數字 break; } } String temp = str.substring(i, j);// 截取字符串索引號i到j區域(包括i,不包括j) // 加到Map裏去 if (map.containsKey(temp)) { int n = Integer.parseInt(map.get(temp)); n++; map.put(temp, n + ""); } else map.put(temp, "1");
該過程的流程圖爲:
java:詞組頻率,在判斷單詞的基礎上加個計數器計算連續出現的單詞,放入字符串數組,若是次數大於詞組長度,每判斷一個單詞就從字符串數組中該單詞前M個組成個詞組。
public static Map<String, String> count_Phrase_frequency(String file_path, int phraseLength, boolean is_weight) .................................... while ((str = bufferedReader.readLine()) != null) { str = file.clear_String(str); str = str.toLowerCase(); // 去掉"title: "和"abstract: " if (str.contains("title: ")) { is_title = true; str = str.substring(0, str.indexOf("title: ")) + str.substring(str.indexOf("title: ") + 7); } else is_title = false; if (str.contains("abstract: ")) str = str.substring(0, str.indexOf("abstract: ")) + str.substring(str.indexOf("abstract: ") + 10); int count = 0;// 計算連續出現的單詞數 String[] words = new String[101];// 存儲連續出現的單詞 for (int i = 0; i < (str.length() - 3); i++) { if (i > 0) { if (('a' <= str.charAt(i - 1) && str.charAt(i - 1) <= 'z') || (48 <= str.charAt(i - 1) && str.charAt(i - 1) <= 57)) {// 若是前一個字符是字符或數字 continue; } } if ('a' <= str.charAt(i) && str.charAt(i) <= 'z') { if ('a' <= str.charAt(i + 1) && str.charAt(i + 1) <= 'z') { if ('a' <= str.charAt(i + 2) && str.charAt(i + 2) <= 'z') { if ('a' <= str.charAt(i + 3) && str.charAt(i + 3) <= 'z') {// 找到一個單詞 int j; for (j = i + 4; j < str.length(); j++) {// 看單詞是否結束 if ('a' > str.charAt(j) || str.charAt(j) > 'z') { if (48 > str.charAt(j) || str.charAt(j) > 57)// 不是數字,遇到分隔符 break; } } String temp = str.substring(i, j);// 截取字符串索引號i到j區域(包括i,不包括j+1)---截取單詞 if (j == str.length())// 一段中以單詞結尾 temp = temp + " "; else temp = temp + str.charAt(j);// 把單詞後面的一個分隔符加到單詞中去 count++; words[count] = temp; if (count >= phraseLength) { temp = words[count - phraseLength + 1]; for (int k = phraseLength; k > 1; k--) { temp = temp + words[count - k + 2]; } temp = temp.substring(0, temp.length() - 1);// 和並後去掉末尾的分割符 // 加到Map裏去 if (is_weight && is_title)// 計算權值爲10:1,而且該詞組在title段中 { if (map.containsKey(temp)) { int n = Integer.parseInt(map.get(temp)); n += 10; map.put(temp, n + ""); } else map.put(temp, "10"); } else { // 不須要計算權值 if (map.containsKey(temp)) { int n = Integer.parseInt(map.get(temp)); n++; map.put(temp, n + ""); } else map.put(temp, "1"); } int n = Integer.parseInt(map.get("count_words_num")); n++;// 總詞組個數加一 map.put("count_words_num", n + ""); } i = j; } else { count = 0; i = i + 3; } // 遇到少於4個字母的單詞,結束count } else { count = 0; i = i + 2; } // 遇到少於4個字母的單詞,結束count } else { count = 0; i = i + 1; } // 遇到少於4個字母的單詞,結束count } else { if ((48 > str.charAt(i) || str.charAt(i) > 57)) {// 遇到分隔符加到加到上一個單詞末尾 words[count] += str.charAt(i); } else { // 遇到數字,結束count count = 0; }
爬取結果與餅圖文件:https://files-cdn.cnblogs.com/files/masgak/Desktop.rar
爬取結果截圖:
餅圖:
pyecharts代碼
# coding=utf-8 from pyecharts import Pie import random attr = ["that","with","this","image", "from", "learning", "network", "which", "model","images"] v1 = [1755, 1473, 1443, 1223, 1096, 971,971,807,760,732] pie = Pie("熱詞出現次數") pie.add("", attr, v1, is_label_show=True) pie.render('pie.html')