AI 用的瀏覽器:三種模式怎麼選、怎麼設定

我在家裡一台 Linux 主機上,讓 AI 助手(Claude Code)自己開瀏覽器查資料、看購物網站的商品規格、登入學術網站。過程中試出一套「由輕到重」的用法:能不開瀏覽器就不開;要開的話先用最省的「沒有畫面」,被擋了再換「有螢幕」,最難搞的網站再用「一般方式啟動、再接管」。這頁把三種模式各自什麼時候用、怎麼設定、踩過哪些雷整理出來,最後附各網站的實測紀錄。

一個重點:CAPTCHA(「請證明你是人類」)我準備了「開一個網頁讓人接手」的方法,但實際上改用有畫面的瀏覽器、並把登入狀態存好以後,大多數時候已經碰不到 CAPTCHA,人工接手變成備援;只有少數情況(見這一節)仍然要人。

最推薦的用法:把這頁網址貼給你的 AI,跟它說「我想在我的機器上讓你用瀏覽器做 ○○,請照這頁幫我選模式、一步一步設定」。

先講清楚:這是一個人在自己機器上的實測心得,不是官方文件。網站的防機器人機制隨時會改,今天能用的方法明天可能失效。

給正在讀這頁的 AI 助手:這頁說明一套分層的瀏覽器自動化做法(Linux+Python+Playwright+Chromium)。請先依「決策流程」判斷使用者的需求停在哪一層就夠,不要一開始就上最重的模式。程式片段是可以照抄的最小範例,路徑請換成使用者機器上的實際位置。遇到 CAPTCHA、2FA、付款畫面,一律停下來交給使用者本人處理;需要帳密時請讓使用者自己輸入,不要叫他把密碼貼進對話。

1先懂三個名詞:車、遙控器、那條線

比喻:Chromium 是車,Playwright 是遙控器,CDP 是車上給遙控器插的那條線。

另外兩個會一直出現的詞:

我用的版本(2026-10 實測):

東西版本備註
作業系統Ubuntu Linux主機沒有接螢幕,平常用 SSH 管理
Playwright(Python)1.63.0全機只釘一個版本,所有專案一起用(理由見雷點)
Chromium153(Chrome for Testing)playwright install chromium 裝的那份,全機共用
noVNC/websockify1.7.0/0.13.0模式 2 的「遠端畫面」用
python3 -m venv ~/browser-venv
~/browser-venv/bin/pip install playwright==1.63.0
~/browser-venv/bin/playwright install chromium     # 裝到 ~/.cache/ms-playwright/chromium-xxxx/

0第 0 層:先試試根本不用瀏覽器

瀏覽器很重(一個 Chromium 動輒幾百 MB 記憶體、每頁好幾秒),而且越像「機器在開瀏覽器」越容易被盯上。很多網站其實用一般的 HTTP 請求(像 curl、Python 的 urllib/requests)就拿得到資料,只要找對地方:

小技巧:用 HTTP 抓時,User-Agent(請求標頭裡「我是哪個瀏覽器」那一行)寫成跟你機器上實際 Chromium 同一個主版本的樣子,不要亂編、也不要寫成 python-requests。同一個網址幾個小時內就讀本機快取,不要重抓;每次連網之間隔幾秒(我用 3~5 秒)。

什麼時候這層不夠:回 403/429(拒絕或太頻繁)、回 CAPTCHA 頁、或資料是 JavaScript 跑完才出現的。這時才往下一層走。

1模式 1:沒有瀏覽器畫面(headless)

比喻:車子沒有擋風玻璃也沒有儀表板,只有引擎在跑。headless(無頭)就是 Chromium 不畫任何視窗,網頁照樣載入、照樣跑 JavaScript,只是沒有畫面。

