iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
自我挑戰組

30 天養大一個開源專案:baodao-skill 從零開始系列 第 25 篇

【Day 25】郵資表 170 格,其實只有幾個數字:8 元信函怎麼變成 28、35、67

  • 分享至 

  • xImage
  •  

前兩天都在查「數字到底在數什麼」。今天輪到 taiwan-postage:中華郵政的簡明國內函件資費表。它不是 API,是一頁 HTML,裡面一堆表格。我原本以為要寫一堆查表邏輯,實際重跑之後發現,這張表比看起來單純很多。

先確認頁面還在

2026-10-02 重跑 repo 文件裡的 curl,HTTP 200,229,412 bytes(約 224KB),UTF-8,6 張表,和 SKILL 記的 9/19 狀況一致。信函表有 24 個 <tr>,欄位是不逾 20 公克、21-50、51-100、101-250、251-500、501-1000、1001-2000 公克共 7 級。

文件那句「國內普通信函 20 公克以內 8 元,掛號再加 20 元」今天也對得上:普通 8,普通掛號 28。

170 格,只有幾個獨立數字

信函那一段有 10 列、每列 7 級,共 70 格;小包表也是 10 列,每列 10 級,共 100 格。逐格看很容易看花,但把每一列和「普通」那一列相減,差值是固定的:

2026-10-02 實測 相對普通資費
限時 +7
普通掛號 +20
限時掛號 +27
加附普通回執(掛號或限時掛號之上) +15
加附掛號回執(同上) +25
加附限時掛號回執(同上) +32

所以 20 公克的信函:普通 8,限時 15,普通掛號 28,限時掛號 35。限時掛號附限時掛號回執是 35+32=67,頁面上也真的寫 67。這 170 格全部可以由「各級距基本資費」加上這幾個固定加價算出來,沒有例外。

一個可以重跑的檢查

下面這段先抓頁面,再逐格驗證加價規則。2026-10-02 實測輸出兩行,信函 70 格、小包 100 格,加成都成立。

curl -sm 30 -A 'Mozilla/5.0' -o /tmp/post.html 'https://www.post.gov.tw/post/internet/Postal/index.jsp?ID=2020106'
python3 - <<'PY'
import re, html
t = open('/tmp/post.html', encoding='utf-8').read()
tabs = re.findall(r'<table.*?</table>', t, flags=re.S)

def grid(tab, n):
    rows = []
    for r in re.findall(r'<tr.*?</tr>', tab, flags=re.S):
        cells = [html.unescape(re.sub(r'<[^>]+>', '', c)).strip()
                 for c in re.findall(r'<t[dh].*?</t[dh]>', r, flags=re.S)]
        nums = [int(c) for c in cells if c.isdigit()]
        if len(nums) == n:
            rows.append(nums)
    return rows[:10]

for name, idx, n in (('信函', 0, 7), ('小包', 1, 10)):
    g = grid(tabs[idx], n)
    base, rush, reg, rreg = g[:4]
    ok = all(r == b + 7 for r, b in zip(rush, base))
    ok &= all(r == b + 20 for r, b in zip(reg, base))
    ok &= all(r == b + 27 for r, b in zip(rreg, base))
    d1 = {b - a for a, b in zip(reg, g[4])}
    d2 = {b - a for a, b in zip(reg, g[5])}
    d3 = {b - a for a, b in zip(reg, g[6])}
    e1 = {b - a for a, b in zip(rreg, g[7])}
    e2 = {b - a for a, b in zip(rreg, g[8])}
    e3 = {b - a for a, b in zip(rreg, g[9])}
    print(name, '基本', base, '加成成立', ok, '回執加價', d1, d2, d3, e1, e2, e3, '共', sum(len(r) for r in g), '格')
PY

要注意:三個回執加價(15、25、32)頁面沒有逐項標示,是我從表格差值反推的,而且只在「信函」和「小包」這兩張表驗證過。這個規則可以當檢查工具,不應該當成官方計費公式背下來。

錯誤處理:資費表是會改的

這種表最危險的不是抓不到,而是抓到之後悄悄解析錯位。巢狀表格、rowspan、和「普通回執」這種中間夾文字的欄位,都會讓位置不對。加價規則至少給了一個便宜的交叉檢查:如果某天一列對不上基本資費加加價,不要硬湊答案,先確認是郵局改了資費,還是解析錯位。

  • 回答郵資時一律附查詢日期和級距,資費表改版後舊數字就不能再用。
  • curl 失敗或拿到的頁面沒有 6 張表,回報資料源異常,不用記憶裡的郵資代替。
  • 逾 2 公斤的信函另有續重加價(每續重 1 公斤加收 48 元),這段我今天沒有另外驗證。
  • 國際資費、包裹、快捷是不同頁面,這個 skill 只引導到頁面,不在這裡算。

今天沒有改 repo。收穫是一個小習慣:一張大表如果能用幾條規則還原,就把規則寫成檢查,下次頁面一動,先知道是哪一格不對。


上一篇
【Day 24】610 還是 644?圖書館名錄裡,多一個逗號就少算 34 館
系列文
30 天養大一個開源專案:baodao-skill 從零開始 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言