一日一技:在 Puppeteer 中如何攔截并修改網站的 JavaScript 代碼
在我的爬蟲書中,講到了使用 Charles 或者 MitmProxy 實現中間人攻擊,從而繞過反爬蟲機制的方法。但這兩種方法都需要安裝根證書。

今天,我們來試一試在 Puppeteer 中,使用中間人攻擊,攻擊目標是我們自己,來繞過反爬蟲機制。
首先,我們用以下代碼訪問網站http://exercise.kingname.info/exercise_ajax_1.html:
const puppeteer = require('puppeteer-core'); (async () => { const browser = await puppeteer.launch({ executablePath: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', headless:false, }); const [page] = await browser.pages() await page.goto('http://exercise.kingname.info/exercise_ajax_1.html'); })();
運行效果如下圖所示:
現在,我想攔截網站返回的數據,并篡改它。首先我們打開 Chrome 的開發者工具,看看這個頁面有哪些 Ajax 請求:
紅框框住的這個 Ajax 請求,返回了網頁上面的文字。這個請求對應的地址是:http://exercise.kingname.info/ajax_1_backend,如下圖所示:
現在,我們就來嘗試篡改這個請求的返回數據。首先使用npm安裝一個包:npm install puppeteer-interceptor。然后修改代碼:
const puppeteer = require('puppeteer-core'); const { intercept, patterns } = require('puppeteer-interceptor'); (async () => { const browser = await puppeteer.launch({ executablePath: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', headless:false, }); const [page] = await browser.pages(); intercept(page, patterns.XHR('*ajax_1_backend'), { onResponseReceived: event => { console.log(`${event.request.url} intercepted, going to modify`) var content = `You are hacked by me`; event.response.body = content; return event.response; } }); await page.goto('http://exercise.kingname.info/exercise_ajax_1.html'); })();
運行效果如下圖所示:
其中關鍵的代碼如下:
intercept(page, patterns.XHR('*ajax_1_backend'), { onResponseReceived: event => { console.log(`${event.request.url} intercepted, going to modify`) var content = `You are hacked by me`; event.response.body = content; return event.response; } });
這一段代碼指定,要修改一個 XHR 請求的返回。這個 XHR 請求的 URL 是以ajax_1_backend結尾的。所謂的 XHR 請求,全稱是XMLHttpRequest,大家可以把它近似看做 Ajax 請求。
當檢測到滿足這個通配符的請求時,無論它的內容是什么,都改寫成You are hacked by me,然后返回給瀏覽器。
有人可能會問,你這樣修改,簡單是簡單,但它有什么用呢?它的用處非常大,比如你在做爬蟲的時候,把網站的 javaScript 的一部分代碼替換了,這樣就能繞過反爬蟲檢測。
我做了一個示例的頁面來說明。這個頁面直接訪問,如下圖所示:
使用開發者工具,我們可以看到核心的反爬蟲邏輯在http://127.0.0.1:8000/backend.js這個 js 文件中,如下圖所示:
這個演示的例子中,這個反爬蟲函數非常簡單。但在真實的場景中,它的邏輯非常復雜。然而,邏輯再復雜,也有個調用入口。簡單分析這個javaScript 代碼,我們可以知道,只需要把代碼第14行注釋掉,強制設置is_spider = false,就可以繞過這個反爬蟲邏輯了。
為了繞過反爬蟲邏輯,首先,我們把網站的這個JavaScript 代碼復制下來,保存成safe.js文件。然后修改里面的代碼,繞過反爬蟲邏輯:
var a = 1; var b = 2; function antispider(){ console.log('開始檢測爬蟲'); console.log('開始收集瀏覽器指紋'); console.log('開始檢查是否是模擬瀏覽器'); if (a + b === 3) { // 是爬蟲! return true; } } is_spider = false; //這里強制寫成 false if(is_spider) { alert('你是爬蟲!'); } else { document.getElementById("content").innerHTML = "In America, leave airplane, inner People, related to the benefit, know everything, know nothing, said nothing, above."; }
接下來,修改 Puppeteer 的代碼,從本地讀取這個修改后的 js 文件,然后攔截真正的請求并使用修改后的代碼替換:
const puppeteer = require('puppeteer-core'); const fs = require('fs'); const { intercept, patterns } = require('puppeteer-interceptor'); (async () => { const safe_code = fs.readFileSync('./safe.js', 'utf8'); const browser = await puppeteer.launch({ executablePath: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', headless:false, }); const [page] = await browser.pages(); intercept(page, patterns.Script('*backend.js'), { onResponseReceived: event => { console.log(`${event.request.url} intercepted, going to modify`) event.response.body = safe_code; return event.response; } }); await page.goto('http://127.0.0.1:8000'); })();
運行效果如下圖所示:
從圖中可以看到,我們成功繞過了反爬蟲的邏輯,獲得了真正的頁面數據。
這里有兩個地方需要注意:
要攔截哪個請求,對應到的是intercept函數的第二個參數。這個參數的值是patterns.XXX(地址通配符)。其中的 XXX 可以是如下幾個關鍵詞:Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, EventSource, websocket, Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other。地址通配符注意是通配符不是正則表達式。通配符里面,*表示多個字符,?表示一個字符。
puppeteer-interceptor對中文的支持不太好。攔截到請求返回的數據以后,如果要修改文本,盡量修改成英文的。否則可能會報錯。
puppeteer-interceptor不僅可以修改返回的內容,還可以修改網站的請求。更多強大功能,大家可以閱讀它的官方文檔。
JavaScript 爬蟲
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。