從零開始的爬蟲專案(一)

kdai_910hr發表於2020-04-23

引言

本人是隻有c語言基礎的程式設計本科小白,進入大學之前從來沒有接觸過程式設計知識。ddl是生產原動力,不得不開始從零學習如何編寫新聞爬蟲,旨在發現問題解決問題,總結心得,記錄生活,而非提供專業方面的建設性意見。

由於從未學過JavaScript語言,空手做起來難於登天。課程老師給我們這樣的專案的時候也考慮到了這一問題,會同步在課程中教授nodejs語法,也會展示部分爬蟲樣例,對我來說如何參照程式碼,掌握每一步的意圖並仿照進行別的網站的爬蟲專案才是這個作業於我有意義的的地方。

實驗要求

  1. 選取3-5個代表性新聞網站建立爬蟲
  2. 針對不同網站的新聞頁面進行分析,爬取出編碼、標題、作者、時間、關鍵詞等結構化資訊
  3. 儲存到資料庫中
  4. 建立網站供對爬取內容進行分項全文搜尋,給出所查關鍵詞的事件熱度分析

第一次實踐

要想爬取編碼、作者等結構化資訊,學會分析不同網站的新聞頁面是關鍵。我把首個爬取目標設為新浪新聞網。

使用Chrome瀏覽器開啟“新浪新聞網”(https://new.sina.com.cn) , 隨便點開首頁的一則新聞,按F12 點選“Elements"即可檢視該新聞頁面的html檔案,點選左上角箭頭,移動游標至新聞頁面各分割槽還可看到html檔案中與之相對應的語句。

當然,更一般的,新聞頁面右鍵”檢視原始碼“即可在新建頁面中看到完整的html檔案,我還是更傾向於這種的,比較直觀清晰。
在這裡插入圖片描述
接下來就是分析新聞頁面的html檔案,找到關鍵資訊所處的位置。

在這裡插入圖片描述

仔細閱讀的話不難發現,在新浪新聞網的一般新聞網頁中,關鍵詞放在名為“keywords”的meta標籤中,而標題放在title標籤中。

在這裡插入圖片描述
又如,概要放在meta property=“og:description”(meta property=og表示同意了網頁內容可以被其他社會化網站引用)標籤中。

這種模式適用於新浪新聞網的大部分新聞頁面。確定了一個網站各關鍵資訊所處位置後,方能定義其讀取方法:

1 var title_format = "$('title').text()";
2 var keywords_format = "$('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
3 var desc_format = "$('meta[property=\"og:description\"]').eq(0).attr(\"content\")";
4 <meta id=xxxxxxx>    對應    "$('#xxxxxxx')."
5 <meta class=xxx>     對應     "$('.xxx')."

這裡給出涉及到的方法的定義和用法供查閱:

而這些都只是對於指定頁面內相關元素的爬取,想要一次性爬取大量新聞頁面就需要在種子頁面上爬取全部的頁面連結並抽出其中符合新聞連結規則的連結。
隨便以一個新聞連結(https://news.sina.com.cn/c/2020-04-23/doc-iircuyvh9369753.shtml)為例。

可以看出一般規則為 “http://news.sina.com.cn/” + c(//任意字母)/ + xxxx-xx-xx/ + doc-aaaaaaaaaaaa.shtml

為此我們只需查詢不同部分 c(//任意字母)/ + xxxx-xx-xx/ + doc-aaaaaaaaaaaa ,也就是 任意字母/xxxx-xx-xx/doc-字母數字串.shtml 即可。接下來需要使用JavaScript的正規表示式,根據規則,表示式應為

var url_reg = /(\w{1,2})\/(\d{4})-(\d{2})-(\d{2})\/doc-(\w+).shtml/;

將獲得的大量不同格式的連結稍加編輯統一為以http://開頭的連結就能用於後續操作了。

後續就是建立擁有多個屬性的一個物件,並將結構化資訊賦值給該物件對應的不同屬性,並將該物件通過"stringify"(*相關用法
*)的方法轉換成JSON字串並以"writeFileSync"(相關用法
)方法寫入一個JSON檔案並儲存。

遇到的問題

網站通訊協議不統一

在種子頁面獲取符合正規表示式的有效連結後需要對其格式進行統一,但新浪新聞網頁面包含的連結中混雜著支援HTTPS協議以及HTTP協議的不同連結,

if (href.toLowerCase().indexOf('http://') >= 0||
href.toLowerCase().indexOf('https://') >= 0) myURL = href;

因而兩種情況均需要考慮,否則就會出現錯誤的連結補足:

在這裡插入圖片描述

新浪網站根據不同分割槽還有不共用一套關鍵資訊存放規則的子網站

在這裡插入圖片描述
當我在執行程式時發現我建立的物件某些屬性的值為undefined,因而在用replace方法進行部分內容替換時讀到undefined會終止程式並報錯“Cannot read property ‘replace’ of undefined ”。我順著讀取成功返回的連結找到原網址,並檢視原始碼,發現主網站與子網站在某些關鍵資訊處存在差異,以釋出日期為例:

 <span class="date">2020042309:33</span> 
 //此網站地址為//mil.news.sina.com.cn/china/2020-04-23/doc-iirczymi7859278.shtml
 //其位於新浪子網站“新浪軍事網”
<meta property="article:published_time" 
content="2020-04-23T12:36:38+08:00" />
//網址為//news.sina.com.cn/c/2020-04-23/doc-iircuyvh9369753.shtml
//位於新浪主網站

而這並非全部,新浪有著各種以 “mil” ,"finance"等為字首的子網站,一一通過條件判斷列舉過於麻煩,且對我這種小白也不友好,因而我決定在種子頁面抽有效連結的過程中新增限制條件,達到只抽取主網站新聞連結的目的,這就需要建立一個滿足抽取在“news.sina.com.cn”前沒有“finance.” 及 “mil.”等字首的正規表示式。可以說正難則反,我只需要在利用之前的正規表示式篩選出有效連結的基礎上,保留不符合“.news.sina.com.cn”形式的連結就好了:

1 var url_exreg = /[.]news.sina.com/;
//先寫出不符合條件的連結滿足的正規表示式
2 if (url_exreg.test(myURL)) return;
//再在抽取連結的迴圈中新增該判斷條件,若符合則跳過並進行下一個迴圈

如此一來就用一種極不完美的方式解決了新浪子網站引發的程式報錯,雖然這樣一來部分新聞就無法爬取了,但是對於一個新人來說能爬到新聞就不錯了!
在這裡插入圖片描述

小結

一天的時間裡我嘗試瞭如何分析新聞頁面的html檔案,並基本學會了如何寫不同格式的JS正規表示式。雖然遇到了不少問題,報了一堆錯,但通過百度對各種JS方法的用法有了一定的瞭解,並在此基礎上分析出問題源頭,成功爬取到了不少新聞內容,可以說是對我付出的時間的最好回報。
之前總是靜不下心來,怕難,怕碰壁,對於未知總是抱有畏懼的態度。而這一天的時間裡我在讀寫程式碼的過程中也學到了很多之前被灌輸但是不常用過一會就會忘的語法知識,也算是給予了我一點信心吧。雖然我比不上那些爬了很多網站,精通不少JS方法的人,但是人只要和過去的自己比就好了,做到不悔即可。

相關文章