Scraper luôn bị 403? Phá vỡ lớp ngụy trang đơn lẻ, xây dựng môi trường đa tầng
Kịch bản quen thuộc với bất kỳ ai làm web scraping: script crawl của bạn chạy ổn trong vài phút, đột nhiên bắt đầu trả về 403, rồi CAPTCHA, rồi IP bị chặn hẳn. Bạn thêm proxy vào, đổi user-agent cho mỗi request, đổi session cookie, nhưng tỷ lệ bị chặn vẫn không giảm. Gần như chắc chắn là bạn đang che từng lớp riêng lẻ, trong khi phía website nhận diện bot bằng cách tổng hợp nhiều tín hiệu cùng lúc.
Bài viết này đi qua ba kênh phát hiện chính mà các website dùng để phân biệt bot với người dùng thật, giới hạn của những biện pháp chống phát hiện thông thường, rồi cách tiếp cận bằng trình duyệt chống phát hiện và cấu hình thực tế kèm code.
Website phát hiện bot qua những kênh nào
1. IP và tần suất request
Đây là kênh cũ và hiệu quả nhất. Ba tín hiệu thường bị bỏ qua:
- Loại IP. Dải ASN của các nhà cung cấp cloud (AWS, GCP, Azure, DigitalOcean, Vultr) đều nằm trong danh sách đen công khai. Proxy residential thì khác, nhưng nếu dùng proxy pool dùng chung, IP đó có thể đã bị đánh dấu bởi hàng trăm scraper khác trước khi bạn bắt đầu.
- Tần suất. Năm mươi request trong mười giây từ một IP là tín hiệu không thể giải thích bằng hành vi người dùng.
- Nhất quán địa lý. IP ở Mỹ nhưng timezone là Asia/Ho_Chi_Minh, ngôn ngữ trình duyệt là vi-VN. Từng thông số riêng lẻ thì vô hại, nhưng khi nằm chung một session thì đó là mâu thuẫn rõ ràng.
2. Đặc điểm tầng mạng và tầng môi trường (Fingerprint)
Khi request đi qua proxy, TLS handshake vẫn để lộ danh tính. Cần phân biệt rõ hai tầng:
- TLS fingerprint (JA3/JA4) – tầng truyền tải mạng. Thư viện requests của Python hay fetch của Node bắt tay TLS với bộ cipher suite và thứ tự extension khác Chrome thật. Đây là đặc điểm của thư viện mạng, không phải của trình duyệt. Thay user-agent không đổi được fingerprint này.
- Header set. User-Agent khai báo Chrome 120 nhưng thiếu sec-ch-ua, thiếu Accept-Encoding, hoặc thứ tự header không giống Chrome gửi.
- Fingerprint trình duyệt – tầng môi trường. Canvas hash, WebGL renderer, audioContext, danh sách font, độ phân giải màn hình. Nếu chạy headless hoặc qua HTTP client thuần, các thông số này hoặc thiếu, hoặc giống hệt nhau giữa các request.
- WebRTC. Đây là cái bẫy kinh điển: proxy đổi IP nhưng WebRTC vẫn leak IP thật nếu không bị vô hiệu hoá.
3. Hành vi (Behavior)
- Nhịp request và thời gian chờ. Bot gửi request đều đặn như đồng hồ bấm giờ; người dùng có pause ngẫu nhiên, có thời gian đọc (dwell time).
- Vi tương tác (Micro-interactions). Các hệ thống hiện đại không chỉ xem có click hay không, mà còn xem quỹ đạo chuột (mouse trajectory), tốc độ cuộn trang (scroll velocity) và các điểm dừng không đồng đều. Bot thường cuộn theo bước cố định hoặc nhảy thẳng đến phần tử.
- Đường đi và Session. Vào thẳng URL sâu, không có referrer chain, không có lịch sử điều hướng. Session quá sạch, không có cookie tích lũy từ các bước trước.
- Thời điểm. Hàng trăm request liên tục lúc ba giờ sáng theo múi giờ địa phương.
Biện pháp thông thường và giới hạn của chúng
Xoay vòng user-agent
Chỉ đổi header UA là biện pháp phổ biến nhất và cũng yếu nhất. UA nói Chrome 120 nhưng TLS fingerprint vẫn là python-requests, header set vẫn thiếu sec-ch-ua. Phía server so khớp nhiều lớp, lớp nào lệch là bị đánh dấu.
Proxy rotation
- Đổi IP mỗi request. Không người dùng nào đổi IP nhanh đến vậy. Một session hợp lệ cần gắn với một IP trong suốt luồng điều hướng (sticky session).
- Proxy pool dùng chung. IP đã bị hàng trăm scraper khác dùng trước bạn.
- Xoay IP nhưng giữ nguyên fingerprint. Các request vẫn mang cùng canvas hash, cùng timezone, cùng bộ font. Đổi IP không xoá được mối liên kết ở tầng fingerprint.
Quản lý session và cookie
Cookie jar theo IP, storageState theo từng account: đúng hướng, nhưng chỉ giải quyết tầng trạng thái phiên. Fingerprint, timezone, ngôn ngữ, kích thước màn hình vẫn giống nhau giữa các lần chạy.
Hai phản ứng phổ biến khi bị chặn cũng làm tình hình tệ hơn: retry storm (tăng tần suất và xác nhận bạn là bot), và bỏ sleep để đuổi kịp tiến độ.
Tóm lại, mỗi biện pháp trên chỉ giải quyết một chiều. Cách chống phát hiện bền vững là giữ nhất quán đồng thời trên cả ba tầng: IP, fingerprint và hành vi phải khớp với nhau và khớp với câu chuyện của một người dùng thật.
Trình duyệt chống phát hiện trong web scraping
Ý tưởng: dùng một profile trình duyệt chống phát hiện làm đơn vị môi trường hoàn chỉnh. Mỗi profile mang:
- Cookie, storage, cache riêng.
- Fingerprint riêng trên hơn 30 thông số tùy chỉnh được.
- Proxy riêng gán sẵn trong profile.
Điểm then chốt là fingerprint sinh theo proxy: timezone và ngôn ngữ được suy ra từ IP của profile. Quan trọng hơn, vì sử dụng kernel Chromium thật, TLS fingerprint và header set cũng khớp với UA khai báo, giải quyết được vấn đề "UA Chrome nhưng TLS Python" ở tầng mạng.
Về vận hành: trạng thái đăng nhập và cookie nằm trong profile, tái sử dụng được qua nhiều lần chạy; Local API cho phép tạo, mở, đóng profile và cấu hình proxy từ code; Playwright hoặc Puppeteer kết nối qua CDP để điều khiển trang như một người dùng thật.
Một pattern phổ biến khi triển khai: mỗi website đích (hoặc mỗi luồng điều hướng) một profile, proxy gán cứng theo profile, thay vì xoay proxy và fingerprint theo từng request.
Cấu hình BitBrowser với proxy trong dự án thực tế
Mỗi phương án trên đều có đánh đổi riêng. Trong dự án thực tế của mình, mình dùng BitBrowser, cơ chế profile isolation của nó xử lý khá tốt phần nhất quán môi trường. Vài điểm đáng chú ý khi cấu hình cho scraping:
- Fingerprint sinh dựa trên proxy, nên geo, timezone và ngôn ngữ khớp với IP ra ngoài.
- Hơn 30 thông số fingerprint tùy chỉnh được.
- Nhiều loại proxy: HTTP, HTTPS, SOCKS5, SSH và kết nối trực tiếp.
- Local API để tạo, mở, đóng profile và cấu hình proxy từ script; batch update proxy cho nhiều profile cùng lúc.
- 10 profile miễn phí.
Tạo một profile gắn sẵn proxy residential:
// Tạo profile scrape với proxy residential await callApi('/browser/update', { name: 'scrape-job-01', browserFingerPrint: {}, // sinh fingerprint phù hợp với proxy proxyMethod: 2, // 2 = proxy tùy chỉnh proxyType: 'socks5', host: 'gw.residential-proxy.com', port: 1080, proxyUserName: 'user', proxyPassword: 'pass', });
Hai điểm về cấu hình proxy cần nhớ:
- proxyMethod: 3 dùng khi proxy pool có API trích IP: truyền dynamicIpUrl và dynamicIpChannel.
- Muốn đổi proxy cho nhiều profile đã tồn tại, dùng endpoint /browser/proxy/update với danh sách ids, tránh xoá và tạo lại profile (mất cookie).
Ví dụ: Playwright + BitBrowser thu thập dữ liệu
Vòng đời một job scrape: tạo hoặc tái sử dụng profile, mở, kết nối qua CDP, thu thập, đóng.
import { chromium } from 'playwright';
async function scrapeJob(profileId, url) { const opened = await callApi('/browser/open', { id: profileId, queue: true, // tránh hai job cùng mở một profile }); const browser = await chromium.connectOverCDP(opened.ws); const context = browser.contexts()[0]; const page = context.pages()[0] || (await context.newPage());
await page.goto(url, { waitUntil: 'domcontentloaded' }); console.log('Tiêu đề trang:', await page.title());
await browser.close(); // ngắt kết nối CDP await callApi('/browser/close', { id: profileId }); // đóng và dọn dẹp profile }
Ranh giới pháp lý và tuân thủ
Công cụ chỉ là phần cuối của bài toán; ranh giới pháp lý mới là thứ quyết định bạn có nên làm hay không:
- Robots.txt và điều khoản sử dụng. Tuân thủ robots.txt là chuẩn mực tối thiểu. Ở Việt Nam, Luật An ninh mạng 2018 là khung tham chiếu cơ bản khi nói đến truy cập hệ thống mạng trái phép.
- Tốc độ hợp lý. Giữ delay giữa các request, dùng exponential backoff khi retry.
- Không vượt qua kiểm soát truy cập. Đăng nhập trái phép, vượt paywall, bỏ qua CAPTCHA để lấy dữ liệu trả phí là vượt biên giới pháp lý rõ ràng.
- Dữ liệu cá nhân. Thu thập dữ liệu cá nhân cần cơ sở pháp lý. Bên cạnh Nghị định 13/2023/NĐ-CP, cần lưu ý Luật Bảo vệ dữ liệu cá nhân (có hiệu lực từ đầu năm 2026) quy định chặt chẽ hơn về xử lý PII, trong đó cấm mọi hình thức mua bán dữ liệu cá nhân. Ranh giới thực tế: thu thập dữ liệu công khai (giá cả, thông tin sản phẩm) khác với thu thập PII (email, số điện thoại, hành vi cá nhân).
- Use case hợp lệ: nghiên cứu thị trường, so sánh giá công khai, giám sát thương hiệu, kiểm thử hệ thống của chính bạn.
Kết luận
Phát hiện bot là bài toán đa tầng, nên chống phát hiện cũng phải đa tầng. Xoay user-agent, đổi proxy, quản lý session đều cần, nhưng chỉ có hiệu quả khi ba tầng IP, fingerprint và hành vi đi cùng nhau và kể một câu chuyện nhất quán. Trình duyệt chống phát hiện biến việc ghép các công cụ rời rạc thành một đơn vị môi trường có thể lập trình.
Lựa chọn kiến trúc công cụ (ví dụ: profile isolation so với xoay proxy theo từng request) quyết định liệu sự nhất quán về môi trường có khả thi về mặt kỹ thuật hay không. Và trên hết, ranh giới pháp lý quyết định năng lực đó nên được sử dụng ở đâu.
All rights reserved