นี่คือกับดักที่นักพัฒนา browser-automation ทุกคนต้องตกหลุมพรางสักครั้งหนึ่งพอดี: คุณเพิ่ม --proxy-server=http://user:pass@host:port เข้าไปใน launch flags ของ Chrome เบราว์เซอร์เริ่มทำงานได้ปกติ แล้วทุกหน้าก็ค้างอยู่ที่ป็อปอัปยืนยันตัวตนที่สคริปต์ของคุณมองไม่เห็นและคลิกไม่ได้ Chrome ตัดข้อมูลรับรอง (credentials) ออกจาก proxy flag อย่างเงียบ ๆ ไม่มี error ไม่มีบรรทัด log มีแค่กล่องโต้ตอบ modal ในเบราว์เซอร์ที่ไม่มีใครเฝ้าดู
คู่มือนี้คือแผนที่ฉบับสมบูรณ์ของวิธี การยืนยันตัวตน (authentication) ของพร็อกซีที่ใช้งานได้จริงใน Selenium และ Playwright ในปี 2026 — วิธีไหนควรใช้ วิธีไหนควรเลี่ยง และโค้ดที่แม่นยำสำหรับแต่ละวิธี (สำหรับการเลือกพร็อกซีและกลยุทธ์การหมุนเวียนในเครื่องมือเหล่านี้ ดูที่ การใช้พร็อกซีกับ Playwright & Puppeteer — บทความนี้พูดถึงเรื่องการส่งข้อมูลรับรองให้ผ่านล้วน ๆ)
ไคลเอนต์ HTTP แบบ command-line จะแยกข้อมูลรับรองออกจาก proxy URL และตอบ 407 Proxy Authentication Required ของพร็อกซีด้วยเฮดเดอร์ Proxy-Authorization ให้โดยอัตโนมัติ แต่ Chromium ไม่ทำแบบนั้น: --proxy-server รับเฉพาะ scheme://host:port เท่านั้น และเมื่อ 407 ตอบกลับมา มันจะแสดงกล่องโต้ตอบแบบโต้ตอบ ส่วนในโหมด headless ไม่มีแม้แต่กล่องโต้ตอบ — คำขอจะล้มเหลวไปเฉย ๆ
ดังนั้นคำถามจึงไม่เคยเป็น "ฉันจะใส่รหัสผ่านลงใน URL อย่างไร" — แต่เป็น "เลเยอร์ไหนจะตอบ 407 ให้ฉัน" มีคำตอบที่ใช้ได้สี่ข้อ เรียงจากดีที่สุดก่อน
Playwright แก้ปัญหานี้ได้อย่างถูกต้อง: มันตอบ challenge การยืนยันตัวตนของพร็อกซีเองผ่าน CDP ข้อมูลรับรองจะถูกใส่ไว้ใน launch หรือ context options:
# Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://us.jibaoproxy.com:913",
"username": "USERNAME-session-job1",
"password": "PASSWORD",
}
)
// Node.js - and per-context, which is where it gets powerful:
const browser = await chromium.launch({
proxy: { server: 'per-context' } // declare intent at launch
});
const ctx = await browser.newContext({
proxy: {
server: 'http://us.jibaoproxy.com:913',
username: 'USERNAME-session-job2',
password: 'PASSWORD',
}
});
พร็อกซีแบบ per-context หมายความว่ากระบวนการเบราว์เซอร์เดียวสามารถรัน N contexts บน N sticky sessions ที่ต่างกันได้ — เป็นรากฐานของทุกการตั้งค่า scraping ด้วย Playwright ที่จริงจัง ถ้าคุณใช้ Playwright อยู่ ก็จบแล้ว ข้ามไปยังส่วนการตรวจสอบได้เลย ทุกอย่างด้านล่างนี้มีอยู่เพราะ Selenium ไม่มีสิ่งที่เทียบเท่ากัน
selenium-wire ห่อ Selenium ด้วยพร็อกซี MITM ในเครื่องที่จัดการการยืนยันตัวตนปลายทาง:
from seleniumwire import webdriver # pip install selenium-wire
options = {
"proxy": {
"http": "http://USERNAME:[email protected]:913",
"https": "https://USERNAME:[email protected]:913",
}
}
driver = webdriver.Chrome(seleniumwire_options=options)
driver.get("https://example.com")
ข้อควรระวังที่คุณควรรู้ก่อนนำไปใช้งานจริง:
วิธีคลาสสิก: ส่วนขยายเล็ก ๆ ที่สร้างขึ้นเองซึ่งตั้งค่าพร็อกซีและตอบการยืนยันตัวตนผ่าน chrome.webRequest.onAuthRequired ไม่มี MITM ไม่มีกระบวนการเพิ่ม ใช้งานได้ใน Selenium ธรรมดา:
import zipfile, json
HOST, PORT = "us.jibaoproxy.com", 913
USER, PASS = "USERNAME-session-sel1", "PASSWORD"
manifest = {
"version": "1.0.0", "manifest_version": 2, "name": "Proxy Auth",
"permissions": ["proxy", "webRequest", "webRequestBlocking", ""],
"background": {"scripts": ["background.js"]},
}
background = f"""
chrome.proxy.settings.set({{value: {{mode: "fixed_servers", rules: {{
singleProxy: {{scheme: "http", host: "{HOST}", port: {PORT}}}
}}}}, scope: "regular"}}, () => {{}});
chrome.webRequest.onAuthRequired.addListener(
() => ({{authCredentials: {{username: "{USER}", password: "{PASS}"}}}}),
{{urls: [""]}}, ["blocking"]
);
"""
with zipfile.ZipFile("proxy_auth.zip", "w") as zp:
zp.writestr("manifest.json", json.dumps(manifest))
zp.writestr("background.js", background)
from selenium import webdriver
opts = webdriver.ChromeOptions()
opts.add_extension("proxy_auth.zip")
driver = webdriver.Chrome(options=opts)
มีจุดสะดุดสองอย่าง: ส่วนขยายจะไม่โหลดในโหมด headless แบบคลาสสิก — ใช้ --headless=new (Chrome 109+) หรือรันแบบ headed; และสคริปต์เบื้องหลังของ Manifest V2 ยังคงใช้งานได้สำหรับส่วนขยายอัตโนมัติที่ sideload เข้ามา แต่ให้จับตาดูไทม์ไลน์การเลิกใช้ MV2 ของ Chrome — ตัวเทียบเท่าแบบ MV3 ต้องใช้ service worker และ listener onAuthRequired เดียวกัน
รันพร็อกซีในเครื่องเล็ก ๆ ที่เก็บข้อมูลรับรองไว้; แล้วชี้เบราว์เซอร์ไปที่ localhost โดยไม่ต้องยืนยันตัวตนเลย ใช้งานได้กับทุกเบราว์เซอร์ ทุกไดรเวอร์ ทุกภาษา ทั้ง headless และไม่ headless:
# Using pproxy (pip install pproxy) - terminal 1:
pproxy -l http://127.0.0.1:8899 \
-r "http://USERNAME:[email protected]:913"
# Your script - terminal 2: plain Selenium, no auth needed
opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://127.0.0.1:8899")
driver = webdriver.Chrome(options=opts)
นี่ยังเป็นคำตอบที่สะอาดที่สุดสำหรับ Firefox/geckodriver (ซึ่งทริคส่วนขยายใช้ไม่ได้) และสำหรับสภาพแวดล้อมแปลก ๆ อย่างการทดสอบแอป Electron ค่าใช้จ่าย: มีชิ้นส่วนที่ต้องดูแลเพิ่มอีกหนึ่งตัว และการกำหนดเส้นทางแบบ per-context ต้องใช้ forwarder หนึ่งพอร์ตต่อหนึ่ง session
| วิธีการ | ใช้งานได้ใน | Headless | Session แบบ per-context | คำตัดสินสำหรับการใช้งานจริง |
|---|---|---|---|---|
| Playwright native | Playwright | ได้ | ได้ | ตัวเลือกเริ่มต้น |
| selenium-wire | Selenium (Py) | ได้ | ต่อไดรเวอร์ | ใช้ได้ดีในระดับปานกลาง |
| Auth extension | Selenium (ทุกภาษา) | --headless=new เท่านั้น | ต่อไดรเวอร์ | แน่น จับตาดู MV3 |
| Local forwarder | ทุกอย่าง | ได้ | หนึ่งพอร์ตต่อ session | ตัวสำรองสากล |
การ fallback กลับไปยัง IP จริงของคุณอย่างเงียบ ๆ คือโหมดความล้มเหลวที่ทำให้บัญชีถูกแบน ตรวจสอบ exit IP ที่จุดเริ่มต้นของทุกการรัน:
ip = driver.execute_script(
"return fetch('https://api.ipify.org').then(r => r.text())"
) if hasattr(driver, 'execute_script') else page.evaluate(
"fetch('https://api.ipify.org').then(r => r.text())"
)
assert ip != MY_REAL_IP, "Proxy not applied - aborting before we leak"
--proxy-server; Chrome ตัดมันทิ้ง ใช้หนึ่งในสี่วิธีERR_PROXY_CONNECTION_FAILED — host/port ผิดหรือโปรโตคอลไม่ตรงกัน ทดสอบบรรทัดเดียวกันด้วย curl -x ก่อน; ถ้า curl ใช้ได้ ปัญหาคือการเชื่อมต่อในเบราว์เซอร์ของคุณ--headless=newเบราว์เซอร์ไม่อ่าน proxy URL แบบ user:pass@ — ต้องมีบางอย่างคอยตอบ 407 ให้พวกมัน ใน Playwright สิ่งนั้นมีอยู่ในตัว; ใน Selenium มันคือ selenium-wire, ส่วนขยายยืนยันตัวตนที่สร้างขึ้น หรือ forwarder ในเครื่อง เลือกตาม stack ของคุณจากตารางเปรียบเทียบ แล้ว assert exit IP ในทุกการรัน เพื่อให้ความล้มเหลวของการยืนยันตัวตนแบบเงียบ ๆ ไม่มีวันรั่วที่อยู่จริงของคุณกลางการ crawl
500MB ทราฟฟิกฟรี — หนึ่งเกตเวย์ ทั้ง sticky หรือ rotating ทั้ง HTTP และ SOCKS5
เริ่มทดลองใช้ฟรีผู้ใช้ใหม่รับ 500MB เมื่อสมัครสมาชิก พร้อมโบนัสในการเติมเงินครั้งแรก ข้อเสนอมีระยะเวลาจำกัด