Python x 網路爬蟲
今天來分享一個可以從網路獲取資料的技術:叫「網路爬蟲」,英文稱做Web Crawler
or Web Scrapying
,以下簡稱爬蟲。
這篇文章將會分成「原理介紹」以及「程式實作」,如果有基本概念的朋友們,可以直接跳至「程式實作」開始,我將會以 iPeen 愛評網(以下簡稱 iPeen)作為範例用 Python 來實作簡單的爬蟲,希望透過此篇入門介紹,能讓大家都會寫基本的爬蟲,抓到你想要的資料。
2021/06 更新:iPeen 愛評網已經被收購,目前網站已經找不到,範例沒了但是基本觀念還是有效。
一、基本概念
爬蟲是一個將網路上的檔案下載下來然後做一些處理的程式,一般我們在網路上看到的網頁、圖片或影片等,都算是一個檔案,只是透過瀏覽器我們可以看到正確的結果,例如:網頁檔案本身是一個 HTML 檔案,瀏覽器幫我們轉成我們看得懂的網頁介面(如下圖所示,操作方式為在 Chrome 按右鍵的[檢視網頁原始碼
])。
那麼瀏覽器會將這個原始碼轉成我們看得懂的頁面,也就是下圖。
為什麼要講這個呢?因為爬蟲所要處理的,是沒有透過瀏覽器處理的 HTML 原始碼,當我們看到網頁有我們要抓的資料之時(以 iPeen 為例,我們要抓店家的資訊,如下圖,操作方式為在網頁上游標移至店家名稱連結,然後按下右鍵按[檢查
])
我們必須知道這些在網頁上我們所看到的店家名稱是在 HTML 原始碼所對應的位置(如下圖),必須看看這些這些程式碼有沒有什麼樣的規律或特徵,以剛剛所講述的店家網址名稱為例,我們可以看出店家連結是 <a>
標籤,擁有 data-label=”店名”
獨特可以找出店家連結的CSS屬性。
爬蟲兩大工作
- 下載檔案:在給定一個網址時,我們可以使用 HTTP 協定的方法去對於伺服器送出 Request 請求,並且取得 Response 回應,在我們爬蟲一般的情況就是對於伺服器送出 GET Request 來取得 HTML 檔案的 Response,在取得 HTML 檔案後接著我們就可以進行第二步驟:分析內容。
- 分析內容:擁有 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),正確的解法是調整爬蟲抓網頁的速度,可以設定延遲機制來預防。