Socks5Proxy

การตั้งค่า proxy ใน Puppeteer เชื่อมต่อด้วย --proxy-server และ page.authenticate

คู่มือนี้จะอธิบายวิธีการเชื่อมต่อ HTTP Proxy ของ Socks5Proxy ด้วยอาร์กิวเมนต์ --proxy-server และการรับรอง page.authenticate เมื่อรัน Chrome ด้วย Puppeteer การเชื่อมต่อ SOCKS5 และโค้ดสำหรับเปิดเบราว์เซอร์หลายตัวด้วย IP ที่แตกต่างกัน

proxy ทำงานอย่างไรใน Puppeteer?

Puppeteer กำหนด proxy ด้วยอาร์กิวเมนต์เมื่อเรียกใช้ Chrome การใส่ที่อยู่ใน --proxy-server จะทำให้ทุกหน้าในเบราว์เซอร์นั้นใช้ proxy เดียวกัน ไม่สามารถใส่ชื่อผู้ใช้และรหัสผ่านของ HTTP proxy เป็นอาร์กิวเมนต์ได้ ต้องใช้ page.authenticate หลังจากเปิดหน้า เมื่อ proxy ขอการยืนยันตัวตน Puppeteer จะตอบกลับโดยอัตโนมัติ

ตัวอย่างใช้ IP 198.51.100.23 พอร์ต HTTP 8000 พอร์ต SOCKS5 1080 ชื่อผู้ใช้ spx_user และรหัสผ่าน spx_pass

npm install puppeteer

How to connect HTTP proxy and authentication?

เพิ่ม --proxy-server=198.51.100.23:8000 ใน args ของ launch และส่ง username กับ password ไปยัง page.authenticate ทันทีหลังจากสร้างหน้าด้วย newPage ต้องทำการยืนยันตัวตนสำหรับทุกหน้า ดังนั้นให้เรียกใช้คำสั่งเดียวกันทุกครั้งที่สร้างหน้าใหม่

HTTPS sites open normally. The browser creates a CONNECT tunnel and communicates encrypted within it.

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();

จะใช้ SOCKS5 Proxy อย่างไร

ใส่ที่อยู่ socks5:// ใน --proxy-server แต่ Chrome ไม่รองรับการยืนยันตัวตนด้วย username/password สำหรับ SOCKS proxy ดังนั้น page.authenticate จะไม่ทำงานกับ SOCKS5 ให้ใช้ IP authorization โดยลงทะเบียน IPv4 ของเซิร์ฟเวอร์ที่รันโค้ดนี้ในแดชบอร์ดแทน

หากต้องเชื่อมต่อด้วยชื่อผู้ใช้และรหัสผ่าน การใช้พอร์ต HTTP ของ IP เดียวกันจะง่ายที่สุด เนื่องจากเป็น IP เดียวกัน ตำแหน่งที่แสดงบนเว็บไซต์เป้าหมายจึงเหมือนกัน

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();

วิธีการเปิดเบราว์เซอร์หลายตัวด้วย IP ที่ต่างกัน?

Chrome allows only one proxy per browser instance, so if you need different IPs, you need to launch separate browsers. The code below fetches an ip:port:user:pass list via the API, launches a browser for each of the first three entries, and prints the IP displayed on each page.

การเปิดเบราว์เซอร์หลายตัวจะใช้หน่วยความจำมาก แนะนำให้ตั้งคิวงานและจำกัดจำนวนเบราว์เซอร์ที่ทำงานพร้อมกัน

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();
  }
}));

จะเปิดหน้าเว็บได้เร็วขึ้นได้อย่างไร?

เมื่อใช้พร็อกซี่ รูปภาพ แบบอักษร และวิดีโอทั้งหมดจะถูกดาวน์โหลดผ่านพร็อกซี่ ทำให้ใช้แบนด์วิธและเวลามากขึ้น หากต้องการเพียงข้อความและข้อมูล การบล็อกคำขอรูปภาพและแบบอักษรด้วย page.setRequestInterception จะช่วยเพิ่มความเร็วและประหยัดแบนด์วิธรายเดือนของแผน共享

