ADSSPEED

Hướng dẫn

API cục bộ điều khiển hồ sơ trình duyệt: ví dụ Selenium, Puppeteer và Playwright

Tác giả ADSSPEED Team · Đăng · Cập nhật · 7 phút đọc

API cục bộ hoạt động thế nào?

API cục bộ là một dịch vụ web nhỏ chạy ngay trên máy tính của bạn, cùng với ứng dụng ADSSPEED. Bạn gọi nó từ một đoạn mã để mở và đóng hồ sơ, và nó trả về các cổng để công cụ tự động hoá của bạn gắn vào trình duyệt của hồ sơ.

Vì công cụ gắn vào chính trình duyệt của hồ sơ, mã của bạn chạy bên trong hồ sơ đó: cookie, đăng nhập, proxy và thiết lập thiết bị của hồ sơ.

Trước khi bắt đầu

  1. Mở ADSSPEED và đăng nhập. API chạy cùng app, nên tắt app là API cũng tắt.
  2. Ở bản 2.9.220, API mặc định tắt. Vào Cài đặt → API & Tích hợp và bật API cục bộ. Các bản mới tự bật khi mở app.
  3. Trên cùng trang đó, xem cổng (mặc định 19555) và chép khoá API. Bấm "đổi khoá" thì mọi mã đang dùng khoá cũ sẽ ngừng chạy.
  4. Kiểm tra API có trả lời không. Lệnh này không cần khoá:
import requests
print(requests.get("http://127.0.0.1:19555/status").json())

Kết quả khoẻ mạnh trông như {"code": 0, "data": {"version": "...", "ready": true, "api": "v1"}, "msg": "success"}. Trường version cho bạn biết nên đọc tài liệu của bản nào.

Mở một hồ sơ trong năm dòng

import requests
KEY = "API_KEY"
r = requests.get("http://127.0.0.1:19555/api/v1/browser/start",
                 params={"profile_id": 1}, headers={"X-API-Key": KEY}, timeout=120).json()
print(r["data"]["ws"])   # các địa chỉ để công cụ của bạn gắn vào

profile_id là số thứ tự của hồ sơ trong app (1, 2, 3…). Kết quả trả về có data.ws.selenium và data.ws.puppeteer, được dùng ở các phần sau.

Gắn Selenium (Python)

import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

BASE, KEY = "http://127.0.0.1:19555", "API_KEY"
r = requests.get(f"{BASE}/api/v1/browser/start", params={"profile_id": 1},
                 headers={"X-API-Key": KEY}, timeout=120).json()
if r["code"] != 0:
    raise SystemExit(r["msg"])

opts = Options()
opts.add_experimental_option("debuggerAddress", r["data"]["ws"]["selenium"])
driver = webdriver.Chrome(options=opts)   # gắn vào trình duyệt đang chạy
driver.get("https://ip.me/")
print(driver.title)

Selenium cần chromedriver cùng số phiên bản với trình duyệt của hồ sơ. Để xem số phiên bản, mở http://127.0.0.1:<debug_port>/json/version và đọc trường Browser. Cơ chế tự quản lý driver của Selenium có thể nhìn vào một Chrome cài sẵn trên máy tính của bạn, nên nếu hai số phiên bản không khớp, hãy tự chỉ đường dẫn driver bằng Service(executable_path=...) lấy từ selenium.webdriver.chrome.service.

Tuỳ chọn debuggerAddress nhận một địa chỉ dạng host:port, đúng là những gì data.ws.selenium chứa.

Gắn Puppeteer (Node.js)

// npm i puppeteer-core   ·   Node 18+, lưu thành tệp .mjs
import puppeteer from "puppeteer-core";

const BASE = "http://127.0.0.1:19555", KEY = "API_KEY";
const r = await (await fetch(`${BASE}/api/v1/browser/start?profile_id=1`,
                             { headers: { "X-API-Key": KEY } })).json();
if (r.code !== 0) throw new Error(r.msg);

// defaultViewport: null để giữ kích thước cửa sổ của hồ sơ
const browser = await puppeteer.connect({ browserWSEndpoint: r.data.ws.puppeteer, defaultViewport: null });
const [page] = await browser.pages();
await page.goto("https://ip.me/");
console.log(await page.title());
browser.disconnect();   // ngắt kết nối; KHÔNG đóng trình duyệt của hồ sơ

Gắn Playwright (Python)

# pip install playwright requests
import requests
from playwright.sync_api import sync_playwright

