終於介紹完所有有關 FanGraphs 的使用方法,以及相關進階數據的說明。今天想帶大家來看 pybaseball 的原始碼,看看他們是怎麼取得 FanGraphs 上面的資料吧。
因為 pybaseball 都是用抓取同一個頁面的資料,所以我這邊用 batting_stats
這個方法為例子,剩於其他方法可以照著一樣的步驟去找到相對應的程式碼。
pybaseball
資料夾,所有方法的程式碼都在這個資料夾裡面__init__.py
,這個檔案是用來把資料夾裡的方法匯出,讓之後的其他使用者可以順利匯入到他們的程式,這也是為什麼我們可以在安裝完 pybaseball 後使用 from pybaseball import batting_stats
的原因。batting_stats
會在第 43 行 並且由 batting_leaders.py
import 他。batting_stats.py
變成要找 batting_leaders.py
,投手也可能以此類推去找 pitching_leaders.py
而不是 pitching_stats.py
,大家在查找的時候可以注意一下。batting_stats.py
,除了 import 檔案外會只看到一行 batting_stats = fg_batting_data
,這行的意思是 batting_stats
是直接從 fg_batting_data
來,所以我們又要再去看 datasources 資料夾裡的 fangraphs.py。這個檔案幾乎就是所有關於 FanGraph 方法的程式碼的地方,之後要快速查看其他功能的程式碼其實可以直接到這個檔案,不過前面還是介紹一下平常我們 trace code 的流程。
fg_batting_data
是從 FangraphsBattingStatsTable
這個 Class 的 fetch
method 獲得。FangraphsBattingStatsTable
後,會發現他的參數會再帶入另一個 Class FangraphsDataTable
,這邊會用一個 ABC
的套件來實現抽象類別,更詳細可以參考這篇文章:https://ithelp.ithome.com.tw/articles/10306278enums
這個資料夾裡面取得,主要會有要搜尋的種類 (batting or pitching or fielding),預設的欄位,跟一些欄位名稱需要多做處理的 Mapper,還有會用 html 的 <a>
tag 來獲得 ID 的 function。這個取得 ID 的方法是因為 FanGraphs Leaderboard 的結果會有球員或球隊名字,然後他們會戴上他們個人頁或球隊頁的連結,上面就會有相對應的 ID 可以爬蟲爬到。fetch
,他會用 super()
取得父類別的 fetch
拿資料。FangraphsDataTable
,可以看到也是會先有一些常數的定義,主要是我們要爬的 FanGraphs 的頁面 domain,再來還有用來給爬蟲的指標的 Table Class 與 xpath,之後就能用這些常數去爬蟲。__init__
,他會獲得 HTMLTableProcessor
的類別,這個類別裡面會是他們爬蟲並整理的方法,主要會是用 lxml
這個 package 來爬蟲,在 fetch
會呼叫裡的方法獲得資料。關於 lxml
的更多詳細介紹,可以參考:【Day 6】剖析網頁原始內容 (2/2) - XML - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
fetch
,這邊會先預設搜尋的參數,這些都是在使用 FanGraphs Leaderboard 會帶入 URL 的 Search Params 的參數,可以從註解知道他們更多各自更詳細的描述。參數定義完,會用 stat_list_from_str
找到相對應的 Enum
,像是 batting_stats
就會找到 batting_data_enum.py
HTMLTableProcessor
的 get_tabular_data_from_options
獲得我們爬蟲下來的資料,並用 _sort
去排序,batting_stats
會是用 WAR
和 OPS
排。最後就能拿到我們要的資料了。今天算簡單把整個 pybaseball 獲得 FanGraphs 資料的流程呈現給大家,感謝大家耐心地閱讀,不知道這樣的流水帳的形式來介紹還清不清楚,或是大家覺得講重點幾個 methods 就好,下次在介紹 Statcasts 原始碼我可以再調整看看。
另外不知道大家有沒有注意到之前介紹的 URL 有帶有 legacy 這個字樣,原因是 FanGraphs 在前些日子有改版,所以 pybaseball 的爬蟲爬不到資料,變成必須要抓舊的頁面。可以從這個 PR 得知:
Updating FanGraphs leaderboard URL by corleymj · Pull Request #377 · jldbc/pybaseball (github.com)
然後要注意的是那時候雖然 PR 進去到主 branch,但是他們沒有更新 PyPI 上的版本,所以直接 pip install 下來會還是舊的,這時候就會需要先刪除,然後安裝 Github 上最新的,像是這樣:
pip uninstall -y pybaseball
pip install git+https://github.com/jldbc/pybaseball.git@master
這樣才會是最新版的,可以看這個 Issue 裡的討論:
Can't seem to get pitching/batting stats. · Issue #381 · jldbc/pybaseball (github.com)
之後假設遇到類似的狀況可以多注意一下。明天會開始介紹另一個網站 Statcast。