AIREITER

AI 圖片

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 ProSeedream V5 liteSeedream V4.5更多

AI 影片

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0Grok Imagine 1.5Veo 3.1更多

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 ProClaude Opus 5Claude Fable 5更多
即將推出Seedance 2.5
Super ResolutionLyric Video GeneratorGPT Image 2 1K GeneratorGPT Image 2 Product Mockup GeneratorUse GPT-5.6 Online
API 文件價格
部落格更新LLM API GuideClaude API GuideKimi K3 API Guide
範本
  • AIReiter
  • 部落格
  • B2B 廣告情報只能從 HTML 取得:打造能撐過改版的解析器

B2B 廣告情報只能從 HTML 取得:打造能撐過改版的解析器

最近更新: 2026-07-31 07:04:41

如果你想知道某個 B2B 競爭對手這一季在哪些國家投放廣告、跑了多久、大致燒了多少曝光量,以及受眾鎖定切了哪些維度,答案往往都藏在公開的廣告資料庫裡。許多平台為了符合廣告透明度規範,必須公開這些資訊。但打開 DevTools 找了一輪後,你常會發現沒有乾淨的 JSON endpoint,只有整頁伺服器端渲染的 HTML。於是你寫了解析器,資料也順利抓到了;三週後平台改版,解析器沒有報錯,卻一個欄位都抓不到,只是安靜地回傳一堆空值。要是拿這些空資料去做決策,後果可想而知。

這篇要談的是:這類解析器在網站改版後怎麼繼續活下來,以及模型在維護流程中真正能幫上什麼忙。先講清楚資料邊界:本文提到的資料都來自各平台公開的廣告資料庫與創意中心,以自己的帳號正常登入後存取;不使用簽名、不繞過機制,也不碰非公開 endpoint。這條界線會直接寫進解析器的設計裡。

為什麼 B2B 廣告情報往往只能從 HTML 解析

即使同樣是廣告資料庫,資料公開方式大致可分成三類:部分消費型平台,例如 Meta 的廣告資料庫,提供結構化搜尋與 JSON;另一類連搜尋都要求登入 session;而大多數 B2B 平台的廣告資料庫,則完全是伺服器端渲染的 HTML,根本沒有 JSON endpoint。原因很簡單:這些廣告資料庫是合規產物,不是給開發者使用的產品 API。

它們的存在目的,是滿足廣告透明度法規,而不是讓工程師串接。沒有版本號、沒有 changelog,也沒有向後相容的承諾。頁面是給人看的,伺服器輸出 HTML;你能使用的唯一「API」,其實就是那張網頁。

因此它天生脆弱:你依賴的是別人 UI 的實作細節,而對方想改就改,也沒有義務通知你。JSON API 改了一個欄位,至少還算一次「變更」;HTML 改版在平台眼中,通常只是日常前端迭代。這件事無法避開,唯一能做的是讓解析器在改版後優雅失效、容易修復,而不是默默吐出一堆空欄位。

手寫串流解析器,省下的不只是程式碼

第一個直覺通常是拿 lxml 或 BeautifulSoup,把整頁建成 DOM tree,再一路用 .find() 往下找。這當然能做,但面對這類目標並不是好選擇。DOM tree 是瀏覽器渲染頁面時產生的中間產物,MDN 對 DOM 的定義就是把文件解析為可由腳本依結構存取的節點樹;但你的目的只是抽出幾個欄位,既不需要整棵樹,也不該把自己綁死在它的結構上。

我最後採用的是 Python 標準函式庫 HTMLParser 的子類別,程式超過八百行,精確來說是 881 行。它完全以串流方式運作:透過少量 starttag、data、endtag callback 驅動狀態機,掃描時持續累積資料;碰到卡片邊界就輸出一筆 record、清空狀態並繼續往下,不會建立完整 DOM tree。

串流方式帶來的好處很具體。第一是記憶體:一張詳情頁 HTML 很容易就是數十到數百 KB,DOM tree 會把整頁結構都放進記憶體;串流解析只需要保留「目前掃到哪裡、這張卡片解析到什麼程度」的狀態。第二是更重要的心智負擔。一旦你寫下 .find('div').find('div')[2],就等於把解析邏輯綁到 DOM 的層級位置;而層級正是改版最愛動的地方,多包一層 container、拆出一個 wrapper,所有位置都會跟著偏移。狀態機會逼你只問一件事:眼前掃到的東西,在語意上是不是卡片起點、曝光數字或受眾標籤?位置會變,語意通常不會。