BASE, KEY = "http://127.0.0.1:19555", "API_KEY"
r = requests.get(f"{BASE}/api/v1/browser/start", params={"profile_id": 1},
                 headers={"X-API-Key": KEY}, timeout=120).json()

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(r["data"]["ws"]["puppeteer"])
    ctx = browser.contexts[0]                       # ngữ cảnh có sẵn của hồ sơ
    page = ctx.pages[0] if ctx.pages else ctx.new_page()
    page.goto("https://ip.me/")
    print(page.title())

Luôn dùng ngữ cảnh và tab có sẵn của hồ sơ. Tạo cái mới là bắt đầu một phiên trắng không có cookie của hồ sơ, đó là lý do phổ biến nhất khiến mở ra trang trắng và mất đăng nhập. Tài liệu của Playwright cũng ghi chú rằng kết nối qua CDP chỉ hỗ trợ trình duyệt nền Chromium và có độ trung thực thấp hơn kết nối bằng giao thức riêng của nó.

Đóng hồ sơ

Khi mã chạy xong, hãy ngắt công cụ (driver.quit() kết thúc phiên Selenium, browser.disconnect() ngắt Puppeteer), rồi đóng chính hồ sơ:

requests.get(f"{BASE}/api/v1/browser/stop", params={"profile_id": 1}, headers={"X-API-Key": KEY})

Xác thực và định dạng kết quả

Mọi lệnh trừ /status đều cần khoá. Gửi khoá trong header (khuyên dùng) hoặc làm tham số:

X-API-Key: ads-1a2b3c4d
/api/v1/profile/list?key=ads-1a2b3c4d

Mọi câu trả lời có cùng một khuôn, {code, data, msg}. Hãy kiểm code trước khi đọc data.

codeHTTPÝ nghĩa
0200Thành công
-1200Lỗi nghiệp vụ; msg nói rõ lý do (ví dụ proxy không hợp lệ hoặc không tìm thấy hồ sơ)
401401Thiếu hoặc sai khoá
404404Không có đường dẫn này, hoặc bản app của bạn chưa có lệnh đó
429200Một lệnh nặng bị gọi nhiều hơn một lần mỗi giây

Các bản mới còn trả 403 khi app chưa đăng nhập.

Mở nhiều hồ sơ an toàn

Mở hồ sơ là lệnh nặng: tối đa một lần mỗi giây, nếu không bạn nhận 429. Lần mở đầu có proxy có thể mất vài giây, nên hãy đặt thời gian chờ rộng rãi (tài liệu khuyên ít nhất 90 giây). Khi các hồ sơ đã mở, bạn có thể điều khiển chúng song song, mỗi hồ sơ một driver hoặc một kết nối trình duyệt. Bọc mỗi hồ sơ trong try/finally để nó luôn được đóng:

import time, requests
BASE, KEY = "http://127.0.0.1:19555", "API_KEY"
H = {"X-API-Key": KEY}

def call(path, **params):
    r = requests.get(f"{BASE}{path}", params=params, headers=H, timeout=120).json()
    if r["code"] != 0:
        raise RuntimeError(f'{path}: {r["code"]} {r["msg"]}')
    return r["data"]

for pid in (1, 2, 3):
    data = call("/api/v1/browser/start", profile_id=pid)
    try:
        ...   # gắn công cụ vào data["ws"]["selenium"] hoặc data["ws"]["puppeteer"], làm việc
    finally:
        call("/api/v1/browser/stop", profile_id=pid)
    time.sleep(1.1)    # lệnh nặng: tối đa một lần mỗi giây

Các sự cố thường gặp

Vấn đềNên thử
"Từ chối kết nối" (connection refused)API đang tắt, app chưa mở, hoặc cổng bị chương trình khác giữ. Bật API ở Cài đặt → API & Tích hợp, hoặc đổi cổng và cập nhật mã của bạn.
401Thiếu hoặc sai khoá. Chép lại khoá ở cùng trang cài đặt; sau khi "đổi khoá", hãy cập nhật các đoạn mã.
404 ở một lệnhBản app của bạn chưa có lệnh đó. Kiểm GET /status, đọc tài liệu của đúng bản, hoặc cập nhật app.
429 khi mở hồ sơChờ một giây giữa hai lần mở.
"This version of ChromeDriver only supports…"Dùng chromedriver cùng số phiên bản với trình duyệt của hồ sơ (xem /json/version).
Trang trắng, mất đăng nhập (Puppeteer hoặc Playwright)Bạn đã tạo ngữ cảnh mới. Dùng browser.contexts[0] hoặc browser.pages(), kèm defaultViewport: null trong Puppeteer.
Lỗi Node ECONNREFUSED ::1Hãy dùng 127.0.0.1 thay vì localhost; các bản Node mới có thể đổi localhost thành địa chỉ IPv6 ::1.
Xoá nhầm hồ sơHồ sơ bị xoá nằm trong thùng rác và khôi phục được trong app. Xoá vĩnh viễn thì không lấy lại được.