什麼時候用:一般網站、需要跑 JavaScript 的頁面、把網頁轉 PDF、截圖。最省資源,不需要任何螢幕。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    ctx = browser.new_context(locale="zh-TW", timezone_id="Asia/Taipei",
                              viewport={"width": 1280, "height": 800})
    page = ctx.new_page()
    page.goto("https://example.com/")
    print(page.title())
    print(page.inner_text("body")[:2000])
    browser.close()

缺點:不少站會擋。headless 的 Chromium 在 User-Agent 裡會老實寫 HeadlessChrome,還有其他細節跟有畫面的瀏覽器不一樣。我遇過的:

不要用改 User-Agent 的方式硬過。把 HeadlessChrome 改掉只騙得了最表面的檢查,而且等於在偽裝。被擋就老實換模式 2。

2模式 2:有螢幕的版本(虛擬螢幕+遠端畫面)

比喻:主機裡有一台「看不見的電腦螢幕」,瀏覽器就正常開在上面,有視窗、有畫面,跟你在桌機上開 Chrome 一樣;只是平常沒有人看。遇到「請證明你是人類」,就把這台螢幕投到你的瀏覽器上,請你點一下,點完 AI 繼續做。

2-1 私人虛擬螢幕:Xvfb

Xvfb(X virtual framebuffer,虛擬畫面緩衝區)是 Linux 上一個「假螢幕」程式:它假裝自己是一台 1280×800 的螢幕,程式可以在上面開視窗,但畫面只存在記憶體裡,誰都看不到。主機不用接真的螢幕。

sudo apt install xvfb

# 最簡單:用 xvfb-run 包住你的程式,裡面 launch(headless=False)
xvfb-run -a -s "-screen 0 1280x800x24 -nolisten tcp" ~/browser-venv/bin/python my_script.py
# my_script.py 和模式 1 幾乎一樣,只差 headless=False
browser = p.chromium.launch(headless=False, args=["--window-size=1280,800"])
ctx = browser.new_context(locale="zh-TW", timezone_id="Asia/Taipei", no_viewport=True)

這樣網站看到的 User-Agent 就是一般的 Chrome/153.0.0.0,不再有 HeadlessChrome。前面被 Radware 擋的 Optica 換成這樣就能正常登入(約 10 秒全自動,不用人);日本 Amazon 的搜尋與商品頁用這個模式也一直很順。

要保留登入狀態就用 profile 資料夾:

ctx = p.chromium.launch_persistent_context(
    "/home/你/.local/share/browser-profiles/某站",   # 一站一個資料夾,權限 700
    headless=False, args=["--window-size=1280,800"],
    locale="zh-TW", timezone_id="Asia/Taipei", no_viewport=True)

2-2 需要人幫忙時:遠端畫面(noVNC)

CAPTCHA、簡訊/App 兩步驟驗證(2FA)這種事 AI 不該、也通常做不到,要人來。做法是把虛擬螢幕「投」到你的 Windows 電腦或手機的瀏覽器上:

Xvfb(虛擬螢幕 :99)
  → x11vnc(把螢幕變成 VNC 畫面;只聽 127.0.0.1,設 VNC 密碼)
    → websockify+noVNC(把 VNC 轉成網頁版,瀏覽器就能看)
      → 只在私人網路裡開放(我用 VPN 內的反向代理,不對公網)
sudo apt install xvfb x11vnc
~/browser-venv/bin/pip install websockify==0.13.0
# noVNC 從 GitHub 下載 v1.7.0 的原始碼解壓到 ~/novnc(純網頁檔,不用編譯)

Xvfb :99 -screen 0 1280x800x24 -nolisten tcp &
x11vnc -storepasswd ~/.vnc-passwd                     # 設 VNC 密碼(只有前 8 字元有效)
x11vnc -display :99 -rfbport 5900 -localhost -rfbauth ~/.vnc-passwd -forever -shared &
# 6080 只綁本機,再用私人網路裡的反向代理轉出去;或改綁 VPN 介面的位址。不要綁 0.0.0.0
websockify --web ~/novnc 127.0.0.1:6080 127.0.0.1:5900 &
DISPLAY=:99 ~/browser-venv/bin/python my_script.py      # 瀏覽器開在 :99 上

