Chuyển đến nội dung

Playwright & Puppeteer

Về bản chất Clearcote chỉ là Chromium, nên nó dùng được như một trình duyệt thay thế trực tiếp (drop-in) cho các công cụ tự động hóa bạn đang dùng.

Gói clearcote (npm, PyPI và NuGet) biến các tùy chọn danh tính thành tham số có tên và trả về các đối tượng Playwright bình thường. Ở lần dùng đầu tiên, nó tải trình duyệt về và xác minh SHA-256 — bản build mở nếu không có khóa giấy phép, bản build có giấy phép mới nhất nếu có (xem Cài đặt) — rồi áp dụng các giá trị mặc định được mô tả ở phần dưới.

# pip install clearcote
from clearcote import launch

browser = launch(fingerprint="seed-123", platform="windows", brand="Chrome")
page = browser.new_page()
page.goto("https://example.com")
browser.close()

SDK hiện tại: 0.45.0. Từ 0.23, launch() trong Python và Node chạy trên một thư mục profile thật, dùng một lần (bị xóa khi đóng) thay vì chế độ incognito, nhờ vậy những gì phụ thuộc vào profile khớp với một Chrome thật và widevine: true có thể nạp module DRM. Hàm trả về một handle hoạt động như browser: newPage() vẫn dùng như thường, nhưng newContext() trả về chính context của profile đó chứ không tạo context tách biệt. Nếu cần các cookie jar riêng, hãy khởi chạy các browser riêng; truyền ephemeralProfile: false / ephemeral_profile=False để dùng Browser incognito như trước, hoặc userDataDir / user_data_dir để giữ lại profile.

API async (clearcote.async_api) nhận cùng các tùy chọn persona và proxy bên trong một vòng lặp asyncio và trả về các đối tượng async của Playwright; launch() của nó chạy incognito, nên hãy dùng launch_persistent_context() khi cần profile (và khi cần widevine=True). SDK .NET hỗ trợ LaunchEphemeralProfileAsync (khuyến nghị — LaunchAsync của .NET chạy incognito và không căn được cửa sổ khi chạy headless), LaunchPersistentContextAsync, ServeAsync, tải xuống có xác minh, cấp phép, Geoip và thao tác nhập liệu giống người (gọi tường minh HumanClickAsync / HumanTypeAsync / HumanSelectOptionAsync thay vì bật bằng flag khi khởi chạy). Profile đã lưu, profile: "auto", kiểm tra render-coherence, Widevine và các helper cho agent hiện chỉ có trên Python & Node. Các quy trình đầy đủ để copy-paste có ở Ví dụ.

Puppeteer và các client CDP khác (serve)

SDK không có launcher cho Puppeteer. Thay vào đó, serve() khởi động Clearcote với các thiết lập khởi chạy của SDK (persona, proxy, giá trị mặc định) cùng một endpoint CDP trên loopback, và bất kỳ client CDP nào cũng kết nối vào được — Puppeteer, connectOverCDP của Playwright, browser-use, Crawl4AI, Stagehand. Cách này dùng được với bản build có giấy phép, và không có gì thêm --enable-automation vào. humanize nằm ở phía Playwright, nên không áp dụng cho client kết nối theo cách này.

import { serve } from "clearcote";
import puppeteer from "puppeteer-core";

const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
const browser = await puppeteer.connect({ browserURL: srv.cdpUrl, defaultViewport: null });
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.disconnect();
await srv.close();

Khi chạy headless, serve() cấp cho trình duyệt một màn hình có kích thước thật và căn cửa sổ vừa với vùng làm việc trước khi bất kỳ client nào kết nối (0.31+); truyền windowSize / window_size nếu muốn cửa sổ nhỏ hơn. Từ shell, clearcote serve làm điều tương tự dưới dạng một dịch vụ chạy thường trực — và có thể cấp cho mỗi kết nối một trình duyệt riêng, với danh tính, proxy, múi giờ và ngôn ngữ lấy từ URL kết nối. Xem Triển khai.

Điều khiển binary trực tiếp (bản build mở)

Bạn cũng có thể trỏ launcher của mình vào bản build mở bằng executablePath (Node) hoặc executable_path (Python) và truyền các tùy chọn danh tính qua args. Bản build có giấy phép không khởi động theo cách này — nó cần token giấy phép mà SDK lấy về, vì vậy hãy dùng launch() hoặc serve() ở trên. Hãy bỏ --enable-automation như SDK vẫn làm (Puppeteer và các phiên bản Playwright cũ thêm flag này; nó chuyển Chromium sang chế độ automation). Theo cách này, không giá trị mặc định nào của SDK (ngôn ngữ, chính sách WebRTC, kích thước và vị trí cửa sổ) được áp dụng.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        executable_path=r"C:\clearcote\chrome.exe",
        headless=False,
        ignore_default_args=["--enable-automation"],
        args=[
            "--fingerprint=seed-123",
            "--fingerprint-platform=windows",
            "--timezone=America/New_York",
        ],
    )
    page = browser.new_page()
    page.goto("https://abrahamjuliot.github.io/creepjs/")
    browser.close()

