純手工[博客園-博文數據分析]及技術分享(java)


 

        上次我們分析了博客園閃存數據,為什么分析?那是出於個人想看看,意義不大,反正閑着也是閑着搗鼓搗鼓沒什么不好,后來沒有分享技術,這次我們分享一下技術,不過再分享之前,我們先來看看我又趁着,這熱乎勁抓取了一把博文首頁的數據分析了一下(數據來自2013-05-28 08:27至2013-08-26 15:40,大概三個月的時間,共計4k數據,也就是說這三個月總計首頁發布了4k的文章,不錯的效益。這次有點意外3個線程花了1min多一點的時間跑完),熱騰騰的結果出爐了,這次加點個人點評。

博文數據分析

1.1發帖總人數

count

1.2文章發布量top30(看看發布文章數量排行前30的有哪些人?)

文章發布量排行top30

1.3推薦top30(看看推薦量高文章的前30人,看看誰是牛1,牛2,牛3,牛逼,有木有?哈哈哈)

推薦top30

1.4評論top30(文章受到評論排行前30人)

評論top30

1.5閱讀top30(文章閱讀量排行前30,我沒記錯的話,有幾個排行里面靠前的,恰好就是討論島奶車薪資的文章。看看誰是神1,神2,神9)

閱讀top30

1.6每天發帖量

每天發帖量

x軸由於日期太多擠在一起了,為了良好閱讀我截取了日期,將峰值較低的標注了出來,翻看黃歷6-11是星期二,不知為何出現低峰這個貌似不科學?是不是節假日?7-14,8-3日前者是周日,后者是周六,這個可以理解,從圖中可以目測出低峰的基本都是周末的時候、其余都是工作日,大概目測下來平均每天的發文章量保持在45+左右的樣子、還算可以哦、

1.7每天發布人數

每天多少個人發布

同上x軸截取了,可以看出基本和上圖保持一致,這樣可以看出基本每天的發帖是人均一片的樣子、月經貼拉低了人均值,當然也有博文小子拉高了人均值、哈哈哈、

1.8每天所有文章的閱讀總量

每天發布文章的所有閱讀量

同上x軸截取了,可以看出低峰依舊是文章量較少的日期。目測一下每天的文章閱讀總量保持在4w+的數量,哈哈哈,dudu啊網站的流量不少吧,哈哈哈,照這樣計算還不算閃存,其他網站流量,就這個已經夠可以的了。還有博客園網站博文靜態化處理百度、google的檢索之靠前,敢不敢爆爆網站流量?不過沒關系,我前不久看博客園還是極具價值的網站,不錯!

總結:基本就統計了這些,統計這個不是目的,只是簡單了解一下,數據完全真實可靠。有機會抓抓stackoverflow上面的數據分析分析。得出結論博客園人氣高,流量高,文章發布量高。出現三高的勢態,壓力也高,所以這個就不難解釋為什么前不久總是出現高血壓的症狀(500 錯誤),免費的為阿里爸爸做了雲服測試?好了,這個不是大伙關心的問題,下面分享技術。

技術分享

1.方案思路:

