Python x 網路爬蟲

今天來分享一個可以從網路獲取資料的技術:叫「網路爬蟲」,英文稱做Web Crawler or Web Scrapying,以下簡稱爬蟲,這篇文章將會分成「一、原理介紹」以及「二、程式實作」,如果有基本概念的朋友們,可以直接跳至「二、程式實作」開始,我將會以iPeen愛評網(以下簡稱iPeen)作為範例用Python來實作簡單的爬蟲,希望透過此篇入門介紹,能讓大家都會寫基本的爬蟲,抓到你想要的資料。

一、基本概念

爬蟲是一個將網路上的檔案下載下來然後做一些處理的程式,一般我們在網路上看到的網頁、圖片或影片等,都算是一個檔案,只是透過瀏覽器我們可以看到正確的結果,例如:網頁檔案本身是一個HTML檔案,瀏覽器幫我們轉成我們看得懂的網頁介面(如下圖所示,操作方式為在Chrome按右鍵的[檢視網頁原始碼])。

iPeen首頁的HTML原始碼檔案
瀏覽器將HTML原始碼檔案轉成我們看得懂的頁面

為何要講這個呢?

因為爬蟲所要處理的,是沒有透過瀏覽器處理的HTML原始碼,當我們看到網頁有我們要抓的資料之時(以iPeen為例,我們要抓店家的資訊,如下圖,操作方式為在網頁上游標移至店家名稱連結,然後按下右鍵按[檢查])

圖片來源:http://www.ipeen.com.tw/search/taiwan/000/1-0-0-0/

我們必須知道這些在網頁上我們所看到的店家名稱是在HTML原始碼所對應的位置(如下圖),必須看看這些這些程式碼有沒有什麼樣的規律或特徵,以剛剛所講述的店家網址名稱為例,我們可以看出店家連結是 <a> 標籤,擁有 data-label=”店名” 獨特可以找出店家連結的CSS屬性。

爬蟲兩大工作

  1. 下載檔案:在給定一個網址時,我們可以使用HTTP協定的方法去對於伺服器送出Request請求,並且取得Response回應,在我們爬蟲一般的情況就是對於伺服器送出GET Request來取得HTML檔案的Response,在取得HTML檔案後接著我們就可以進行第二步驟:分析內容。
  2. 分析內容:擁有HTML之後,我們就可以透過搜尋、正則、字串處理、切分、取代等的各種技巧來將HTML過濾抓到我們所要的資料,例如上述例子所提到的店家連結標籤,可以用正則找到<a>標籤,然後用搜尋過濾留下CSS包括data-label=”店名” 的標籤,然後再用正則去除標籤只留下連結和店家名稱。

二、程式實作

首先,我們先安裝必要的第三方程式套件,有了這些套件加上Python本身提供的套件可以加速我們的開發工作,這邊我們使用Python3來開發,上述爬蟲兩大工作「下載檔案」是使用Requests來實作,而「分析內容」是使用BeautifulSoup來實作,這兩個套件安裝方式可以參考官網,不再文章詳述,讓我們開始吧!

我們的目標是抓下iPeen的美食店家資訊,在我們開始寫程式之前,我們必須大致分析網頁結構,知道我們所要的資料是在哪一些頁面,爬蟲要從哪裡開始、有哪些網頁要爬、爬蟲要怎麼到那些網頁等,所以先在iPeen先找到可以抓店家列表的網頁作為爬蟲起始點,這邊我們找到「http://www.ipeen.com.tw/search/taiwan/000/1-0-0-0/」具有店家列表可以作為爬蟲起始點,從此頁面取得各店家的資訊頁面連結後,在個別進入每個店家頁面抓店家資訊。

開頭我們先寫一個方法從起始點抓到所有的店家資訊頁面連結,並且儲存到列表中,程式碼如下(完整版在 commit 6741fde):

我們先使用 requests.get() 來下載HTML程式碼 list_req.content 並且傳入 BeautifulSoup() 作為分析來源,然後我們可以用

BeautifulSoup.find_all(‘a’, attrs={‘data-label’: ‘店名’})

找到所有CSS為 ‘data-label’: ‘店名’<a> 標籤。

接著,我們針對每個店家頁面去分析出詳細資訊,程式碼如下(完整版在 commit fd6435a):

這邊我們可以看到用 BeautifulSoup.find() 再搭配正則 re.search() / re.sub() 和字串操作 string.split() / string.replace() 就可以取得店家的名稱、分類、地址、GPS(分析取得字串方法不只一種,你可以寫的跟我不同沒關係,重點在於可以有效且正確分析出字串即可)。

大功告成,所有完整程式碼在我的GitHub上,歡迎下載使用,也多用星星來支持。

FAQ

  • 寫爬蟲有一個問題很多人會來問我「奇怪,我的網頁程式碼有看到,為何爬蟲卻無法抓到?」,這個原因很簡單,因為你看到的是「假的」(無誤),是因為網頁內容是動態產生的(以用Javascript產生的內容為例),你所看到的是經過瀏覽器已經將Javascript執行後產生的結果,而一般爬蟲預設是沒有執行這些Javascript,所以當然抓不到,我們要如何判別呢?在Chrome當中如果是右鍵按下[檢視網頁原始碼],則你所看到的HTML是沒有動態產生內容的,也就是我們一般爬蟲預設抓到的資料;在網頁上游標移動到其中一個元素按右鍵點[檢查]所看到的HTML內容則是經過動態產生的結果,一般爬蟲沒有特別處理是無法得到這些內容的。 這問題有沒有解?答案是有的,需要用其他方式例如讓爬蟲先模擬瀏覽器取得動態產生內容後,再去取得分析HTML的方式解決。
更新:關於動態產生的網頁內容抓取方式,可以參考我下列的文章。
  • 爬蟲是否能抓到一個需要登入或驗證後的網頁資訊?答案是可以的,但前提是你要知道該網頁怎麼登入、怎麼驗證身份,接著像瀏覽器一樣用 Session / Cookie 將登入或驗證後的資料儲存一起帶入到須登入驗證的網頁中去爬。
  • 有時候網頁會回傳 HTTP 429 Too Many Requests的錯誤,我該如何處理?會出現這錯誤表示你存取得太頻繁,每一個爬蟲都是一個Request,對於伺服器都是一個資源損耗,有些伺服器會擋甚至你存取太快會視為攻擊的一種(類DDOS),正確的解法是調整爬蟲抓網頁的速度,可以設定延遲機制來預防。

後記

我在Android讀書會所分享「Android x 網路爬蟲」的完整簡報內容:

此文章同步分享於我的部落格 http://enginebai.logdown.com/posts/834887/webcrawler

我是大白,Co-founder & Developer @DualCores Studio / Developer @17Media,歡迎對於大家跟我一起交流學習。