iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Software Development

下載器不是寫完就能跑:一個 HLS 分段式串流工具的架構與測試修練系列 第 4

Day 04:案例——字串裡包一段 JSON 的 M3U8 連結,怎麼解析比較不脆弱

  • 分享至 

  • xImage
  •  

前言:頁面裡的資料格式,不會照你希望的方式長

「網頁原始碼裡就是一段文字,用正規表達式撈出網址不就好了?」

理論上是。實務上,很多頁面會把設定資料用 JSON 的形式塞進一段 <script> 裡,M3U8 位置就藏在這段 JSON 字串裡面。這種情況下,正規表達式撈出來的不是「一個網址」,而是「一段包含網址、還帶著引號跟其他 JSON 語法字元的片段」——直接拿去用,十次有兩三次會因為多了一個逸出字元或引號沒處理乾淨而失敗。

今日目標

  • 認識「看起來只是抓一個網址」背後藏著的資料結構問題
  • 看一組「直接正則截字串 vs 正則定位+JSON 正確解析」的對照
  • 知道正規表達式的合理定位:用來「找到範圍」,不是用來「解析結構」

❌ vs ✅:正規表達式硬截字串 vs 用它定位、交給 JSON 解析

❌ 反例:正規表達式直接截出網址本體

import re

def extract_url(html: str) -> str:
    matched = re.search(r'"https:[^"]+\.m3u8"', html)
    return matched.group(0).strip('"')

這段程式碼隱含一個假設:網址字串裡不會出現任何跳脫字元、不會被額外包在別的結構裡。這個假設在多數情況下成立,但只要來源站把網址放進帶跳脫字元的 JSON 字串(例如 \/ 取代 /),這段程式碼撈出來的網址就是壞的,而且不會拋例外,只會在後續下載階段才發現連不上。

✅ 正例:正規表達式只負責定位範圍,實際解析交給 JSON 解析器

import json
import re

def extract_url(html: str) -> str:
    matched = re.search(r'"https:[^:]+?\.m3u8"', html)
    return json.loads('{"url": %s}' % matched.group(0))['url']

把撈出來的片段包成一段合法的 JSON({"url": "..."}),再交給 json.loads 正式解析。這樣即使原始字串裡有 \/ 這種 JSON 跳脫字元,也會被正確解讀成 /,不會把跳脫符號原封不動留在結果裡。

正規表達式的合理定位

這個案例的教訓不是「不要用正規表達式」,而是分清楚正規表達式該負責什麼:它適合用來在一大段文字裡「找到某個範圍」,但只要那個範圍本身是一種有明確語法規則的結構(JSON、URL 編碼、HTML 屬性),就該把「解析範圍裡的內容」這件事交給對應的解析器,而不是繼續用正規表達式往下切。正規表達式沒有語法感知能力,字串裡多一個逸出字元、少一個引號,都可能讓結果悄悄壞掉而不拋錯。

今日思考題

你的專案裡有沒有用正規表達式解析過某種本身有語法規則的結構(JSON、URL、HTML 屬性)?那段程式碼有沒有處理過跳脫字元的情況,還是「目前測試過的資料剛好沒踩到」?

今日重點回顧

  • 正規表達式撈出來的字串,可能只是「範圍」,不代表「值」本身已經正確
  • 把撈出的範圍包成合法結構、交給對應的解析器,比繼續用正規表達式硬切更不脆弱
  • 判斷準則:目標本身有沒有明確語法規則?有的話,正規表達式該止步於「定位」,不該延伸到「解析」

明日預告

明天講另一種例外情況:從頁面文字判斷「這是第幾個項目」時,不是每個項目的標題都乖乖是純數字。


上一篇
Day 03:用 Factory 依網址判斷該用哪個爬蟲,而不是到處寫 if-else
系列文
下載器不是寫完就能跑:一個 HLS 分段式串流工具的架構與測試修練4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言