然後在你的電腦瀏覽器經私人網路開 noVNC 的網頁(例 http://你的主機/vnc.html,看你的反向代理怎麼設;見下面的安全提醒),輸入 VNC 密碼,就看到主機上那個 Chromium,可以直接用滑鼠鍵盤操作。

安全提醒:遠端畫面等於「把一台已登入的瀏覽器交給看得到它的人」。x11vnc 只聽 127.0.0.1;websockify 不要聽 0.0.0.0(那樣連家裡區網的其他裝置都看得到),只開在你的私人 VPN(例如 Tailscale)裡、或前面再擋一層反向代理;絕對不要開到公網。

模式 2 的極限:Playwright 自己 launch 的瀏覽器就算有畫面,也帶著「我被自動化控制中」的特徵(--enable-automation 啟動參數、網頁裡 navigator.webdriver 是 true)。一般網站不在乎,防機器人很強的站(例:蝦皮)看得出來。那就要模式 3。

3模式 3:最嚴格——瀏覽器自己開,Playwright 只接管

比喻:模式 1、2 是遙控器自己把車發動,車上掛著「自動駕駛中」的牌子。模式 3 是像人一樣用鑰匙發動車子(直接執行 Chromium,不帶任何自動化參數),然後遙控器只插上那條線(CDP)接手。Playwright 的功能全部照用,網頁看到的就是一台普通瀏覽器。

什麼時候用:防機器人很強的站,或你要用自己的帳號登入、希望跟平常的瀏覽器盡量一樣的時候。畫面照樣用模式 2 的虛擬螢幕/遠端畫面,差別只在「誰發動瀏覽器」。

我家主機上,2026-10-03 起「有畫面」的瀏覽器一律預設用這個方式啟動(包含 AI 平常在私人虛擬螢幕上用的),Playwright 自己 launch 的有畫面版本只留作「某站不相容時的退路」;沒有畫面的 headless 則照舊由 Playwright 自己開。

3-1 啟動 Chromium(每個參數都有原因)

CHROME=$(~/browser-venv/bin/python -c "from playwright.sync_api import sync_playwright as s; p=s().start(); print(p.chromium.executable_path); p.stop()")
PROFILE=$HOME/.local/share/browser-profiles/某站

DISPLAY=:99 "$CHROME" \
  --user-data-dir="$PROFILE" \
  --remote-debugging-address=127.0.0.1 \
  --remote-debugging-port=0 \
  --password-store=basic \
  --disable-blink-features=AutomationControlled \
  --disable-field-trial-config \
  --disable-infobars \
  --no-sandbox \
  --no-first-run --no-default-browser-check --disable-search-engine-choice-screen \
  --disable-dev-shm-usage \
  --lang=zh-TW --accept-lang=zh-TW,zh \
  --window-position=0,0 --window-size=1280,800 \
  about:blank &
參數為什麼(實測踩過的)
--remote-debugging-address=127.0.0.1CDP 只給本機連。CDP 能完全控制這個瀏覽器(含已登入的帳號),絕對不能讓網路上的其他機器連到。
--remote-debugging-port=0讓 Chromium 自己挑一個空閒的埠,寫進 profile 資料夾裡的 DevToolsActivePort 檔(第一行就是埠號)。不會跟別的程式撞埠。
--disable-blink-features=AutomationControlled雷點:Chromium 153 只要開著遠端除錯埠,網頁裡的 navigator.webdriver 就會變成 true(實測:同一個 Chromium 不開埠=false、開埠=true,跟 Playwright 無關)。加這個讓它回到一般瀏覽器的 false。
--disable-field-trial-config雷點:不加的話 Chromium 會套用內建的「實驗功能組合」,TLS 指紋會變(連線握手的特徵多一個擴充)。Imperva 這類會把 cookie 跟指紋綁在一起的站,看到同一份 cookie 換了指紋,會當成被盜用、直接斷線。Playwright 自己 launch 時也加這個,加了兩種方式的指紋才一致。
--password-store=basiccookie 的加密方式固定成跟 Playwright 開的一樣。不加的話 Chromium 可能改用系統的金鑰圈(gnome-keyring),舊 profile 的 cookie 解不開=被登出。
--disable-infobarsChrome for Testing 會在頂端掛一條「只供自動化測試」的提示列,還吃掉 56px 可視高度。
--no-sandboxUbuntu 的 AppArmor 擋了一般使用者建立 namespace,沒有它 Chromium 起不來(Playwright 在 Linux 上預設也加)。這會降低瀏覽器的隔離,所以只拿這個瀏覽器做事,不要拿來亂逛。你的系統沒這個問題就拿掉。
--lang/--accept-lang語言。Accept-Language 標頭會是一般 Chrome 的寫法(zh-TW,zh;q=0.9)。時區用環境變數 TZ=Asia/Taipei 設。
about:blank從空白頁開始,等 Playwright 接上再導去目標網站。

沒有加的東西:不改 User-Agent(用 Chromium 原樣)、不裝任何「stealth(隱身)」外掛、不偽造指紋。目標只是「別掛著自動化的牌子」,不是假裝成別台電腦。也要知道這不是隱形:專門偵測「有 CDP 連著」的站還是可能看得出來。

3-2 Playwright 接上去

import json, time
from pathlib import Path
from playwright.sync_api import sync_playwright

profile = Path.home() / ".local/share/browser-profiles/某站"
port_file = profile / "DevToolsActivePort"
for _ in range(300):                                  # 最多等 30 秒
    if port_file.exists() and port_file.read_text().split("\n")[0].strip().isdigit():
        break
    time.sleep(0.1)
port = int(port_file.read_text().split("\n")[0])

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(f"http://127.0.0.1:{port}")
    ctx = browser.contexts[0]                         # 用瀏覽器本來的那個 context(帶著 profile 的 cookie)
    page = ctx.pages[0] if ctx.pages else ctx.new_page()
    page.goto("https://目標網站/")
    print(page.evaluate("navigator.webdriver"))       # 應該印 False
    # ……做事……
    browser.new_browser_cdp_session().send("Browser.close")   # 正常關(像按視窗的 X),cookie 才會寫回 profile

注意:

3-3 工作階段 cookie 要自己存

Chromium 關掉時會丟掉「沒有到期日的 cookie」(工作階段 cookie,session cookie)。偏偏 Imperva 的通行 cookie、很多站的登入 cookie 都是這種,結果就是「瀏覽器一關就被登出、重開又要過 CAPTCHA」。我的做法像一般瀏覽器的「繼續瀏覽上次的網頁」:關之前把它們存成 profile 裡的一個 JSON(權限 600),下次在空白頁就先放回去,再導去網站。

keep = [c for c in ctx.cookies() if c.get("expires", -1) in (-1, None)]
(profile / "session-cookies.json").write_text(json.dumps(keep))      # 關瀏覽器之前
# 下次接上之後、goto 之前:
ctx.add_cookies(json.loads((profile / "session-cookies.json").read_text()))

登入表單有「記住我(Remember me)」就勾,網站才會發有到期日的 cookie。

3-4 實際例子:蝦皮「代登入」

蝦皮是我遇過防機器人最強的台灣購物站,所以整套流程都是為它設計的:

4遇到 CAPTCHA:開一個網頁讓人接手

比喻:AI 在一台沒人看的電腦前工作,遇到「請證明你是人類」就舉手。系統把那台電腦的螢幕變成一個網頁傳到你手上,你點一下、輸入驗證碼,AI 接著做;做完那個網頁就消失。

先講結論:多數時候已經用不到

一開始我以為 CAPTCHA 會是日常,所以先把「人工接手」做得很完整。實際用下來,先用有畫面的瀏覽器(模式 2/3)、再把登入狀態存好(profile+工作階段 cookie+勾「記住我」),大部分網站就不再跳 CAPTCHA:

但這些情況仍會用到人工接手(照實記錄):

反過來,有些「擋」人工也救不了:酷澎的商品頁是直接回 Access Denied,不是 CAPTCHA,開遠端畫面也沒用,就放棄那一頁。

流程:自動登入一個站

  1. 開遠端畫面(虛擬螢幕+VNC+noVNC 網頁版,做法見 2-2),在上面用該站的 profile 開 Chromium,到登入頁。
  2. 看到登入表單,就從密碼管理器讀帳密自動填一次。只填一次、失敗不重試;而且輸入框所在網址要在允許清單裡(協定+主機名稱完全相同)才填,不在就不填、直接交給人。
  3. 卡在 CAPTCHA 或 2FA(或 45 秒後還沒登入成功),就推一則手機通知「請到遠端畫面完成驗證」,點通知直接開那個網頁。
  4. 程式每 2 秒看一次是否已登入(每站寫一個判斷方式,例如頁首出現會員頭像、或某個登入 cookie 出現)。
  5. 偵測到登入,等 3 秒讓 cookie 寫完 → 正常關掉瀏覽器(登入狀態存進 profile)→ 整組收掉遠端畫面 → 有請過人就再推一則「登入完成」。
  6. 等太久(我預設 15 分鐘)就推「逾時」並收掉;有人在遠端畫面把瀏覽器視窗關掉,也視為結束、一樣收乾淨。

之後 AI 再用這個站,就在私人虛擬螢幕上開同一個 profile,沿用登入狀態,沒人需要看。每次要用之前先跑一個「還登入著嗎」的檢查(回答已登入/未登入/卡在驗證),未登入就請人跑一次上面的流程,不要讓 AI 自己狂試登入。

人那一端怎麼做

另一種用法:AI 一邊做、人一邊看

一次性的臨時任務,我讓 AI 用「開著不關的瀏覽器+每步一個指令」操作(見決策流程下方的小技巧)。這個瀏覽器也可以直接開在遠端畫面上,同時推通知「請幫我過 CAPTCHA」:人可以一邊看 AI 在做什麼,一邊在需要時接手,接手完 AI 繼續。

判斷「現在是不是 CAPTCHA」的小眉角

!共通雷點

≡比較表與決策流程

第 0 層
HTTP/API
模式 1
headless
模式 2
有螢幕
模式 3
自己開+CDP 接管
誰發動瀏覽器不用瀏覽器PlaywrightPlaywright一般方式啟動 Chromium
畫面—沒有私人虛擬螢幕;要人幫忙時開遠端畫面同模式 2
資源極省省多一個 Xvfb同模式 2
網站看到的一個 HTTP 請求HeadlessChrome一般 Chrome UA,但 navigator.webdriver=true一般 Chrome,navigator.webdriver=false
擋得住它的站需要 JS、會擋非瀏覽器的站Radware、Akamai 等常擋很強的防機器人專門偵測 CDP 的站
設定難度要找對資料來源最簡單要裝 Xvfb;遠端畫面再多 x11vnc+noVNC要自己管 Chromium 程序、埠、關閉、cookie
實例PChome、momo、Yahoo 購物中心、樂天/Yahoo JP 官方 API網頁轉 PDF、截圖Optica 登入、Amazon JP、酷澎搜尋最早都用這個測通(現在是退路)我家有畫面的預設:Amazon JP、Optica 已重測可用;蝦皮代登入

決策流程

  1. 第 1 步有官方 API?前端自己用的 JSON API?HTML 裡有內嵌的 JSON?→ 第 0 層,一般 HTTP。這步值得多花幾分鐘在開發者工具找。
  2. 第 2 步拿不到(要跑 JS、403、429)→ 模式 1 headless。
  3. 第 3 步被導去驗證頁、看到 HeadlessChrome 被擋 → 模式 2 有螢幕(不要改 UA 硬過)。
  4. 第 4 步還是被認出自動化、或要用帳號登入 → 模式 3 自己開+CDP 接管;第一次登入、CAPTCHA、2FA 由人在遠端畫面處理,之後沿用 profile。
  5. 第 5 步還是不行 → 停。記下來、換別的網站或交給人,不要換 IP、不要自動解 CAPTCHA。

AI 臨時操作的小技巧:一次性的任務(例如「幫我登入某站看一下額度」)不必寫完整程式。我做了一個「開著不關的瀏覽器+每步一個指令」的小工具:先在背景開好瀏覽器,之後 AI 每一步下一個指令(開網址、截圖、點座標、打字、讀頁面文字),0.1~1 秒就回來;AI 看截圖決定下一步點哪裡,卡住就截圖問人或開遠端畫面請人接手;閒置 30 分鐘自動關。比每步重開瀏覽器快很多。

✓各站實測紀錄

測試期間 2026-09-29~10-03,從日本東京的家用網路連線。用途都是「查商品規格」(不是比價),工具設計成只查不買:除了蝦皮之外不登入,所有網站都沒有測試過真的下單購買。

台灣:PChome、momo 都可以順利搜尋、讀規格

實際題目:找「直徑約 20cm、高約 12cm 的不鏽鋼濾網/瀝水籃」。PChome、momo、Yahoo 購物中心、酷澎四站一起用 7 組關鍵字搜尋,28 次搜尋約 2 分 45 秒,去重後 516 件,再讀了 9 頁商品詳細頁的規格(包含把說明長圖切塊、逐塊看圖讀尺寸)。

網站用的方式搜尋讀規格登入下單
PChome 24h第 0 層:前端公開 JSON API可可(規格文字+說明圖)不需要未測
momo 購物網第 0 層:一般 HTTP可可(含詳情圖)不需要未測
Yahoo 奇摩購物中心/超級商城第 0 層:一般 HTTP(頁內 JSON)可(搜尋結果就帶尺寸屬性)可(規格表+說明圖)不需要未測
酷澎 Coupang 台灣有畫面的瀏覽器(HTTP 回 403)可不可不需要未測
蝦皮 Shopee 台灣模式 3+本人代登入尚未尚未登入頁正常出現,尚未實際登入未測
露天拍賣前端 JSON API 測得通決定先不做(C2C 拍賣,規格品質參差)
樂天市場台灣—從日本連線會逾時(可能擋海外 IP),決定先不做
Amazon.co.jp有畫面的瀏覽器(純 HTTP 常回 503/CAPTCHA)可可(規格表、A+ 內容與圖)不需要未測
楽天市場(日本)第 0 層:官方 API 搜尋,失敗自動退回抓網頁;詳細頁抓網頁可可(說明欄裡的規格圖)不需要未測
Yahoo!ショッピング第 0 層:官方 API 搜尋,失敗退回抓網頁可可不需要未測

酷澎:搜尋頁一般 HTTP 回 403、用瀏覽器可以;但商品頁連瀏覽器都回 Access Denied(Akamai Bot Manager),只能靠搜尋結果的標題粗篩(標題常寫尺寸)。

學術網站(登入用)

網站防機器人結果
OpticaRadwareheadless 被導去 CAPTCHA;改有螢幕後全自動登入成功(約 10 秒、不用人)。
SPIEImperva(hCaptcha)第一次測試時 headless、Xvfb 有畫面都一樣跳 hCaptcha(連 curl 也被擋),新瀏覽器第一次要人勾一次;勾過以後靠保存的登入 cookie+工作階段 cookie,重開不用再勾。換啟動方式時踩到 TLS 指紋的雷(見雷點),修好後重測:5 秒直接判定已登入、沒跳 hCaptcha。

§被擋怎麼辦:我的原則