# Puppeteer

Puppeteer 需要两件事：启动时加 `--proxy-server`，再用 `page.authenticate()` 处理凭证。

## 基础写法

```js
import puppeteer from "puppeteer";

const browser = await puppeteer.launch({
  args: ["--proxy-server=http://gate.helodata.io:7777"],
});
const page = await browser.newPage();

await page.authenticate({
  username: "helo_s1a2b3c4d5e-type-res-region-us",
  password: "PASSWORD",
});

await page.goto("https://ipv4.icanhazip.com");
console.log(await page.content());
await browser.close();
```

`page.authenticate()` 透明处理代理认证弹框。

## ISP

```js
const browser = await puppeteer.launch({
  args: ["--proxy-server=http://198.51.100.42:8000"],
});
await page.authenticate({ username: "helo_s1a2b3c4d5e", password: "PASSWORD" });
```

## 用 `puppeteer-page-proxy` 按页代理

官方 Puppeteer 无法运行中改代理——Chromium 启动后 `--proxy-server` 就固定了。要按页轮换，请用 `puppeteer-page-proxy`：

```bash
npm i puppeteer-extra puppeteer-extra-plugin-stealth puppeteer-page-proxy
```

```js
import puppeteer from "puppeteer-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
import useProxy from "puppeteer-page-proxy";

puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch();
const page = await browser.newPage();

await useProxy(page, "http://helo_s1a2b3c4d5e-type-res-region-us:PASSWORD@gate.helodata.io:7777");
await page.goto("https://ipv4.icanhazip.com");
```

`useProxy()` 可反复调用，在请求间切换 page 的代理。

## ISP 轮换示例

```js
import fs from "node:fs";
const list = fs.readFileSync("isp.txt", "utf8").trim().split("\n");
let i = 0;

async function fetchOne(url) {
  const line = list[i++ % list.length];
  const [ip, port, user, pass] = line.split(":");
  const p = `http://${user}:${pass}@${ip}:${port}`;
  await useProxy(page, p);
  await page.goto(url);
}
```

## 验证

```js
const ip = await page.evaluate(() =>
  fetch("https://ipv4.icanhazip.com").then(r => r.text())
);
console.log(ip.trim());
```

## 常见陷阱

* **在 `page.goto()` 之前没调用 `authenticate()`** — 首个请求会卡在认证弹框。`newPage()` 后立刻调用。
* **`puppeteer-extra-plugin-stealth` 只伪装浏览器指纹**，不改 IP——配合 helodata 才能两手都硬。
* **仅用 `--proxy-server` 导致所有页共用代理** — 按页代理需上述插件。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.helodata.com/helodata-zh/ji-cheng-zhi-nan/pa-chong-gong-ju/puppeteer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
