Proxy hoạt động như thế nào trong Puppeteer?
Puppeteer xác định proxy qua các đối số truyền vào khi khởi chạy Chrome. Nhập địa chỉ vào --proxy-server sẽ khiến tất cả các trang trong trình duyệt đó sử dụng cùng một proxy. Tên người dùng và mật khẩu của HTTP proxy không thể được nhập qua đối số thực thi, vì vậy bạn cần truyền chúng qua page.authenticate sau khi mở trang. Điều này sẽ khiến Puppeteer tự động trả lời khi proxy yêu cầu xác thực.
Ví dụ sử dụng IP 198.51.100.23, cổng HTTP 8000, cổng SOCKS5 1080, username spx_user, password spx_pass.
npm install puppeteerLàm thế nào để kết nối HTTP proxy với xác thực?
Thêm --proxy-server=198.51.100.23:8000 vào args của launch và chuyển username và password vào page.authenticate ngay sau khi tạo trang bằng newPage. Xác thực cần được thực hiện cho mỗi trang, vì vậy hãy thêm cùng một lệnh gọi mỗi khi tạo trang mới.
Trang HTTPS vẫn mở bình thường. Trình duyệt tạo đường hầm CONNECT và giao tiếp mã hóa trong đó.
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({
headless: true,
args: ["--proxy-server=http://198.51.100.23:8000"],
});
const page = await browser.newPage();
await page.authenticate({ username: "spx_user", password: "spx_pass" });
await page.goto("https://api.ipify.org", { waitUntil: "domcontentloaded" });
console.log(await page.evaluate(() => document.body.innerText)); // proxy IP
await browser.close();Làm thế nào để sử dụng proxy SOCKS5?
Chỉ cần đặt địa chỉ socks5:// vào --proxy-server. Tuy nhiên Chrome không hỗ trợ xác thực username/password cho SOCKS proxy nên page.authenticate không áp dụng được với SOCKS5. Để kết nối SOCKS5, hãy dùng IP authorization bằng cách đăng ký IPv4 của server chạy code này vào dashboard.
Nếu môi trường yêu cầu kết nối bằng tên người dùng và mật khẩu, cách đơn giản nhất là sử dụng cổng HTTP của cùng một IP. Vì cùng IP nên vị trí hiển thị trên trang đích sẽ giống nhau.
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({
args: ["--proxy-server=socks5://198.51.100.23:1080"], // server IP is authorized in the dashboard
});
const page = await browser.newPage();
await page.goto("https://api.ipify.org");
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();Làm thế nào để mở nhiều trình duyệt với các IP khác nhau?
Chrome chỉ hỗ trợ một proxy cho mỗi trình duyệt đang chạy, vì vậy nếu bạn cần các IP khác nhau, bạn phải chạy các trình duyệt riêng biệt. Đoạn mã dưới đây nhận danh sách ip:port:user:pass từ API và mở ba trình duyệt riêng biệt với ba IP đầu tiên, sau đó hiển thị IP trên mỗi trang.
Mở nhiều trình duyệt cùng lúc tốn nhiều bộ nhớ. Nên thiết lập hàng đợi công việc và giới hạn số trình duyệt chạy đồng thời.
import puppeteer from "puppeteer";
const KEY = "YOUR_API_KEY";
const res = await fetch("https://socks5proxy.io/api/v1/proxies/download?format=ip:port:user:pass&protocol=http", {
headers: { Authorization: "Bearer " + KEY },
});
const lines = (await res.text()).trim().split("\n").slice(0, 3);
await Promise.all(lines.map(async (line) => {
const [ip, port, user, pass] = line.trim().split(":");
const browser = await puppeteer.launch({ args: ["--proxy-server=http://" + ip + ":" + port] });
try {
const page = await browser.newPage();
await page.authenticate({ username: user, password: pass });
await page.goto("https://api.ipify.org", { timeout: 30000 });
console.log(ip, await page.evaluate(() => document.body.innerText));
} finally {
await browser.close();
}
}));Làm thế nào để mở trang nhanh hơn?
Proxy xử lý mọi thứ từ hình ảnh, phông chữ đến video nên tốn nhiều băng thông và thời gian hơn. Nếu chỉ cần văn bản và dữ liệu, chặn yêu cầu hình ảnh và phông chữ bằng page.setRequestInterception giúp tăng tốc và tiết kiệm băng thông hàng tháng của gói chia sẻ.
Giá trị waitUntil cũng quan trọng. networkidle0 chờ đến khi tất cả các yêu cầu hoàn thành, có thể làm chậm, vì vậy tốt hơn là sử dụng page.waitForSelector để chuyển sang bước tiếp theo ngay khi các yếu tố cần thiết xuất hiện.
await page.setRequestInterception(true);
page.on("request", (req) => {
const type = req.resourceType();
if (type === "image" || type === "font" || type === "media") req.abort();
else req.continue();
});Có thể dùng IP khác nhau cho mỗi trang trong cùng trình duyệt không?
Tùy chọn --proxy-server của Chrome áp dụng cho toàn bộ trình duyệt, khiến việc sử dụng các IP khác nhau cho từng trang trở nên khó khăn. Puppeteer 22 trở lên hỗ trợ tùy chọn proxyServer trong browser.createBrowserContext, cho phép bạn sử dụng proxy khác nhau cho từng ngữ cảnh. Ngữ cảnh này tách biệt cookie và bộ nhớ, phù hợp cho các tác vụ theo từng tài khoản.
Bạn có thể chuyển username và password cho các trang trong context thông qua page.authenticate. Cách này tiết kiệm bộ nhớ hơn so với mở nhiều trình duyệt.
import puppeteer from "puppeteer";
const browser = await puppeteer.launch();
const context = await browser.createBrowserContext({ proxyServer: "http://198.51.100.23:8000" });
const page = await context.newPage();
await page.authenticate({ username: "spx_user", password: "spx_pass" });
await page.goto("https://api.ipify.org");
console.log(await page.evaluate(() => document.body.innerText));
await context.close();
await browser.close();Để xuất hiện như người dùng từ quốc gia đó, bạn cần điều chỉnh những gì?
Đặt Accept-Language bằng page.setExtraHTTPHeaders và múi giờ bằng page.emulateTimezone theo quốc gia IP. Ngôn ngữ/múi giờ khác với IP có thể khiến trang hiển thị sai ngôn ngữ hoặc định dạng ngày.
Thiết lập kích thước màn hình bằng page.setViewport, nếu cần giao diện điện thoại có thể chuyển cài đặt thiết bị từ KnownDevices của puppeteer vào page.emulate.
await page.setExtraHTTPHeaders({ "Accept-Language": "ja-JP,ja;q=0.9" });
await page.emulateTimezone("Asia/Tokyo");
await page.setViewport({ width: 1366, height: 900 });Làm thế nào để duy trì trình duyệt ổn định trong tác vụ dài?
Đối với công việc chạy cả ngày, thay vì mở một trình duyệt và sử dụng liên tục, hãy đóng và mở lại trình duyệt sau khi xử lý một số trang nhất định. Trình duyệt để lâu sẽ sử dụng nhiều bộ nhớ hơn và một lỗi có thể làm dừng toàn bộ công việc sau đó.
Đảm bảo gọi page.close trong khối try và finally cho mỗi trang, đồng thời thêm timeout vào goto để không bị kẹt ở trang không phản hồi. Đối với tác vụ thất bại, hãy thử lại bằng cách mở trình duyệt mới với proxy khác.
Ghi lại thời gian phản hồi và lỗi proxy theo từng proxy sẽ giúp bạn tìm ra proxy chậm để liên hệ hỗ trợ hoặc điều chỉnh lịch trình tác vụ.
Làm thế nào để giải quyết các lỗi thường gặp?
net::ERR_INVALID_AUTH_CREDENTIALS hoặc mã 407 xuất hiện khi giá trị page.authenticate không chính xác hoặc không được gọi sau newPage. Hãy đảm bảo gọi nó trước khi goto cho mỗi trang.
net::ERR_PROXY_CONNECTION_FAILED xuất hiện khi địa chỉ hoặc cổng không chính xác. Hãy đảm bảo sử dụng cổng HTTP cho địa chỉ HTTP và cổng SOCKS5 cho địa chỉ SOCKS5. Nếu kết nối SOCKS5 bị từ chối, hãy kiểm tra xem IP của máy chủ đã được đăng ký trong IP authorization chưa.