Xác định hoặc tải trước binary đã xác minh

SDK xác định trình duyệt theo thứ tự sau: executablePath / executable_path được chỉ định tường minh, sau đó là CLEARCOTE_BINARY, rồi đến version bạn yêu cầu (hoặc CLEARCOTE_BROWSER_VERSION), tiếp theo là bản build có giấy phép nếu tìm thấy khóa giấy phép (tùy chọn licenseKey, CLEARCOTE_LICENSE_KEY, hoặc ~/.clearcote/license.key), và cuối cùng là bản build mở được cố định trong phiên bản SDK này. Đường dẫn do bạn cung cấp sẽ được kiểm tra xem có tệp nào bị thiếu hoặc bị cắt cụt không trước khi khởi chạy. Hãy gọi download / executable_path khi bạn muốn làm nóng cache mà không khởi chạy, dùng thư mục cache tùy chỉnh, hoặc chủ động chọn bản build mở mới nhất trên GitHub lúc runtime.

from clearcote import download, launch

chrome = download(cache_dir=r"C:\clearcote-cache", auto_update=True)
browser = launch(executable_path=chrome, fingerprint="seed-123")

Chế độ cố định (pinned) xác minh theo các giá trị SHA-256 được nhúng sẵn trong SDK. autoUpdate / auto_update phải bật chủ động (opt-in) và sẽ xác minh manifest checksum của bản phát hành; khi có gpg, nó còn đối chiếu manifest đã ký với fingerprint của khóa ký Clearcote đã được cố định. Tùy chọn này chỉ áp dụng cho bản build mở: khi có khóa giấy phép, download() sẽ tải bản build có giấy phép hiện hành (chọn bản cụ thể bằng version hoặc releaseChannel — xem chọn bản build). Trong .NET, DownloadAsync chỉ tải bản build mở; để tải trước bản build có giấy phép, hãy dùng ExecutablePathAsync(new LaunchOptions { LicenseKey = … }).

Nhất quán theo mặc định (không cần flag bổ sung)

Dù bạn khởi chạy với tùy chọn nào, engine vẫn giữ các bề mặt thứ cấp khớp với persona bạn chọn — với persona Windows là khớp với những gì một máy desktop chạy Chrome trên Windows thật báo cáo. Nền tảng của persona mặc định theo hệ điều hành máy host, nên trên host Linux, các bề mặt này sẽ theo persona Linux trừ khi bạn truyền platform. Các giới hạn WebGL getParameter (WebGL1 + WebGL2) báo cáo giá trị của persona, nhưng bị giới hạn ở mức GPU của máy này thực sự đáp ứng được, còn UNMASKED_RENDERER / UNMASKED_VENDOR cố định trong suốt phiên (cùng một GPU trên mọi trang, theo persona). Với persona Windows, navigator.getBattery() báo cáo một máy desktop cắm điện lưới, navigator.connection báo cáo một kết nối mạng dân dụng, và AudioContext báo cáo sample rate và độ trễ Windows-WASAPI tương ứng. getScreenDetails() báo cáo một màn hình duy nhất, còn @media (pointer: fine) / (hover: hover) khớp với một máy desktop dùng chuột.

Đã kiểm tra trên 153 r26, chạy headed trên Windows (tháng 9/2026): BrowserScan báo không có bot và CreepJS hiển thị 0% stealth. Khi dùng proxy, hãy thêm geoip để múi giờ và WebRTC khớp với điểm thoát (exit).

Giá trị mặc định nhất quán (có thể ghi đè)