讓解析器撐過改版的三個設計原則

歸根究底就是三件事,而且每一件都是從改版中學來的。

第一,錨定語意,不要錨定位置。狀態機應該根據語意訊號前進:欄位的標籤文字,例如「總曝光量」、「投放日期」這類人可讀的文字;帶有角色意義的標記;或區塊的語意邊界。絕對不要依賴「從上面數來第三個節點」。判斷標準只有一句:如果這個元素被移動,或外面多包了一層,我的解析還能成立嗎?可以,才是有效錨點。位置錨點第一次改版就會碎裂;語意錨點通常能撐過純視覺樣式調整。

第二,欄位缺失要降級,不要直接拋錯。每次開始累積一張卡片前,先從一個完整欄位 template 初始化:文字欄位預設空字串、數字欄位是 None、列表欄位則為空陣列。能填的就填,抓不到的就留空。任何單一欄位擷取失敗,都不能毀掉整張卡片,更不能讓整頁解析中斷。一支廣告少了 CTA 文案,仍然值得保留它的曝光量與目標國家。為了一個不重要的缺失欄位,丟掉頁面本來能提供的情報,是最糟糕的設計。

第三,結果要帶完整性標記,別讓「真的沒有」和「解析壞了」看起來一樣。這點最容易被忽略,代價也最高。「解析到 0 支廣告」其實可能代表兩件完全不同的事:第一,這個廣告主這一季確實沒投廣告;第二,頁面結構改了,解析器找不到任何錨點。回傳值必須能分辨這兩種情況。做法是附上可交叉驗證的證據:抓到的卡片數、頁面自己宣告的總數,以及分頁狀態一起回傳。例如「卡片數是 0,但頁面 metadata 顯示應有一批資料,而且沒有下一頁標記」,就應判定為結構變更,而不是正常的空結果;應清楚拋出錯誤,而不是面無表情地回傳空 list。

前面提過的資料邊界,也會落實在這一層:解析器會檢查是否被導回登入頁;只要發現 title 是登入/註冊頁,就立即報錯,不會繼續解析。它只處理你以自己帳號正常可見的公開頁面,遇到登入牆就停止,絕不嘗試穿透。

真正有價值的是可切分的情報維度

看到這裡,你可能會以為重點是把每一支廣告的每個欄位都乾淨抓出來。其實不是。單支廣告的欄位本身沒有太多生命力,真正有價值的是你能用哪些維度切分這批廣告。廣告資料庫裡的搜尋篩選條件,本身就是現成的情報維度;把它們整理成可程式化的查詢參數,你得到的就不只是一支廣告,而是一個競爭對手的投放切片:

  • 國家:它在哪些市場投放、又刻意避開哪些市場。B2B 公司突然開始在某個國家投廣告,往往比它自家網站更早透露市場擴張動作。

  • 投放期間:起訖日期能看出一組創意跑了多久。長期投放的廣告是很強的訊號,因為沒人會一直為無法轉換的創意付費。投放長度本身,就是對方用真金白銀替你跑出的 A/B test 結果。

  • 曝光量區間:以最小/最大曝光量作為粗略的花費代理指標。絕對數字未必精準,但足以用來排序哪些是優先投放項目。

  • 受眾鎖定面向:哪些 targeting 被納入、哪些被排除。這是最直接的受眾情報:對方認為誰最可能買單。

欄位擷取只是手段,這些維度才是目的。寫解析器時應該反過來想:為了支援這些維度的查詢與排序,最少要穩定抓到哪些欄位?其他看似花俏的欄位,就算不抓也不會傷害情報價值。

網站改版後,讓模型比對新舊 HTML 提出修復方向

這種解析器遇到改版一定會壞;而「怎麼修」正是模型真正該介入的地方。注意,不是在解析過程中。解析是確定性的工作,應該由硬編碼的狀態機處理,不該把模型呼叫塞進去(這和別把確定性工作交給模型的原則完全一致)。模型的角色是維護。