ค่า waitUntil ก็สำคัญเช่นกัน networkidle0 รอจนกว่าคำขอทั้งหมดจะเสร็จสิ้นซึ่งอาจช้า ดังนั้นหากต้องการให้ดำเนินการต่อทันทีที่องค์ประกอบที่ต้องการปรากฏขึ้น ให้ใช้ page.waitForSelector แทน

await page.setRequestInterception(true);
page.on("request", (req) => {
  const type = req.resourceType();
  if (type === "image" || type === "font" || type === "media") req.abort();
  else req.continue();
});

สามารถใช้ IP ต่างกันสำหรับแต่ละหน้าในเบราว์เซอร์เดียวได้หรือไม่

Chrome's --proxy-server applies to the entire browser, making it difficult to assign different IPs per page. Puppeteer 22 and above allows different proxies per context via the proxyServer option in browser.createBrowserContext. Contexts have separate cookies and storage, making them suitable for account-specific tasks.

หน้าที่สร้างใน context ก็สามารถส่ง username และ password ผ่าน page.authenticate ได้ ใช้หน่วยความจำน้อยกว่าการเปิดเบราว์เซอร์หลายตัว

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();

ต้องปรับอะไรบ้างเพื่อให้ดูเหมือนผู้ใช้จากประเทศนั้น?

ตั้งค่า Accept-Language ด้วย page.setExtraHTTPHeaders และเขตเวลาด้วย page.emulateTimezone ให้ตรงกับประเทศ IP หากภาษาและเขตเวลาไม่ตรงกับประเทศ IP หน้าเว็บอาจแสดงผลในภาษาที่ไม่ถูกต้องหรือรูปแบบวันที่แตกต่างกัน

กำหนดขนาดหน้าจอด้วย page.setViewport และหากต้องการหน้าจอมือถือ ให้ส่งการตั้งค่าอุปกรณ์จาก KnownDevices ของ puppeteer ไปยัง 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 });

วิธีรักษาเสถียรภาพของเบราว์เซอร์ในงานที่ทำงานต่อเนื่องนานๆ

สำหรับงานที่ทำงานตลอดทั้งวัน การปิดเบราว์เซอร์และเปิดใหม่หลังจากประมวลผลหน้าจำนวนหนึ่งจะเสถียรกว่าการเปิดเบราว์เซอร์ครั้งเดียวและใช้ต่อเนื่อง เบราว์เซอร์ที่เปิดไว้นานจะใช้หน่วยความจำมากขึ้นเรื่อยๆ และหากเกิดข้อผิดพลาด งานทั้งหมดอาจหยุดลง

ใช้ try และ finally เพื่อเรียก page.close ทุกหน้า และเพิ่ม timeout ใน goto เพื่อไม่ให้หยุดที่หน้าที่ไม่ตอบสนอง สำหรับงานที่ล้มเหลว ให้ลองใหม่ด้วย proxy อื่นโดยเปิดเบราว์เซอร์ใหม่

การบันทึกเวลาตอบสนองและข้อผิดพลาดของพร็อกซี่แต่ละตัวจะช่วยให้คุณค้นหาเส้นที่ช้าและติดต่อฝ่ายบริการลูกค้าในแดชบอร์ดหรือปรับเปลี่ยนแบตช์งานได้

วิธีแก้ไขข้อผิดพลาดที่พบบ่อย?

net::ERR_INVALID_AUTH_CREDENTIALS หรือ 407 เกิดจากค่า page.authenticate ที่ไม่ถูกต้องหรือไม่ได้เรียกใช้หลังจาก newPage ตรวจสอบให้แน่ใจว่าได้เรียกใช้ก่อน goto ในทุกหน้า

net::ERR_PROXY_CONNECTION_FAILED เกิดจากที่อยู่หรือพอร์ตที่ไม่ถูกต้อง ตรวจสอบว่าคุณใช้พอร์ต HTTP กับที่อยู่ HTTP และพอร์ต SOCKS5 กับที่อยู่ SOCKS5 หรือไม่ หากการเชื่อมต่อ SOCKS5 ถูกปฏิเสธ ตรวจสอบว่า IP ที่ออกจากเซิร์ฟเวอร์อยู่ในรายการ IP ที่อนุญาตหรือไม่

การตั้งค่า proxy ใน Puppeteer ยืนยันตัวตนด้วย page.authenticate | Socks5Proxy