SDK áp dụng sẵn một vài giá trị mặc định chuẩn stealth để những dấu hiệu lộ dễ thấy không bị lọt ra:

  • Khởi chạy headed mặc định không giả lập viewport (viewport: null / no_viewport=True) để window.innerWidth bám theo cửa sổ thật của hệ điều hành — một viewport giả lập 1280×720 nằm trên một cửa sổ thật là dấu hiệu lộ kiểu “cửa sổ bất khả thi”. Truyền viewport tường minh để ghi đè. Trên máy chủ Linux không có trình quản lý cửa sổ (Xvfb, container của riêng bạn), nơi --start-maximized không có tác dụng, cửa sổ headed được chỉnh vừa với vùng làm việc của màn hình trước khi mở trang đầu tiên, giống một cửa sổ desktop đã phóng to tối đa (SDK 0.42.0).
  • Khởi chạy headless có một màn hình thực tế và một cửa sổ được chỉnh vừa với màn hình đó trước khi mở trang đầu tiên: màn hình của persona, hoặc, khi không có persona, một kích thước desktop thật. Từ SDK 0.42.0, điều này đúng trên mọi nền tảng kể cả khi persona không có hiệu lực, nên trang không bao giờ thấy bề mặt headless 800×600 nguyên bản của engine. Tự đặt tùy chọn viewport hoặc screen sẽ tắt cơ chế này, còn khi truyền --screen-info của riêng bạn thì bạn tự đặt màn hình. --window-size, --window-position hoặc --start-maximized của riêng bạn giữ nguyên màn hình và chỉ bỏ qua bước chỉnh vừa; trong serve(), chỉ riêng --window-position cũng giữ nguyên màn hình, và chỉ một switch kích thước hoặc --screen-info mới để bạn tự quyết hoàn toàn kích thước và vị trí cửa sổ.
  • Một bề mặt WebGL duy nhất trên Linux: trên host Linux, WebGL của persona Linux được render qua Mesa trên EGL ở cả headless lẫn headed (SDK 0.42.0; host cần có libegl1), nên trang thấy cùng một chuỗi renderer, danh sách extension và bộ giới hạn ở cả hai chế độ, theo dạng OpenGL ES mà phần lớn máy Linux thật báo cáo. Khi không có EGL, khởi chạy headed dùng desktop GL của Mesa, còn persona Windows được render qua SwiftShader. --use-angle hoặc --use-gl do chính bạn đặt trong args sẽ được ưu tiên, và khởi chạy headless vẫn nhận --ignore-gpu-blocklist đi kèm, để WebGL tiếp tục hoạt động.
  • Sáng hay tối là do persona quyết định trên bản build có giấy phép từ 154 r32: các context mà SDK tạo ra để tắt chế độ giả lập color scheme của Playwright (SDK 0.41.0+), vốn nếu không thì sẽ ép dùng nền sáng. Truyền colorScheme / color_scheme nếu vẫn muốn giả lập một chế độ.
  • Persona không xuất hiện trên dòng lệnh trên bản build có giấy phép từ 154 r32: seed, các giá trị ghi đè persona và thông tin đăng nhập proxy đến trình duyệt qua biến môi trường của nó, chứ không qua mục của nó trong danh sách tiến trình (SDK 0.41.0+; đặt personaEnv: false để giữ dòng lệnh). Xem Tùy chọn khởi chạy.
  • WebRTC mặc định dùng disable_non_proxied_udp, nên không có UDP nào đi ra ngoài proxy và địa chỉ thật của máy bạn được giữ kín. Chỉ có --webrtc-ip-handling-policy do chính bạn đặt trong args mới ghi đè được — và, trên bản build mở, cả webrtcIp / geoip, vốn cho phép UDP của WebRTC lại đi ra qua kết nối của chính bạn (bản build có giấy phép luôn chặn UDP của WebRTC bất kể thế nào). Với chính sách đó và không có webrtcIp, trang sẽ không nhận được ICE candidate nào — khi dùng proxy, hãy truyền geoip (hoặc webrtcIp) để WebRTC báo cáo địa chỉ của proxy, hoặc socks5Udp để truyền UDP thật qua proxy SOCKS5.
  • Khi dùng proxy, QUIC / HTTP-3 bị tắt, giống như một Chrome thật đứng sau proxy — nên không có kết nối UDP nào được thử đi vòng ngoài proxy.
  • Persona có nền tảng mặc định theo hệ điều hành máy host và brand mặc định là Google Chrome. Nếu không có timezone và không có geoip, múi giờ sẽ theo ngôn ngữ (en-US → New York).
  • Thông tin xác thực proxy được giao cho trình duyệt, không phải cho Playwright, ở những chỗ engine hỗ trợ: SOCKS5 thì luôn luôn (Playwright hoàn toàn không xác thực được SOCKS5), HTTP(S) từ 151 r19+ để cache của trang vẫn được bật (Python & Node). Xem bên dưới.
  • humanize chạy một bước kiểm tra trước khả năng thao tác (actionability pre-flight) trước mỗi cú click trusted (hiển thị / được bật / ổn định + kiểm tra phần tử có bị che hay không bằng elementFromPoint) và chuyển về click native nếu không đạt, nên một cú click trusted không bao giờ được phát ra khi đang bị lớp phủ che hoặc giữa lúc animation đang chạy.
Mẹo: suy ra seed từ id tài khoản/tenant của chính bạn để mỗi danh tính đều tái lập được — cùng seed, cùng fingerprint trình duyệt, lần nào cũng vậy. Xem danh sách switch đầy đủ ở Các flag fingerprint.