1 pupppeteer-page-proxy模塊簡介
puppeteer代理設置方法中介紹了設置代理的幾種方式,其中之一是通過攔截請求,再通過http模塊轉發,給http模塊加上代理實現代理設置。pupppeteer-page-proxy[1]nodejs模塊就是基於此實現爲每個請求或page加代理。其中一些特性如下:
- 支持每個page或每個請求使用代理。
- 內部處理cookie。
- 支持http、https、socks4、socks5 代理。
2 環境準備
需要三個工具:
- puppeteer 2.1.1
- pupppeteer-page-proxy 1.2.3
- nodejs 10+
由於pupppeteer-page-proxy設置代理依賴http-proxy-agent、https-proxy-agent。這兩個模塊又依賴agent-base。agent-base需要5.0+。而puppeteer2.1.0纔將agent-base升級到5.1.1。因此puppeteer版本要使用5.1.1。
pupppeteer-page-proxy發送http請求依賴got[2](一個強大的nodejs http庫)。用高版本時got會使用asyn generator因此nodejs版本要升級到10+。否則啓動提示語法錯誤。
3 使用pupppeteer-page-proxy
首先我們爲每個請求指定代理。在page.on監聽請求,隨後通過page proxy發送。以訪問百度爲例,僅當url包含baidu時才使用代理。當打開頁面後,我們查詢ip會發送訪問百度的ip爲代理ip。而訪問bing時則不會對請求增加代理。
const puppeteer = require('puppeteer');
const useProxy = require('puppeteer-page-proxy');
(async () => {
const browser = await puppeteer.launch({
args: [
'--disable-setuid-sandbox',
'--no-sandbox',
'--ignore-certificate-errors',
'--remote-debugging-port=9222',
'--disable-web-security'
],
ignoreHTTPSErrors: true,
headless: false,
executablePath: "path"
});
const proxy = 'http://username:password@domain:port';
const page = await browser.newPage();
await page.setUserAgent('baiduSpider');
await page.setRequestInterception(true);
page.on('request', req => {
if(req.url().indexOf('www.baidu.com/') > -1) {
useProxy(req, proxy);
} else {
req.continue();
}
});
await page.goto('https://www.baidu.com');
})();
接着爲page增加代理。這是將上面的例子稍作修改。不需要在手動設置攔截,監聽請求。page-proxy對於page請求攔截設置會在方法內部完成。
useProxy(page,proxy);
await page.goto('https://www.baidu.com');
4 注意事項
4.1 data-uri數據請求
一個頁面內部通常會有如下形式的標籤。data-src部分指定了一段base64編碼來顯示圖片。這稱作data-uri[3],即在頁面內部嵌入一段數據作爲請求結果。
<img id="id_p" class="id_avatar sw_spd"
style="display:none"
aria-hidden="true"
alt=""
aria-label="個人資料圖片" onerror="FallBackToDefaultProfilePic(this)"
data-src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7" data-alt="" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7" data-bm="17">
通過chrome 調試面板查看網絡請求,url如下所示。
got遇到這種請求會產生錯誤。因此需要改造page-proxy,將這類請求交給瀏覽器處理即可。
Unsupported protocol "data:" 異常
Error: UnsupportedProtocolError: Unsupported protocol "data:"
at request (/Users/sunfei/WebstormProjects/jsDebug/node_modules/puppeteer-page-proxy/src/lib/request.js:43:19)
4.2 代理請求超時控制
由於最終請求通過got發送,page-proxy1.2.3未提供got超時設置。因此這部分需要獨立升級,對外暴露got的設置接口。
const response = await got(url,{
headers: {
'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/82.0.4085.12 Safari/537.36"
},
agent: {
http:proxyAgent,
https:proxyAgentHttps
},
timeout:1000 //超時設置
});
4.3 代理ip查詢
page-proxy提供了一個使用代理後ip地址查詢,其實就是通過請求一個ip查詢接口實現。但默認是一個國外網站。我們在國內使用存在打不開的情況。因此需要進行改造。
const lookup = async (page,
lookupService = "ip查詢服務地址",
isJSON = true, timeout = 30000) => {
5 總結
page-proxy是一個很小巧的puppeteer page/request代理庫,基於攔截轉發思路實現,很簡介。但存在一些問題,如超時控制,代理ip查詢。實際使用過程中可在此基礎上二次開發使用即可。
6 參考
[1]pupppeteer-page-proxy,https://www.npmjs.com/package/puppeteer-page-proxy
[2]got,https://www.npmjs.com/package/got
[3]https://developer.mozilla.org/zh-CN/docs/Web/HTTP/data_URIs