請啟用JavaScript來查看內容

「PTX 公共運輸資訊平台」Python 範例程式

    前言

    在上一篇文章中,我們介紹了PTX 公共運輸整合資訊流通服務平台,它整合公車、臺鐵、高鐵、捷運等多項公共運輸的資料服務 API,以及說明 OData(Open Data Protocol)標準介面格式如何使用。

    本篇文章將帶你實際使用 Python 來串接 PTX 平台,取得這些相關數據資料 💾。


    關於 PTX 平台我寫了三篇文章來介紹與程式教學:

    1. 「PTX 公共運輸資訊平台」API 介紹 (含 Odata 說明)
    2. 「PTX 公共運輸資訊平台」Python 範例 <– 本篇
    3. 「PTX 公共運輸資訊平台」Google Apps Script 範例

    PTX 公共運輸整合資訊流通服務平台
    PTX 公共運輸整合資訊流通服務平台

    後來發現 PTX 竟然只服務到今年(2022年)底,之後會改以 TDX 運輸資訊整合流通服務平台,因此又特別寫一篇文章帶大家快速了解一下 TDX 平台:
    「TDX 運輸資料流通服務平臺」含 Python 範例程式,PTX 平台的升級版~


    API 認證授權機制

    目前 PTX 平台採用 HMAC 認證授權機制,在送出請求時 headers 需代上規定的資料,它會依照 HTTP header 資訊來判別用戶是否有授權身份 🔓。

    官方說明如下:

    HMAC 機制:以 HMAC 簽章驗證使用者的身份,用戶在請求 API 服務時,將 APP Key 與當下時間(格式請使用GMT時間) 做 HMAC-SHA1 運算後轉成 Base64 格式,帶入 signature 屬性欄位,服務器端將驗證用戶請求時的 header 欄位,驗證使用者的身份及請求服務的時效性。

    HMAC Signature 簽章時效性:於 MOTC Helper 該網頁測試時,請在最上方輸入 API Key 與 API ID (請再次確認是否有把 APP Key 跟 ID 填寫正確,若欄位資訊相反會無法執行)。點選 Explore ,每次請求下方 API 時,會於 header 帶入 Authorization 及 x-date ,依照請求當下的時間 & API Key 製作簽章。

    參數如下:

    KeyValue
    Authorizationhmac username="APP ID", algorithm="hmac-sha1", headers="x-date", signature="Base64(HMAC-SHA1("x-date: " + x-date , APP Key))"
    x-dateWed, 19 Apr 2017 08:37:50 GMT

    ※ 建議於每次請求 API 服務當下建立新的 signature,簽章時效性為 5 分鐘。


    如果 HMAC 認證有問題、未符合身份驗證,它會回覆下列訊息:

    • HTTP Status Code 403:
      • (1) HMAC signature cannot be verified, a valid date or x-date header is required for HMAC Authentication (x-date 的間隔時間超過定義的 clock skew 秒數)
      • (2) HMAC signature does not match (日期格式正確,但簽章演算法有問題)
    • HTTP Status Code 401:
      • (1) Unauthorized (未帶簽章,未經授權)


    依照上方說明,使用 Python 把這個 HMAC 編碼寫出來,這邊我也是參考範例來做修改的。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    class Auth():
        def __init__(self, app_id, app_key):
            self.app_id = app_id
            self.app_key = app_key
    
        def get_auth_header(self):
            xdate = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
            hashed = hmac.new(self.app_key.encode('utf8'), (f'x-date: {xdate}').encode('utf8'), sha1)
            signature = base64.b64encode(hashed.digest()).decode()
            authorization = (f'hmac username="{self.app_id}", algorithm="hmac-sha1"' +
                             f', headers="x-date", signature="{signature}"')
            return {
                'Authorization': authorization,
                'x-date': xdate,
                'Accept-Encoding': 'gzip'
            }
    

    Python 程式範例

    我們來實際舉個例子,像是我想抓:

    台鐵"台北"車站即時的列車到離站看板資訊,並且只要"逆行"的列車


    先進到 PTX 平台的 Swagger 文件,找到 "取得指定[車站]列車即時到離站電子看板":

    列車即時到離站電子看板
    列車即時到離站電子看板

    填入 "台北車站" 代碼 1000 (車站代碼表),並依照下方 Responses 欄位說明 "Direction" 代表順逆行(0:'順行', 1:'逆行'),在 $filter 填入 Direction eq 1,指定 JSON 格式,最後點擊藍色 "Execute" 按鈕,看看回傳結果是不是我們想要的~

    (關於這些 Odata 的寫法,我在上一篇文章有說明,忘記的可以回去看看)


    它顯示的 "Request URL" 長得像這樣:
    https://ptx.transportdata.tw/MOTC/v2/Rail/TRA/LiveBoard/Station/1000?%24filter=Direction%20eq%201&%24format=JSON

    這是以下這句經過 URL 編碼後的結果:
    (程式中 requests 會自動幫我們編碼,因此輸入底下這句也可以)
    https://ptx.transportdata.tw/MOTC/v2/Rail/TRA/LiveBoard/Station/1000?$filter=Direction eq 1&$format=JSON


    接下來將這些代入程式中:

    1
    2
    3
    4
    
    auth = Auth(app_id, app_key)
    url = "https://ptx.transportdata.tw/MOTC/v2/Rail/TRA/LiveBoard/Station/1000?$filter=Direction eq 1&$format=JSON"
    response = requests.get(url, headers=auth.get_auth_header())
    print(response.json())
    

    如此應該就能順利取得資料 🎉🎉🎉


    完整 Python 程式範例

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    import hmac
    import base64
    import requests
    from datetime import datetime
    from hashlib import sha1
    
    
    app_id = '<YOUR APP ID>'
    app_key = '<YOUR APP KEY>'
    
    
    class Auth():
        def __init__(self, app_id, app_key):
            self.app_id = app_id
            self.app_key = app_key
    
        def get_auth_header(self):
            xdate = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
            hashed = hmac.new(self.app_key.encode('utf8'), (f'x-date: {xdate}').encode('utf8'), sha1)
            signature = base64.b64encode(hashed.digest()).decode()
            authorization = (f'hmac username="{self.app_id}", algorithm="hmac-sha1"' +
                             f', headers="x-date", signature="{signature}"')
            return {
                'Authorization': authorization,
                'x-date': xdate,
                'Accept-Encoding': 'gzip'
            }
    
    
    if __name__ == '__main__':
        auth = Auth(app_id, app_key)
        base_url = "https://ptx.transportdata.tw"
        # 取得指定[車站]列車即時到離站電子看板(動態前後30分鐘的車次)
        endpoint = "/MOTC/v2/Rail/TRA/LiveBoard/Station/1000"
        filter = "Direction eq 1"  # 順逆行: [0:'順行', 1:'逆行']
        url = f"{base_url}{endpoint}?$filter={filter}&$format=JSON"
        response = requests.get(url, headers=auth.get_auth_header())
        print(response.json())
    

    其他程式範例

    除了參考我上面的 Python 範例,PTX 官方也提供不同程式語言的範例程式碼提供開發者下載 (GitHub)。

    • 平台提供
      • ASP.NET
      • Java
      • JavaScript
    • 網友提供
      • Bourne Shell
      • C# 與 .NET Standard 2.0
      • Go
      • Go Client SDK - Code generated by go-swagger
      • Node.js
      • python
      • Ruby
      • Swift
      • PHP
      • Postman

    另外,在下一篇文章裡,我會分享 Google Apps Script 的範例程式,它跟一般 JavaScript 有一些些不同,Google Apps Script 中預設應該是不能使用 jQuery,還有編碼的寫法也有些不同。


    結語

    除了以上文章的解說,也可以看看官方的文件說明
    有針對 "航空"、"公車"、"雙鐵(台鐵/高鐵)" 資料做進一步的說明,如果有使用到此 API 服務的人,建議進入先了解。
    * 不過我看此文件上次更新時間 2018/04/12,可能有些資料不是最新的。


    上一篇了解 PTX 平台的說明與 OData 介面,本篇則教你如何透過 Python 程式來發出請求、獲取資料,快將你有趣的 idea 來動手做實現它吧~


    歡迎追蹤『IT空間』FB 粉專,取得最新發文通知🔔




    參考:
    公共運輸整合資訊流通服務平台 | 官網
    PTX 資料服務使用注意事項 | GitHub
    PTX 官方範例程式碼 | GitHub


    專注你喜歡的事,就能感受到那股強大的力量。

    —— 戴資穎 (台灣羽球國手)


    🔻 如果覺得喜歡,歡迎在下方獎勵我 5 個讚~
    分享

    Jia
    作者
    Jia
    軟體工程師