Sometimes you win, sometimes you lose, sometimes it rains.

Nodejs 爬蟲教學 (cheerio)- 以 CPBL 官網賽程為例

延續前一篇實作 TPBL Fantasy 心得,這篇更專注在爬蟲的實作,需要爬蟲的情境是當你需要某個類型的資料,但有那個網站的資料並沒有 Open API

說到這邊一定要靠杯一下幾年前看過政府的某個黑客松,裡面的 Open API 居然有 PDF 格式的

所謂的 Open API,要可以提供一個機器可以讀得懂的介面,以及機器可以方便閱讀,有規律的資料格式,所以網站有提拱 PDF, Word,並不等同於是 Open API

必備知識

  • 網路知識

  • 知道怎麼用 chrome 的 devtool 觀察網站怎麼運作

  • 知道怎麼用 Nodejs

  • 知道怎麼用 css (selector 的部份)

觀察 CPBL 官網賽程的結構

網址在: http://www.cpbl.com.tw/schedule/index/2020-05-26.html?&date=2020-05-01&gameno=01&sfieldsub=&sgameno=01

先按右鍵,選檢視網頁原始碼,確定是 SSR

簡單分辨 SSR 或 CSR 就是在看原始碼時,網頁可視內容原始碼內容大小有沒有差太多

然後打開 DevTool 的 Elements tab

2020 五月賽程表2020 五月賽程表在同一個 tab,按下 Cmd+F (windows 是 Ctrl+F) 搜尋 .one_block,會找到這個月份 44 場比賽,這邊要特別講一下,因為 Chrome 會自動補齊網站原始碼不完整的部份,所以有時候在 devtool 沒問題,但在爬蟲程式就會找不到,如果發現有這種情況,記得要按 view source 看一下差異

WARNING: It may burn your eyes

然後展開 .one_block 可以看到以下結構

CPBL 很貼心的註解每個區塊的資料,然後我其實不懂那個  onclick 在幹嘛的CPBL 很貼心的註解每個區塊的資料,然後我其實不懂那個 onclick 在幹嘛的看到這邊差不多可以開始實作了

開始實作爬蟲

接下來可以開始動手了,首先準備好環境

mkdir ./web-scraper && cd ./web-scraper
npm init -y
npm i axios cheerio -s

然後用剛觀察到的 selector 去取得全部的賽程

確定一下程式抓到的數量跟用 devtool 一不一樣確定一下程式抓到的數量跟用 devtool 一不一樣map 取得每場的資訊

去 parse 每一個 cell 取得裡面的資訊去 parse 每一個 cell 取得裡面的資訊因為隊伍是用圖片示意,沒辦法直接取得文字,只好轉個彎,改用圖片的網址去 parse

抓得到東西不難,穩定的抓得到東西才難

以下有些爬蟲的進階狀況

被網站擋了

一般有規模的網站,會有防止 ddos 的機制,所以如果太過頻繁存取的話,ip 會被直接擋掉。除了買 proxy 之外,也可以試試用 tor (安裝看這裡),不過通常抓東西不要太密集會比較好啦,不然不小心把網站弄掛就得不償失

另外有一種擋 ip 的做法是在 application 層,以下是常見的做法 (php):

if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $ip = $_SERVER['REMOTE_ADDR'];
}

這做法邏輯上沒錯,但問題是所有來自 client 端的資料都可以被竄改,例如 (以 axios):

const response = axios({ 
  method: 'get', 
  url: 'https://some-domain.com/api/', 
  headers: {
    'HTTP_X_FORWARDED_FOR': randomIP() 
  }
});

所以如果網站是這樣擋的,那只要發 request 時改個 ip 就可以了,更詳細的資訊可以看 DEVCORE

有好多東西要抓

通常要配合前段一起做,才不會被擋,如果不用的話……這網站大概沒什麼人在管,總之可以先蒐集內部相關網址,然後配合 MessageQueue 循序去抓,至於要用哪個 MessageQueue? 就看個人喜好

如果想試的話,可以先從這個範本開始

  • web scraper
  • nodejs