iT邦幫忙

2023 iThome 鐵人賽

DAY 9
0

終於介紹完所有有關 FanGraphs 的使用方法,以及相關進階數據的說明。今天想帶大家來看 pybaseball 的原始碼,看看他們是怎麼取得 FanGraphs 上面的資料吧。

Trace Code

因為 pybaseball 都是用抓取同一個頁面的資料,所以我這邊用 batting_stats 這個方法為例子,剩於其他方法可以照著一樣的步驟去找到相對應的程式碼。

  1. 先到 Github 首頁:https://github.com/jldbc/pybaseball
  2. 接下來點選 pybaseball 資料夾,所有方法的程式碼都在這個資料夾裡面
  3. 點選此資料夾裡的 __init__.py,這個檔案是用來把資料夾裡的方法匯出,讓之後的其他使用者可以順利匯入到他們的程式,這也是為什麼我們可以在安裝完 pybaseball 後使用 from pybaseball import batting_stats 的原因。
  4. 進入這個檔案,可以看到裡面 import 各種 methods,我們可以在裡面找到 batting_stats 會在第 43 行 並且由 batting_leaders.py import 他。
  5. 知道是哪個檔案 import 之後我們就能去那個檔案繼續追下去,這邊想提起一點,我在 Day 7 的時候有提到文件跟程式碼的命名問題,要找 FanGraphs 的程式碼不能跟官方文件一樣用 batting_stats.py 變成要找 batting_leaders.py,投手也可能以此類推去找 pitching_leaders.py 而不是 pitching_stats.py,大家在查找的時候可以注意一下。
  6. 點入 batting_stats.py,除了 import 檔案外會只看到一行 batting_stats = fg_batting_data,這行的意思是 batting_stats 是直接從 fg_batting_data 來,所以我們又要再去看 datasources 資料夾裡的 fangraphs.py。

fangraphs.py

這個檔案幾乎就是所有關於 FanGraph 方法的程式碼的地方,之後要快速查看其他功能的程式碼其實可以直接到這個檔案,不過前面還是介紹一下平常我們 trace code 的流程。

  1. 繼續追程式碼,在檔案底下可以找到 fg_batting_data 是從 FangraphsBattingStatsTable 這個 Class 的 fetch method 獲得。
  2. 找到 FangraphsBattingStatsTable 後,會發現他的參數會再帶入另一個 Class FangraphsDataTable,這邊會用一個 ABC 的套件來實現抽象類別,更詳細可以參考這篇文章:https://ithelp.ithome.com.tw/articles/10306278
  3. 再來可以看到裡面會定義一些會拿來查資料的常數,很多會從 enums 這個資料夾裡面取得,主要會有要搜尋的種類 (batting or pitching or fielding),預設的欄位,跟一些欄位名稱需要多做處理的 Mapper,還有會用 html 的 <a> tag 來獲得 ID 的 function。這個取得 ID 的方法是因為 FanGraphs Leaderboard 的結果會有球員或球隊名字,然後他們會戴上他們個人頁或球隊頁的連結,上面就會有相對應的 ID 可以爬蟲爬到。
  4. 設定完常數可以看到他們定義的 fetch,他會用 super() 取得父類別的 fetch 拿資料。
  5. 接下來就來看 FangraphsDataTable,可以看到也是會先有一些常數的定義,主要是我們要爬的 FanGraphs 的頁面 domain,再來還有用來給爬蟲的指標的 Table Class 與 xpath,之後就能用這些常數去爬蟲。
  6. 看完常數,再來看 __init__,他會獲得 HTMLTableProcessor的類別,這個類別裡面會是他們爬蟲並整理的方法,主要會是用 lxml 這個 package 來爬蟲,在 fetch 會呼叫裡的方法獲得資料。關於 lxml 的更多詳細介紹,可以參考:【Day 6】剖析網頁原始內容 (2/2) - XML - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
  7. 最後看到 fetch,這邊會先預設搜尋的參數,這些都是在使用 FanGraphs Leaderboard 會帶入 URL 的 Search Params 的參數,可以從註解知道他們更多各自更詳細的描述。參數定義完,會用 stat_list_from_str 找到相對應的 Enum,像是 batting_stats 就會找到 batting_data_enum.py
  8. 等剛剛說的搜尋參數整理完,會從 HTMLTableProcessorget_tabular_data_from_options 獲得我們爬蟲下來的資料,並用 _sort 去排序,batting_stats 會是用 WAROPS 排。最後就能拿到我們要的資料了。

本日小結

今天算簡單把整個 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。


上一篇
Day 08 - FanGraphs 進階數據解釋
下一篇
Day 10 - Statcast 介紹
系列文
Python 棒球數據分析套件 pybaseball 介紹30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言