cookmeplox 在 3 月 13 日的覆盤裡丟出一個數字:如果不擋,AI scraper 會吃掉 Weird Gloop 旗下 wiki 比所有真人加總還要 10 倍的算力;今年 95% 的 server issue 都是 scraper 帶來的,每月大約 2.5 億次 bot 請求平均落在 100 req/s,spike 期單機被打到 1000 req/s 以上。
AI scraper 怎麼壓垮一個 wiki——cookmeplox 從 10× 流量、residential proxy、到 JA4 偵測的覆盤
這是 Minecraft Wiki、Old School RuneScape Wiki、League of Legends Wiki 三個玩家社群——後兩者各自有約 4 萬條目,能組合出十億級可導覽 URL——的營運方在 2026 年 3 月寫的一份「我們怎麼擋 AI 爬蟲、什麼擋得住、什麼擋不住」的紀錄。重點不在「AI 不好」這種立場,而在:當對手換成把流量散到數百萬支住宅 IP、把 User-Agent 偽裝成最近版本 Chrome、甚至把請求繞過 Facebook link preview 與 Google Translate 來洗來源時,傳統 rate-limit + WAF 規則為什麼一條一條被穿掉。
時間順序是這樣的:先是 Cloudflare challenge 解決了大部分問題,然後 challenge 被繞過,於是改寫了 User-Agent + IP 的自訂防火牆規則,等到對方把 IP 換成 residential proxy 之後,規則升級到 JA4 hash + TLS cipher 指紋,最後 cookmeplox 自己寫了一套 MediaWiki 行為偵測 ML、用決策樹自動提出封鎖建議。他承認這套系統「大概 90% 準確」,長期不可持續。下面把這條時間線拆開——每一段都對應一個防線在什麼壓力下被穿透、下一段是怎麼補上的。
選 Weird Gloop 來寫,不是因為它特別大或特別小,而是因為 cookmeplox 把過程寫得夠細:哪些信號失效、為什麼失效、目前哪些還撐得住。對任何一個有公開 read-heavy endpoint 的服務——文件站、API 文件、產品目錄、開源 wiki——這份覆盤都是可以直接搬回去比對的 reference。三個 wiki 加起來條目過 10 萬,但合法請求基本上落在熱條目上,被 cache 接住;scraper 為了拿到全 dump,會把所有冷條目 + 所有歷史版本一起抓——這是後面壓力曲線翻轉的根因。當人類流量越集中、cache 命中率越高,scraper 跟人類的「單位請求 CPU 成本差」就越大;換句話說,越會用 cache 的站點,反而越容易被 scraper 用一條 cache-miss 路徑打爆。
2024 年以前——challenge 還夠用的世界
Weird Gloop 旗下幾個 wiki 的合法流量其實不算小:人類 pageview 一天上千萬、編輯動作數萬筆,由 MediaWiki + cache 層支撐。傳統的爬蟲問題長這樣:一支機器、一個 ASN、一個固定 User-Agent,每秒打你 10-50 次。Cloudflare 的 managed challenge 與 bot fight mode 在這種模式下幾乎是免費勝利——丟一個 JS challenge、機器無法執行就被擋下,剩下的 99% 流量根本不用看。對手成本曲線是「想多抓就要多花錢解 challenge」,曲線陡到不划算,bot operator 通常會自動繞道去抓沒擋的站點——這個年代的「擋住」與「擋不住」之間有一條清晰的經濟邊界,只要對手有更便宜的替代來源,他就會走那條路。
cookmeplox 估計,challenge 在 2024 上半年大約 90% 場合都有效。剩下的 10% 是會跑 headless Chromium 的稍進階 bot,由人工規則處理。整個 ops team 對 scraper 的注意力可以壓在「每週看一次 alert」的水準,平常時段甚至不需要值班的人盯著 dashboard 看流量分布。
這個世界的隱含前提是:抓資料的人是一個對手——一支 bot、一台機器、一條清楚的請求曲線。當你看到某個 IP 每秒打 30 次、UA 是 python-requests/2.x,整套處理流程是「IP 加黑、發信給 operator、結案」。Cloudflare 的 managed challenge 在這個假設下幾乎是 zero-config 的勝利——所有需要的判斷都壓在 edge node 上,origin 完全不需要知道有人在試圖爬。
2024 下半到 2025——AI 訓練資料採集潮把成本曲線翻過來
翻轉的不是技術,是經濟學。當每一家 frontier lab 都需要結構化、多版本、有人工校對的長尾資料時,遊戲 wiki 變成優質目標:條目間互相連結、語料密度高、版本歷史完整。第一波 AI 爬蟲還算守規矩——掛著真實 User-Agent、有 contact email、會看 robots.txt。第二波就不是了。原因不難猜:當合法 dump 渠道(CC license、Wikipedia 的 dataset、付費 API)拿不到「遊戲版本最新化、欄位完整、跟對手不同步」這幾個變數時,私下抓取就會成為比合法管道更有效的取得策略。
cookmeplox 觀察到的對手特徵:(1)User-Agent 寫成「Mozilla/5.0 ... Chrome/120.0.0.0」這種完全 indistinguishable 的字串;(2)請求源 IP 散在數百萬支住宅 IP 上——Comcast、AT&T、Charter 都有,明顯是某些「residential proxy」服務商把家用網路頻寬「洗」給 bot 客戶;(3)為了規避 ASN-based 規則,部分流量還會經由 facebookexternalhit 的 link preview 服務或 Google Translate 的轉譯 proxy 繞一手,源頭 IP 就變成 Facebook / Google 的合法 ASN。
residential proxy 這個產業在過去兩年已經商品化——市面上可以買到「百萬等級住宅 IP 池、按 GB 計費、API 自動輪替」的服務,月費低到 99 美元起跳。對 AI 訓練資料採集而言,這個價格遠低於「自建 datacenter cluster + 自己跟封鎖打架」的成本;對 wiki 站而言,這個價格曲線意味著「不再有單一 bot operator 等你封」——對手變成了一個 IP 不重複、行為高度散亂的群體。
更精準地說,cookmeplox 量到的 bot 月流量大約 2.5 億次請求,平均落在 100 req/s 上下,但分布極不均勻:白天歐美時段有一段平緩高原、半夜會有 1000+ req/s 的 burst 出現。這個 burst 是 origin server 真正會喘的時段——cache 來不及預熱、CDN 回源被 connection pool 卡住、MediaWiki 的 PHP-FPM worker 排隊塞滿。當這種峰值跟人類流量的早晨高峰重疊時,使用者體感就是「wiki 變慢、編輯送不出去」。Cloudflare dashboard 上看到的「攻擊流量」對 alert system 來說已經跟 DDoS 不易區分——但對手沒有想打掛你,他只是想把資料拉完,於是這場攻擊每天都會在固定時段重來一次。
click any layer to read which mitigation it defeats · 4 layers
L1 · User-Agent 偽裝
把 UA 寫成「Mozilla/5.0 ... Chrome/120.0.0.0」這類 indistinguishable 字串,繞掉所有以 UA 為單一信號的 WAF 規則。需要 JA4 / TLS cipher 指紋才能拆穿——真實 Chrome 的 TLS handshake 形狀與 Python requests / Go net/http 不同。
L2 · Residential proxy 池
同一支 bot 把請求散到數百萬支家用 IP(Comcast、AT&T、Charter 的客戶端寬頻)。徹底打掉「按 IP rate-limit」與「按 ASN 封鎖」兩個 mitigation——每個 IP 看起來只請求一兩次,ASN 又是合法寬頻。
L3 · Google Translate proxy
把目標 URL 餵給 translate.google.com 拿回翻譯後內容,源頭 IP 變成 Google 的合法 ASN,UA 也是 Google 的合法 UA。如果 wiki 一律封 Google 的 IP,會連帶損及真實使用者;如果不封,這條路徑就是免費白名單。
L4 · Facebook link preview
觸發 facebookexternalhit 對任意 URL 做 link preview crawl,內容由 Meta 抓回再轉手。對 wiki 來說源頭是 Meta 的合法爬蟲,不能粗暴封掉;對 AI bot operator 來說則是把抓取成本外包給了 Meta。
互動圖表
AI scraper 以 Chrome UA、住宅 IP、Google Translate proxy、FB link preview 四層繞過封鎖。
真正吃資源的不是頻寬——是 cache miss 的 50-100 倍 CPU
scraper 損害的關鍵不在於把網路打爆,而在於把 origin CPU 燒乾。MediaWiki 的快取設計假設大多數請求落在熱條目、相同參數組合上——這時候直接命中 Varnish / CDN,origin 完全不必動。但 scraper 為了取得「完整 dump」會掃所有頁面的 history、所有 diff、所有 namespace 變體、加上各種看似無意義的 query string。這些請求每一筆都是 cache miss,落到 origin MediaWiki + DB 上跑一輪完整渲染。對 MediaWiki 而言這代表 parse template、解析 wikitext、查 link table、套用 skin——一整條 pipeline 跑完才回吐 HTML。
cookmeplox 給的數字:unusual-parameter 請求的 CPU 成本是 cache hit 的 50-100 倍。下面這個 widget 把這個倍率攤出來——拖動 slider 改變「unusual-parameter 請求比例」,看 effective 計算成本如何被少數高成本請求拉爆。
drag handle to vary the share of cache-miss requests · 0–100%
每 100 個請求相當於 100 個 cache-hit 的算力成本——cache-miss 倍率取 75×(50-100 範圍中位)。
當 unusual-param 比例只是 5%,總成本就已經是 cache-only 場景的 4.7 倍;拉到 20% 就突破 16 倍——cookmeplox 觀察到的「10× 算力」上限在這條曲線上對應的是 ~12% 比例。
互動圖表
unusual-param 佔 5% 時 CPU 成本是純 cache 的 4.7 倍,佔 12% 達 10 倍;75× miss 是 origin 崩潰根因。
這個倍率解釋了為什麼「流量看起來才上升一兩倍、伺服器卻全面 timeout」。一個 scraper 操作員只要把 5-10% 的請求隨機 salt 一個 query string(例如附上 timestamp、隨機 UUID、不存在的 lang code),整體 origin CPU 就已經被推到危險區。傳統 rate-limit 看的是 req/s,根本看不到這條垂直壓力。
更糟的是,scraper 對「unusual parameter」的偏好不是 bug 而是 feature——它要的就是「跟訓練資料快照不同」的版本,於是會主動枚舉每個條目的所有歷史 revision、所有 diff、所有 namespace 變體。OSRS Wiki 4 萬條目對應的可導覽 URL 數量超過 10 億,這正好就是「能用 query string 組合出來」的空間。對手知道這個空間打不滿,但也知道每打進一個就賺一筆——同時把你 origin 多消耗一份 50-100 倍的 cache-miss 算力。對 wiki operator 而言,這個策略最惡意的地方是「正當行為的灰色地帶」:raw revision diff 對人類編者也是常用功能,沒辦法粗暴禁掉;要分辨「人在看 diff」與「bot 在掃 diff 空間」需要看請求頻率與 referrer 模式,而這兩個信號剛好也都能被偽造。
從營運角度看,cookmeplox 估算過今年大約 95% 的 server issue 都源自 scraper——不是直接打掛 origin,就是把 CPU 推高到觸發其他 cascading failure(DB connection pool 撐爆、background job queue 塞住、CDN 回源節點失聯)。換句話說,wiki 大部分的 incident postmortem 結論都會指向同一個 root cause——而傳統 SRE playbook 對 root cause 的處方是「擋住源頭」,但這個源頭現在沒有可以擋的單一頂點。對工程團隊更實務的影響是:每一個 unrelated 的效能問題,debug 時都要先排除「是不是 scraper 觸發的」這個假設,平均 MTTR 拉長一倍。
JA4 指紋 + MediaWiki 行為偵測——目前撐住的兩道防線
當 IP / ASN / UA 三個傳統信號都被打掉之後,剩下能用的是 client 在 TLS handshake 階段就洩漏的形狀——HTTP 版本協商順序、TLS cipher suite 排序、ALPN 列表、extension 順序,這些組合可以 hash 成 JA4 簽名。真實 Chrome 120 的 JA4 與 Python requests、Go net/http、Node undici 都不相同——bot 即使把 UA 寫成 Chrome,TLS 形狀仍露馬腳。JA4 比起前代的 JA3 對 HTTP/2 與 QUIC 更友善、誤判率更低,在 Cloudflare 與內部 WAF 規則裡都已經是 first-class 欄位。
第二道是 MediaWiki-specific 行為信號:人類點進一個條目通常會接著載入 CSS / JS / 圖、會用 search box、會在條目間跳轉、會偶爾打開 edit history;bot 通常只請求 raw HTML、不跑 JS、不請求縮圖、不點 search。cookmeplox 寫的決策樹會在「session 內請求模式」這個維度上對比群體分佈,自動 propose 封鎖規則給人工核可——而不是直接 ban——這個 human-in-the-loop 設計是必要的,因為某些合法使用情境(例如 archive.org 的快照爬蟲、單純抓 raw text 的研究者)也會跑出類似 bot 的形狀。
這套行為偵測的價值不在 detection 本身,而在「signal 不依賴對方的 cooperation」——UA、IP、ASN 都是對手可以任意更改的欄位,但「會不會載 CSS」是對手要花成本才能模仿的行為,而模仿成本就會 push 對手提高 per-request CPU 與 bandwidth,等於 implicitly 收取「過路費」。從這個角度,每一條 behavioral check 都是在抬高對手的單位成本而不是徹底擋住他。對手只要決定「不值得為了這個站多付那幾倍 cost」,自動就會去別處抓——這跟早期的 challenge 模式邏輯相同,只是把判斷從「會不會跑 JS」往上推到「會不會完整模擬 browser session」。
2024 H1——丟 JS challenge 給可疑請求;無法執行 JS 的機器被擋下。
命中率:~90%。對「跑 headless Chromium 並過 challenge」的對手無效,但這類成本相對高、流量小。
這一階段不需要 ML、不需要指紋——一個 toggle 解決大半問題。
2024 H2——自寫規則:封掉異常 UA 字串組合、封掉 datacenter ASN(DigitalOcean / Hetzner / OVH 等)。
對「掛真 Chrome UA + datacenter IP」的中段對手有效;對 residential proxy 完全無效——IP 落在合法寬頻 ASN 上。
傳統 WAF 規則的有效期約 6 個月,然後對手換層繞過。
2025——加入 JA4 / TLS cipher fingerprint 與 HTTP/2 setting 順序匹配。
真實 Chrome 的 TLS handshake 形狀對 Python requests、Go net/http、Node undici 都不同;即使 UA 偽裝成 Chrome,JA4 hash 立刻露出 client library。
對「沒花力氣偽造 TLS」的 bot 有效;對 puppeteer-real-stealth 這類用真 Chromium 的對手無效。
2025-2026——cookmeplox 自寫的決策樹 ML,看 MediaWiki-specific 行為信號:人類會載 CSS / JS / 縮圖、會用 search、會跨條目跳轉;bot 通常不會。
系統 propose 封鎖規則給人工核可,避免自動誤殺真實使用者。準確度 ~90%,作者自評長期不可持續——對手只要把「人類典型副請求」一起送出就會被誤判為真人。
這就是現在站住的防線——但靠的是還沒有對手認真去模仿 MediaWiki 行為。
下面這張表把四類流量並排——可以點欄位排序,看每個防禦面在不同對手前的有效性差異。重點是「同一格」與「不同格」的對應關係:一旦對手能讓自己跟真人在某一欄位「同格」,這一欄就被廢掉,需要靠剩下的欄位接管。
click any column header to sort · 5 columns × 4 rows
| 流量來源 | User-Agent | ASN | JA4 / TLS | MediaWiki 行為 |
|---|---|---|---|---|
| 真實 Chrome 使用者 | Chrome 120 | 家用寬頻 | Chrome 形狀 | 含 CSS / JS / search / 跳轉 |
| Residential-proxied bot | Chrome 120(偽) | 家用寬頻 | Python / Go 形狀 | 只 raw HTML、無副請求 |
| Datacenter bot | Chrome 120(偽) | Hetzner / OVH / DO | Python / Go 形狀 | 只 raw HTML、無副請求 |
| Facebook / Google 代洗 | facebookexternalhit / Google | Meta / Google | 合法 Meta / Google 形狀 | 只 single GET、無 session |
互動圖表
四類流量在 User-Agent 與 ASN 欄位難以區分;只有 MediaWiki 行為欄(是否請求 CSS/JS/縮圖)仍能可靠識別 bot。
欄位順序刻意排成「對手能偽造的難度遞增」——從 User-Agent 一路到 MediaWiki 行為,需要的工程力一級比一級高。讀法:最後一欄「MediaWiki 行為」對四類流量的區辨力最強——前三類 bot 都在「只 raw HTML」這一格,跟真人有質的差別。問題在於這個信號最容易被對手模仿(順手送個假的 CSS 請求即可),所以 cookmeplox 才會說 ML 系統長期不可持續。第四列「Facebook / Google 代洗」最棘手:它把所有欄位都漂白成合法值,唯一的可疑點是「single GET、無 session」——但真實的 Facebook link preview 與 Google Translate 也確實就是這個 pattern。要分辨「真 link preview」與「拿 link preview 當 proxy 在抓 dump」需要看 cross-request 統計:同一 endpoint 是不是被反覆 fetch、URL 空間是不是被系統性枚舉。
今天還撐得住,但不知道能撐多久
cookmeplox 文末的自評是「仍然 OK」——前述四層加起來足夠把 95% scraper 算力擋在 origin 之外、伺服器一週還是穩定的。但他也承認 90% 準確的自寫 ML 並不是穩態解:每一條他想出的行為信號,下次 scraper iteration 就會被加進偽裝清單;同時 frontier lab 之間的競爭只會讓 residential proxy 池更便宜、行為偽裝更像人。他甚至預期「一年內」當前的這套組合會被穿透——不是因為哪一塊壞掉,而是因為對手會把每一塊都升一個等級:UA 偽裝會更精細、residential proxy 池會擴大、Playwright 風格的 full-stack browser bot 會普及,連 MediaWiki 行為信號也可能被當成輸入特徵餵進對手的偽裝模型。
bot 流量整體均線約 100 req/s,但分布極不均勻——數個 spike 把瞬時壓力推到 1000+ req/s…
Weird Gloop bot 月流量 2.5 億次、均值 100 req/s,spike 期超過 1000 req/s,達 DDoS 等級壓力。
把這個故事抽離掉具體 wiki,留下三條對所有「面向公開 web 的 read-heavy 服務」都適用的觀察:(1)AI scraper 已經從「掛 UA 的 polite bot」進化到「散佈在合法住宅 IP、模仿真實 Chrome、會繞 Google Translate」的對手——傳統 rate-limit + IP 黑名單已不夠用;(2)真正的瓶頸是 CPU 不是頻寬,cache-miss 的 50-100 倍倍率讓只佔流量 5-10% 的 unusual-param 請求就能把 origin 推爆;(3)目前能撐住的是 TLS 指紋 + behavioral ML,但這兩個都是猫鼠游戲,作者自己給出的時間視野是「一年內」。
有兩條結構性的選項超出了單站可以動手的範圍。第一條是 token bucket + proof-of-work——對每一個 session 收一點 client-side compute 成本,把對手的單位請求變貴。社群裡 Anubis 這類專案在 2025 年下半已經跑出來,付出的代價是真實使用者首次造訪會多 1-2 秒延遲,對黏性低、來自搜尋結果的瀏覽者來說足以勸退一部分人,對 wiki 這種「來查一個答案」場景特別致命。第二條是行業層級的 robots.txt 重新議價——讓 AI 公司付費取得結構化 dump、而不是讓所有人用 bot 偷抓。這條路需要的不是技術,而是法律與商業條款;Reddit、Stack Overflow 已經在走,但 wiki 這類 community-run 站點普遍沒有那個議價籌碼。
從讀者自己的服務看:如果你的 web stack 的成本曲線是「請求數 → CPU」線性的,那 scraper 對你只是頻寬問題;但只要你的 stack 裡有任何「cache 命中與否差幾十倍」的元件(render 重的 SSR、SQL JOIN 重的 endpoint、需要外部 API call 的 enrichment),scraper 就會自動找到那條曲線並把它打爆。把 cache hit rate 與 origin CPU 一起放上 dashboard,不要只看 req/s——這條觀察值是 2026 年版的 SRE common sense,也是 cookmeplox 整篇文章最該帶回去的 takeaway。對於 cookmeplox 的 wiki,下一個合理動作是把 history / diff 這類昂貴 endpoint 移到單獨 worker pool,讓它被打爆時不會牽動主流量;對讀者的服務,相同的思路是先盤點「哪些 endpoint cache miss 倍率最高」,再決定要不要單獨切池、單獨設 rate-limit、或乾脆藏在登入後面。
The lesson:如果你的服務有公開可枚舉的內容空間(wiki、文檔站、產品目錄、API explorer),把「unusual-parameter 請求的 CPU 倍率」當成第一個監控維度——它比頻寬與 req/s 都早爆,而且常規 WAF dashboard 看不到;當 cache hit rate 跌一個百分點而 origin CPU 跳一倍,AI scraper 已經在門外了。