我是在我以前寫的一個網絡爬蟲上面擴展出來的(對網絡爬蟲感興趣的可以看看《自己動手寫網絡爬蟲》),由於當時閃存抓取的時候發現不登錄只有一頁的數據,所以我們要想抓取167頁數據,我們要首先登錄賬號,發起http請求get/post請求,解析response,html數據即可,然后保存本地數據庫即可至於如何分析,這個就看你數據分析的能力了。我這里就做了一下簡單的數據查詢。看了看我想看的數據。這里的博文還是套用閃存分析的模塊,只是多加了一個html解析器(用了一下java的jsoup解析html很好,比用C#那個封裝的方便多了,個人覺得是這樣。)思路就是這樣。

2.實現方案:

2.1所需要的工具庫:

jsoup.jar         解析html用(官方:http://jsoup.org/需要神馬下神馬,學學學學學學)

httpclient.jar    發起http(這里不一一列舉了,了解的到httpclient 官方下吧,這里不做入門官方:http://hc.apache.org/httpclient-3.x/

數據庫連接我采用mysql需要mysql-connector-java.jar (這個看你用神馬數據庫)

Highcharts       前端報表庫,很好很強大,個人免費。

ORM              我采用hibernate(這個你也自己學,不入門網站我就不貼了,如果這也要貼網站,那你就不用學java了,不要罵我,這個是編碼人員最基本的常識。不懂可以教,但是教你了,你要是不call google大神官方文檔就是你的錯,扯遠了)

2.2模塊設計:

先看看目錄結構:截圖00

2.2.1發起http get、post請求。這里用到了爬蟲的一個http封裝模塊貼一下圖(這里我用windows live寫上面木有裝代碼插件所以就只能截圖了,諒解)

截圖02

這個方法用了synchronized 由於我的數據抓取是線程池的方式,所以方法安全,而且這個已經是以前封裝好的,所以拿過來直接用了,很好已經適用我這個需求了、不用改直接用。

2.2.2 包裝登陸信息(本來這里可以通過保存cookie到本地,然后每次拿cookie訪問即可,不過為了方便我就直接請求一次完成,登陸完成立刻訪問uri翻頁)

2.2.3 解析response html(這里就用jsoup,具體如何使用看看doc即可,這個東西就像jquery一樣)

2.2.4 分裝entity 交給DAO 通過ORM映射到存到數據庫即可。

2.2.5 報表生成(通過Highcharts 前端報表庫生成,通過后台bao層處理交個servlet,servlet response一個json數據即可)

單向流程就是如上所述這樣,不過考慮數據量比較大,時間有限,加入了線程池、所以還需要補充一個

2.2.6 線程池(靜態化了一個3個線程數的線程池,添加了200個線程進去,這個根據翻頁的數量定。每一個線程控制當前頁的數據從抓取到解析到數據持久存儲,最后關閉線程池)

上面就是基本實現過程,下面是貼代碼呢?還是到這里就結束呢?貼代碼貌似沒意義,下面結合貼圖講解代碼為何這樣實現。根據上面的模塊設計我們一步一步來,http封裝就跳過了,上面已經提過了。

2.3 模塊實現及分析

2.3.1包裝登陸信息

需要登陸,那我們就需要提交登陸所需要的信息然后發起http post請求給server,如果你用過httpclient,那你該知道發起post請求需要實例化一個HttpPost,下面看圖識字。

截圖02

上圖是封裝的一個httppos方法,接受一個url和一個map的參數,url就是發起post提交的url,map就是post需要的參數,其中UrlEncodedFormEntity頂級父類是AbstractHttpEntity,而AbstractHttpEntity是實現HttpEntity接口理清這個關系下面我們來看 ,http.setEntity(HttpEntity httpEntity)看到這個明白了吧,我們的post參數就是通過setEntity設置進去的,而setEntity接受的是HttpEntity,官方API是這樣描述的:An entity that can be sent or received with an HTTP message. Entities can be found in some requests and in responses, where they are optional.這個大概的意思就是提供request提交參數,或者得到response的數據。entity.setContentType("application/x-www-form-urlencoded");這個頭一定要設置,一般情況下server有時候接受一個json有時候接受form,所以我們要根據server的頭規定來設置想要的,如果是json我們就要entity.setContentType("application/json");還可以通過httpPost.setHeader("Content-type", "application/json");來設置具體這里就不嘮叨了,就是設置好頭信息,及參數。(官方參考API:http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/index.html

下面以博客園為例完整的登陸:

截圖03

通過單例化的httpClient 提交httpPost,Map就是設置cnblogs需要提交的參數,這里的httpResponse,getEntity().getContent();就是獲取的響應流,前面我們提到的HttpEntity 就是從過這個來獲取到的。這里我通過靜態化方法saveHTMLToData();讀取成String放到內存中,包裹登陸完畢,接下來就是解析html了。

2.3.2 解析response的data

解析我采用java友好的jsoup庫,具體API請參考這里(http://jsoup.org/apidocs/)這里我不做多解析,根據響應得到的數據解析的方法也大致不同。講解API這個還不如你自己翻里面都是官方解釋,我就不混淆視聽了。

2.3.3 ORM映射持久到數據庫

通過上面的解析我們分裝給定義的entity對象,然后讓hibernate保存到數據庫即可。這里大家根據自己喜好自行選擇,跳過,不是文章重點。

2.3.4 報表生成

通過我們獲取到的數據通過查詢生成報表,報表我選擇的是Highcharts個人免費,API文檔在這里http://api.highcharts.com/highcharts 官方:http://www.highcharts.com/你可以自己下載例子,里面很多的報表,選擇自己的喜歡的,后台解析成前端data需要的數據格式數據即可,一般都是json數據,根據報表的復雜程度可能需要json對象數組等。這個看看官方定義。

2.3.5 線程池

好了,上面跳了很多有人就會說,那你這不是教我看文檔去嘛?有神馬分享的?線程池這個或許才是我認為的重點,線程大家多少都聽過實際項目用過的沒幾個吧?我們先不買乖子,先講講我這里的實現方式。通過上面的一些步驟我們邏輯處理完了,現在該線程池閃亮登場了,貼圖識字。

截圖04

好了,上面就是我的線程池class,也是我的main函數入口,不錯run一下這個數據控制台就稀里嘩啦的下雨般跑,有點像帝國的綠色背景。不閑扯我們說正題,通過Executors newFixedThreadPool(int nThreads) 我們可以生產一定數量的線程,提供給ExecutorService來管理我們生產的線程,至於為什么選擇newFixedThreadPool(int nThreads)這個方法 API中是這樣描述的:“創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。”也就是說我們創建固定數量的線程,我這里是3個,我們就以3個為例子,線程池幫我們管理了3個線程,運行事如果execute數大於我們線程池數3,3個線程同時搶占cpu資源(忽略安全問題等會說),當某一個線程運行完畢,只要我們后續還有線程在等待執行,這里的等待指的就是pool.execute(new Thread());那么交出cpu鎖的那個線程池,處於空閑狀態(也就是說3個線程池中,同時運行3個線程,其中1個已經運行完畢了,2個還在運行)只要后續還有線程執行,立刻加入到線程池可執行的隊列拿到CPU鎖線程開始執行,直到完畢,交出CPU鎖給下一個,直到所有的線程池線程執行完畢。

好了有些人聽到這里有點蒙了,不要桌急我們再理一下,你如果用過數據庫連接池,這個和那個大致基本相同,類似於一個大池子里面已經為我們准備好了泡澡的水,等我們洗,你洗完了走人,后面還會有人排隊的人來洗,而不是來一個人放一次水。CPU鎖,可能有的人不知道或者不理解,其實我們的線程每次執行都是需要獲取CPU鎖這樣才能執行,誰來分配不知道,為什么?線程就是像一群狼一樣,一旦放開就控制不住誰先搶到只有看運氣了,哈哈哈!前幾天有人還問道為什么他的線程運行順序不一樣,就是這個原因,那我們認為能不能控制?可以通過線程的優先級,與線程休眠類似,線程的優先級仍然無法保障線程的執行次序。只不過,優先級高的線程獲取CPU資源的概率較大,優先級低的並非沒機會執行。具體可以翻看API里面有具體函數的設定。

說到這里我們有一點不可以不談,有些人總是曬自己的機器是多少核,多少線程的?哈哈,告訴我的小伙伴們一個秘密不要妥妥的呆哦,其實如果你玩游戲那確實好,或者你做科研運行大型多線程的軟件,像分布式運行計算機幾個人玩的那確實杠杠的。但是作為我們開發的機器一般都是個人pc性能根本凸顯不出來,而且反而可能沒有單核處理好,為什么?我們個人的pc一般高數量級別的多線程軟件少,而且我們基本都是單用戶模式,一個人操作,你覺得你的pc會運行最佳嘛?那從哪里看性能好?cpu 的主頻,這個才是王道,主頻高處理效率高,單用戶模式下單位時間內,軟件處理事件的能力提高。舉個筆者的例子,筆者新買的hp i5 1.8主頻 4G內存(hp入門薄金剛超級本),和現在筆者的hp i3 2.5主頻 4G內存,兩個沒辦法比(新機器遠不如老機器),兩個都是同廠商主板都一樣,操作系統都是正版。新機器動不動就超頻,CPU100%滿血,筆者那個心疼啊!可是還在服役的老機器我累個神eclipse,vs2010常用開發工具等等同時開,都運行不帶卡的,CPU70%. 神馬6核8核10核,都是瞎扯淡(個人正常使用而言),你要是主頻上去,單核照樣杠杠的。這個尤其在手機上凸顯的明顯,這里不吐槽。

回到線程,線程不是我們想用就能用的,有的情況下多線程是好事,但並非所有的情況下適合多線程。所以我們要在需求上考慮我們的需求是否適合多線程運行,適合多線程,是不是就可以了?也不完全是,還要考慮多少線程數是我們運行處於最佳狀態,這個要根據我們處理的任務量,機器的CPU性能等等。我這里選擇3個從個人筆記本性能和服務器性能來考慮。沒必要設置太多。

截圖05

上圖就是剛剛實例化給線程池的線程,該線程綁定了一個ThreadPostCnblogsTest 類就是 執行請求及解析數據,save數據庫用的。

為了保持線程安全download木有返回值,采用synchronized 修飾。

最后有一點要講的,多線程最危險的無非就是線程共享數據問題,有時候我們聲明的全局變量在多線程下會出現內存篡改,正是線程所為,個人認為最好的方法就是變量局部化,哪里用哪里聲明,有時候需要共享,那就采用方法return 該class采用synchronized  修飾確保安全,前幾天和一個社區coder討論他說一般還可以采用進程方式,即提高擴展也解決數據共享,確實不錯,還有一種就是數據庫方式共享數據。

over到這里完畢!累的稀里嘩啦。感謝您抽寶貴的時間閱讀,有問題歡迎討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM