網上有很多Python爬蟲的帖子,不排除很多培訓班借着AI的概念教Python,然后爬網頁自然是其中的一個大章節,畢竟做算法分析沒有大量的數據怎么成。
C#相比Python可能笨重了些,但實現簡單爬蟲也很便捷。網上有不少爬蟲工具,通過配置即可實現對某站點內容的抓取,出於定制化的需求以及程序員重復造輪子的習性,我也做了幾個標准公開網站的爬蟲。
在學習的過程中,爬網頁的難度越來越大,但隨着問題的一一攻克,學習到的東西也越來越多,從最初簡單的GET,到POST,再到模擬瀏覽器填寫表單、提交表單,數據解析也從最初的字符串處理、正則表達式處理,到HTML解析。一個NB的爬蟲需要掌握的知識不少,HTTP請求、響應,HTML DOM解析,正則表達式匹配內容,多線程、數據庫存儲,甚至有些高級驗證碼的處理都得AI。
當然,爬爬公開標准不是那么難,比如國家標准全文公開系統。
整個過程需要爬以下頁面:
- 列表頁
- 詳細信息頁
- 文件下載頁
需要處理的技術問題有:
- HTTP請求
- 正則表達式
- HTML解析
- SqlLite數據庫存儲
一、列表頁
首先查看到標准分GB和GB/T兩類,地址分別為:
http://www.gb688.cn/bzgk/gb/std_list_type?p.p1=1&p.p90=circulation_date&p.p91=desc
和
http://www.gb688.cn/bzgk/gb/std_list_type?p.p1=2&p.p90=circulation_date&p.p91=desc。
從中可以看出,GET請求的查詢字符串參數p1值為1和2分別查詢到GB和GB/T。因此,要獲取到標准列表,向以上地址發送GET請求即可。
HttpWebRequest httprequst = (HttpWebRequest)WebRequest.Create(Url); HttpWebResponse webRes = (HttpWebResponse)httprequst.GetResponse(); using (System.IO.Stream stream = webRes.GetResponseStream()) { using (System.IO.StreamReader reader = new StreamReader(stream, System.Text.Encoding.GetEncoding("utf-8"))) { content = reader.ReadToEnd(); } }
標准共N多頁,查看第二頁標准列表,地址更改為:
http://www.gb688.cn/bzgk/gb/std_list_type?r=0.7783908698326173&page=2&pageSize=10&p.p1=1&p.p90=circulation_date&p.p91=desc。
由此可見page參數指定了分頁列表的當前頁數,據此,循環請求即可獲取到所有的標准列表信息。

二、詳細信息頁
獲取到標准列表后,下一步我需要獲取到標准的詳細信息頁,從詳細信息頁中抓取更多的標准說明信息,例如標准的發布單位、歸口單位等。

查看標准詳細頁URL,其值為:
http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=9E5467EA1922E8342AF5F180319F34A0。
可以看出每個標准有個GUID值,在列表頁面中點擊按鈕“查看詳細”,轉到詳細頁。實現這個跳轉的方式,最簡單的是HTML超鏈接,此外還可以是JS腳本,甚至是POST數據到服務器。不同的鏈接方式,自然需要不同的抓取方式,因此需要查看列表頁源碼來分析該站點的實現方式並找到對應的處理方法。

通過分析源碼,可以看到在點擊標准號時,通過JS的showInfo函數打開詳細頁面,由於JS方法傳遞的ID即為詳細頁面的參數ID,因此沒必要去模擬onclick執行JS函數,直接解析到該GUID,GET請求詳細頁面即可。解析該GUID值,可以通過正則表達式方便的抓取到。
獲取到詳細信息頁面后,要解析其中的內容,此時使用正則表達式解析就比較費勁了,可以采用HTML解析。C#解析HTML的第三方類庫有不少,選擇其中一款即可,HtmlAgilityPack或Winista.HtmlParser都是比較好用的。
三、文件下載頁
解析到標准詳細信息后,還需要進一步獲取到標准PDF文件,分析詳細頁面可以看到標准文件下載頁面路徑為:
http://c.gb688.cn/bzgk/gb/showGb?type=download&hcno=9E5467EA1922E8342AF5F180319F34A0

進一步分析PDF文件的URL為:
http://c.gb688.cn/bzgk/gb/viewGb?hcno=9E5467EA1922E8342AF5F180319F34A0。
仍然是那個GUID值,因此可以直接GET請求該地址即可下載標准PDF文件。
至此標准的屬性信息和標准PDF文件都可以下載到了,然后需要將這些信息存儲起來。存儲為SQL Server、Oracle自然比較笨重,即使Excel和Access也不大友好,推薦此類臨時存儲可以使用SqlLite。
string connectionString = @"Data Source=" + dbBasePath + "StandardDB.db;Version=3;"; m_dbConnection = new SQLiteConnection(connectionString); m_dbConnection.Open(); SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); command.ExecuteNonQuery(); m_dbConnection.Close();