流程是這樣:用自己的帳號開啟廣告資料庫,保留改版前存下來的 HTML,以及改版後的新 HTML;把兩份 HTML、目前解析器會擷取的欄位清單一起交給模型,請它根據新舊差異指出哪些欄位的語意錨點變了、新錨點應該放在哪裡,以及最小的修改範圍。這是典型需要推理層的情境:模型必須找出新結構裡是否仍存在對應語意,並提出可以修正的方案,而不是只重述「結構調整了」。不同步驟對模型能力的要求不同,全程只用一個層級,不是多花錢,就是少了精準度:

步驟

需要的能力

建議選擇

model id

讀完整頁 SSR HTML,對齊新舊結構

長上下文,可一次吞下數十到數百 KB 的詳情頁

Kimi K3

kimi-k3

改版後閱讀新舊 diff,判斷錨點如何漂移並提出最小修正

強推理能力,能依結構說明原因,而不是重述現象

Claude Opus 5

claude-opus-5

大量將數百個廣告主的卡片正規化/標記為情報

成本低,可高併發執行數百到數千次呼叫

Claude Sonnet 5

claude-sonnet-5

fixture 比對失敗時進行差異歸因

中等推理能力,可根據「預期欄位與實際擷取結果」說明差異

GPT-5.6 Sol

gpt-5.6-sol

核心是第二層,也是唯一一個換模型後結果會明顯不同的步驟。推理層到底值不值得,不必聽我說,測一次就知道,流程很短:

  1. 各存一份改版前與改版後的頁面 HTML(以自己的帳號開啟廣告資料庫並儲存頁面)。

  2. 把兩份 HTML 和目前解析器的欄位清單,同時交給 claude-opus-5 與 gpt-5.6-sol。

  3. 只看一件事:它提出的修正,是否指向具體的語意錨點變化,例如「原本錨定在『總曝光量』標籤,新版中該標籤的 container role 變了,應改為錨定在 X」;還是只含糊地說「結構已調整,建議重新適配」。

  4. 前者可以直接動手修改,後者幾乎沒有資訊量。這就是選型標準,也直接決定改版當天你得進行多少輪盲目嘗試。

跑一輪就能看出差異,比任何 benchmark 都直接。

真正的阻力是切換成本

這四個層級來自三家供應商、三套 SDK、三種驗證方式,以及三種錯誤格式。要為不同步驟接三個 client,大多數人算一算就覺得不值得,畢竟只是「偶爾修一次解析器,再加上批次清理資料」。結果就是全流程只用一個模型,改版修復時拿到的只有「建議重新適配」,白白花時間卻不知道問題出在哪裡。

AIReiter 把這一層攤平:一把 key、一個 OpenAI 相容介面,背後提供全部四個層級;只要改 request body 裡的 model 欄位,就能切換模型。

# 改版修復:推理層
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<新舊 HTML diff + 目前欄位清單,詢問錨點在哪裡漂移>"}]
  }'

# 批次正規化情報:只改 model 欄位,其餘不動
#   "model": "claude-sonnet-5"
# 長上下文讀完整頁:"model": "kimi-k3"
# 差異歸因:          "model": "gpt-5.6-sol"

如果你已經使用 OpenAI SDK,只要把 base_url 指向 https://aireiter.com/api/v1,其他都不必改。使用 Anthropic SDK 時,則以同一把 key 呼叫 POST /api/v1/messages。

價格方面,Claude 模型為定價七折,GPT 模型半價,Kimi K3 也可透過同一把 key 呼叫。這個流程裡,折扣剛好落在主要成本上;真正花錢的不是改版修復,那是低頻但高價值的偶發呼叫,而是批次情報正規化:你追蹤二十個競爭廣告主,每個有數十到數百張卡片,全部送進模型萃取主張/受眾/投放期間。這是呼叫最密集的一段,使用 Claude Sonnet 可享七折。其次最密集的,是讀完整頁並對齊結構所需的長上下文輸入。成本最高的兩個部分,正好都落在折扣上。

  • 取得 API key

  • 免註冊試用:手動把一組改版前後 HTML 交給兩個模型,比較誰真的能指出錨點漂移的位置,再決定是否要接進流程。

