# 當 Python 爬蟲遇到 Cloudflare > 這是一份**研究過程回顧**,聚焦於「為何失敗、如何選擇」,不著墨於程式碼與操作細節。請務必遵守目標網站條款與法規;本文僅供技術學習與經驗分享。 --- ## 1. 動機與前提 最初的目標其實很單純:**測試 AI 是否能從零製作出一個能抓整本小說的爬蟲**。選了第一個目標站就遇到 Cloudflare 防護,導致一般爬蟲手法全面失靈。從此研究重心轉為:在**合規**前提下,理解並評估各種「可行與不可行」的路徑,包含是否一定要執行 JavaScript、指紋/行為層面的要求、與是否能在不破壞服務的情況下完成資料整理。 --- ## 2. 遇到的問題 * **挑戰與錯誤碼**:反覆出現 Cloudflare 的 PAT/Turnstile 挑戰;`/ajax_novels/...` 取得章節清單時回 **403**;挑戰流程的中途請求回 **401**。 * **環境綁定**:放行憑證(如 `cf_clearance`)**常與 UA、IP、指紋**(字體、圖形、TLS、擴充等)綁定;一旦切換到不同環境(例如改成無頭或改用純 `requests`),很容易立即失效。 * **指紋差異**:無頭瀏覽器、打包的 Chromium、缺少使用者自有的字型/擴充或 TLS 行為,容易被識別為自動化而再次被挑戰。 * **行為偵測**:過快的切換、固定節奏、缺乏「暖機」與隨機延遲,也可能被視為異常行為。 --- ## 3. 方案的調整與失敗原因 以下依時間順序,說明每一次調整時的**考量 → 觀察 → 失敗原因**。 ### 3.1 `requests` 純抓 * **考量**:成本最低、實作最簡、希望直接讀 HTML 或 AJAX 端點。 * **觀察**:403/401 居多,章節 AJAX 端點被擋;頁面顯示「請稍候/Just a moment」。 * **為何失敗**:無 JS 執行、無有效 cookie/Referer、TLS/UA 指紋不符。 ### 3.2 `cloudscraper` + `requests` * **考量**:用現成庫處理 JS 挑戰,避免開瀏覽器。 * **觀察**:沒有成功過;現象與 3.1 類似(持續被挑戰/403/401)。 * **為何失敗**:互動式驗證無法自動完成;指紋/UA/IP 綁定導致憑證易失效。 ### 3.3 Playwright + Bundled Chromium(無頭) * **考量**:可執行 JS,全自動化。 * **觀察**:沒有成功過;現象與 3.1 類似(持續被挑戰/403/401)。 * **為何失敗**:無頭指紋與真人差異過大(UA、Navigator、Canvas/WebGL、`sec-ch-ua*`、TLS 等)。 ### 3.4 Playwright + 單一 Context + 抖動延遲 * **考量**:同一個 session、降低速度與固定節奏,嘗試「像真人」。 * **觀察**:沒有成功過;現象與 3.1 類似(持續被挑戰/403/401)。 * **為何失敗**:**根因仍是指紋**,行為層面的擬真不足以掩蓋。 ### 3.5 Playwright `channel=chrome`(叫出系統 Chrome) * **考量**:換成系統安裝的 Chrome,期望指紋更接近真人。 * **觀察**:**沒有成功過**;實測皆被 Cloudflare **PAT** 擋下(挑戰循環、無法進入穩定抓取)。 * **為何失敗**:`channel=chrome` 啟動的實例**不是**附著在**既有使用者的 profile/context**,指紋/啟動特徵仍與真人使用情境不同,無法滿足站點的驗證要求。 --- ## 4. 最終成功的方案 **Playwright 以 CDP 連線到「系統已安裝的 Chrome」,而且非無頭**。核心是「**同一個環境、不中斷**」。 * **同一個 context**:在你正在使用的 Chrome(或以固定 `user-data-dir` 啟動的 Chrome)完成一次人機驗證後,直接用 CDP attach 到該執行個體,**不要重開或切換到其他工具**。 * **非無頭**:保持可視模式,沿用真實的字型、擴充、TLS、UA 等指紋;無頭切換幾乎必失敗。 * **單頁循序**:在同一個分頁內完成「暖機 → 展開章節 → 逐章擷取」;每一步之間插入隨機延遲與偶爾長休息。 * **避免跨環境**:通過驗證後**不要切 requests** 或改無頭;憑證通常會失效。 * **必要時補 Referer**:列表展開的 AJAX 端點若仍 403,補上正確 Referer 再嘗試。 這個方案之所以穩定,是因為它**與真人瀏覽環境完全一致**,且全程維持同一份「身分」。 --- ## 5. 不使用 Python 的替代方案 * **App 內 WebView**:把流程嵌入 App,由使用者在同一視窗完成驗證與展開,程式再讀取 DOM。指紋與真人一致、穩定度高,但需要產品整合與互動設計。 * **第三方代理 API**:把挑戰與風控外包給供應商,專案只接結果;需評估成本、法遵與 SLA。 --- ## 6. 對 Cloudflare 阻擋爬蟲的結論 * **Python 現況**:就本研究與實測而言,**目前沒有**能在**無頭**或不依賴真實瀏覽器 context 的前提下,長期穩定通過 Cloudflare PAT/Turnstile 的做法。 * **有頭爬取的意義**:在 Cloudflare 防護下,必須以**有頭+同一個真實瀏覽器 context** 才較穩;但這等同一般使用流程,且速度需嚴格控管,**已喪失傳統爬蟲(高速/批次/併發)的效益**。 * **熱門套件現況**:`requests`、`cloudscraper`、Playwright/Selenium 的 headless 模式在本案均**無法穩定繞過**限制;切換環境更容易讓 `cf_clearance` 失效。 * **實務可行路徑**:目前觀察最成功、最自然的方案是 **App 內 WebView**(同環境、真人互動);其次是 **代理第三方 API**。 > 一句話總結:**在強防護網站面前,傳統「無頭爬蟲」不再實用;改以同環境的有頭流程(如 WebView)或走授權/第三方服務,才是現實解。**