「網頁原始碼裡就是一段文字,用正規表達式撈出網址不就好了?」
理論上是。實務上,很多頁面會把設定資料用 JSON 的形式塞進一段 <script> 裡,M3U8 位置就藏在這段 JSON 字串裡面。這種情況下,正規表達式撈出來的不是「一個網址」,而是「一段包含網址、還帶著引號跟其他 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 屬性)?那段程式碼有沒有處理過跳脫字元的情況,還是「目前測試過的資料剛好沒踩到」?
明天講另一種例外情況:從頁面文字判斷「這是第幾個項目」時,不是每個項目的標題都乖乖是純數字。