解析器修好、原始卡片也完成批次正規化後,下一步就是把這些情報餵進創意流程,用於決策與素材生成。這正是從關鍵字到完成廣告的完整流程要處理的工作;本文講的則是最前段:可靠地拉取公開資料。

欄位對不對,最終仍由 fixture 說了算

模型給出的修正,在驗證前都只是一個建議。它說「錨點應改成 X」,聽起來合理,但無法保證 X 能涵蓋所有卡片。B2B 廣告有圖文型、純文字型、輪播型,有些帶 landing page、有些沒有;模型看到的兩個樣本不一定包含所有情況。

真正能攔住這個問題的,是和逆向工程中阻擋模型幻覺相同的機制:固定向量比對。把一批已知輸入,也就是幾份存下來的真實頁面 HTML,以及對應的已知正確輸出,也就是你人工檢查過一次的欄位結果,存成提交到 repo 的 fixture。每次修改解析器,不論是自己改還是依模型建議修改,都重新跑一遍 fixture batch,逐欄比對。它能讓你在上游改版後很快判斷:「是我套錯了建議,還是頁面又變了?」全部通過代表修改正確;只有少數失敗時,那些案例的欄位會直接告訴你問題在哪一層。模型負責產生修復建議,fixture 負責判定建議是否正確,兩者不能混為一談。完整的差異比對方法可參考差異測試文章;廣告資料庫解析器套用的是同一套 gate。少了這層,你就是把模型的自信當成正確性,很容易出現「套用建議、沒有報錯、直接上線,三天後才發現某個國家的資料一直都是空的」這種狀況。

結語

B2B 廣告情報往往只能從 HTML 解析,因為廣告資料庫是合規產物,不是產品 API:沒有 API contract,改版也隨時可能發生。要抵抗這種變動,靠的是三個設計:以語意而不是位置作為錨點;欄位缺失時降級而非拋錯;替結果標記完整性,讓「真的沒有」與「解析壞了」看起來不同。真正有價值的不是單支廣告欄位,而是用國家/投放期間/曝光量區間/受眾鎖定面向切出競爭對手的投放策略。模型的位置也很明確:不在解析本身,因為那是確定性的狀態機工作;它該用在維護上,改版後比對新舊結構、提出修復建議時使用推理層,大量把卡片轉成情報時則交給便宜且高併發的層級。但欄位是否正確,最後永遠交給 fixture 裁決。把這些層級接到同一個統一介面後,剩下的摩擦只是一個 model 欄位的切換,而這可透過選擇你的模型解決。

>_AIReiter 模型目錄

快速存取與本指南相關的模型 API

Claude Opus 5

Chat

適用於複雜推理、程式撰寫與長上下文專業工作的高階 Claude 模型。

anthropic取得 API Key >

Claude Sonnet 5

Chat

一款平衡的 Claude 模型,適合進階推理、程式開發與日常工作。

Anthropic取得 API Key >

Kimi K3

Chat

一款適用於程式碼撰寫、寫作、分析與 agent 工作流程的長上下文推理模型。

moonshot取得 API Key >

GPT-5.6 Sol

Chat

一款高級 GPT-5.6 文字模型,適用於高要求的程式設計、推理與長篇代理工作。

OpenAI取得 API Key >

GPT-5.6 Luna

Chat

一款平衡的 GPT-5.6 文字模型,適合日常程式撰寫、寫作與代理工作流程。

OpenAI取得 API Key >

最新文章

GPT-5.6 降價後:Luna 與 Terra 現在到底要多少錢?

2026-07-31

Invalid API Key:修正前先判讀 401 與 403

2026-07-31

修正 OpenRouter 429:供應商錯誤還是速率限制?

2026-07-31

DeepSeek V4 Flash vs GLM-5.2:0731 更新實測

2026-07-31
AIREITER

有問題?請聯絡我們
[email protected]

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 Pro

AI 影片

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0

AI 圖片

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 Pro

部落格

查看全部 →

公司

隱私政策服務條款退款政策

© 2026 AIReiter。保留所有權利。