API làm được và không làm được gì

  • Nó làm đúng những gì app cho phép với gói của bạn, không hơn. Hồ sơ tạo qua API tính vào gói như mọi hồ sơ khác.
  • Bí mật luôn được giấu. Mật khẩu proxy luôn trả về là ***.
  • Vân tay do app dựng cho từng hồ sơ, nên API không chỉnh sửa chúng. Muốn một thiết lập riêng, hãy tạo cấu hình mẫu trong app rồi chọn khi tạo hồ sơ.
  • Hồ sơ điện thoại chưa có trong API. API hiện bao phủ các hồ sơ trình duyệt.

Ở bản 2.9.220, API có 27 lệnh trong sáu nhóm: điều khiển hồ sơ, thông tin hồ sơ, thao tác hồ sơ, proxy (gồm cả proxy di động tự dựng từ USB modem), tiện ích, và hệ thống. Các bản mới thêm kịch bản, chiến dịch, lịch chạy, cookie và nhiều hơn nữa. Danh sách đầy đủ, kèm bộ Postman, nằm trong tài liệu API.

Giữ kín khoá

API chỉ nghe ở 127.0.0.1, nên các máy khác trong mạng của bạn không gọi tới được. Nhưng các chương trình khác trên máy của bạn, kể cả trang web đang mở trong trình duyệt, vẫn gọi được nếu biết khoá. Đừng dán khoá lên dịch vụ bên ngoài, bot hay kho mã công khai, và hãy bấm "đổi khoá" ngay khi nghi bị lộ.

Câu hỏi thường gặp

Làm sao nối Selenium vào một hồ sơ trình duyệt đang chạy?

Mở hồ sơ qua API, lấy địa chỉ Selenium trong kết quả trả về (data.ws.selenium), rồi đưa vào tuỳ chọn Chrome dưới dạng debuggerAddress. Selenium sẽ gắn vào trình duyệt đang chạy thay vì bật một trình duyệt mới. Bạn cần chromedriver cùng số phiên bản với trình duyệt của hồ sơ.

Làm sao nối Puppeteer hoặc Playwright?

Dùng địa chỉ WebSocket trong kết quả trả về (data.ws.puppeteer). Puppeteer nối bằng browserWSEndpoint, còn Playwright bằng connect_over_cdp. Cả hai đều không cần driver riêng.

Vì sao mã của tôi mở ra trang trắng và mất đăng nhập?

Vì nó đã tạo một ngữ cảnh trình duyệt (context) mới. Hãy dùng ngữ cảnh và tab có sẵn của hồ sơ: browser.contexts[0] trong Playwright, hoặc browser.pages() trong Puppeteer. Ngữ cảnh mới là một phiên trắng, không có cookie của hồ sơ.

Tôi nên đọc tài liệu của bản nào?

Kiểm số bản của app bằng GET /status; trường data.version không cần khoá. Các lệnh khác nhau giữa các bản, nên hãy đọc tài liệu của đúng bản bạn đang chạy. Bài này nói về 2.9.220, và các bản mới có thêm nhiều lệnh.

Để API bật liên tục có an toàn không?

API chỉ nghe ở 127.0.0.1 nên các máy khác trong mạng của bạn không gọi tới được. Nhưng các chương trình khác trên chính máy của bạn vẫn gọi được nếu biết khoá, nên hãy giữ kín khoá và đổi khoá nếu nghi bị lộ.

Hồ sơ tạo qua API có tính vào gói của tôi không?

Có. Hồ sơ tạo qua API cũng là hồ sơ của gói, giống hệt hồ sơ tạo trong app.

Nguồn tham khảo

  1. Tài liệu API ADSSPEED (Bắt đầu nhanh, xác thực, mã lỗi, hỏi đáp)
  2. Chrome for Developers: ChromeDriver capabilities (tiếng Anh; debuggerAddress)
  3. Puppeteer: ConnectOptions (tiếng Anh; browserWSEndpoint, defaultViewport)
  4. Playwright: BrowserType (tiếng Anh; connectOverCDP)

Bài liên quan

Chạy máy Android và hồ sơ trình duyệt ngay trên PC của bạn

ADSSPEED quản lý nhiều hồ sơ trình duyệt và hồ sơ điện thoại Android trong một ứng dụng, mỗi hồ sơ có cấu hình máy, proxy và tự động hoá riêng.