爬蟲模擬瀏覽器如何避免重複登錄?

大家好,我是 Kuls。

當我們使用模擬瀏覽器訪問一個網站的時候,可能會遇到網站需要登錄的情況。我的爬蟲練習網站提供了這樣一個登錄練習 [1] 的案例。

如果你手動用瀏覽器測試,你會發現這樣一個現象:第一次訪問的時候,自動跳轉到登錄頁面。輸入賬號kingname和密碼genius以後,可以看到登錄成功的頁面,如下圖所示:

現在,你把瀏覽器關了再打開,然後再次訪問這個網址,你會發現瀏覽器直接就能進入到登錄成功的頁面,不會再出現登錄頁面。

我們都知道,這是因爲瀏覽器記住了網站的 Cookies,即使關閉了瀏覽器再打開,這個 Cookies 依然存在,所以可以繞過登錄功能。

但如果你使用 Selenium 或者 Puppeteer/Pyppeteer,那麼情況就不是這樣了。當你第一次登錄成功了以後,退出程序。第二次重新運行程序的時候,爬蟲又要重新登錄一次。這個過程一來拖慢了爬蟲的運行速度,二來容易讓網站檢測到你的賬號異常——難道自動登錄功能失效了?爲什麼其他人的都正常,他的賬號每小時都要重新登錄一次?可能是爬蟲,發個驗證碼過去探探虛實。

同理,還有時候,網站登錄會出現很麻煩的驗證碼,但是一旦登錄成功,這個驗證碼就再也不會出現了。處理這種驗證碼最簡單的辦法就是直接人工參與。那麼如果爬蟲每小時都要運行一次,豈不是每小時都要人來過一次驗證碼?能不能讓爬蟲只登錄一次,之後就再也不登陸了呢?

方法有兩個。第一個方法,也是大家最直觀能想到的方法:登陸成功以後,把 Cookies 保存下來。下一次要重新登陸的時候直接把這個 Cookies 設置到瀏覽器裏面可以了。這個方法網上有很多例子,你可以通過關鍵詞 “selenium 獲取 cookies” 和“selenium 設置 cookies”搜索到,我就不再贅述了。

我們今天要講的是第二個方法,也是最簡單的方法。並且這個方法聽起來很弱智:我不關瀏覽器,它的 Cookies 不就不會清空了嗎?

但你仔細想一下,根據你之前的經驗,當你的爬蟲代碼退出的時候,是不是瀏覽器也被自動關閉了?即使因爲某種原因,爬蟲代碼本身崩潰了,瀏覽器沒有關閉,那你第二次啓動爬蟲的時候,怎麼重新連回之前啓動的瀏覽器?

我們今天要做的,就是把啓動瀏覽器和啓動爬蟲,這兩件事情分開。首先使用某種方法單獨啓動瀏覽器,然後再啓動爬蟲代碼,並且讓爬蟲代碼接管這個瀏覽器並控制它。

Chrome 瀏覽器是支持遠程調試模式的。這個模式打開的情況下,Puppeteer 或者 Selenium 可以通過 websocket 連上去,進而控制它。

首先我們來啓動 Chrome 的遠程調試端口。你需要找到 Chrome 的安裝位置,在 Chrome 的地址欄輸入chrome://version就能找到 Chrome 的安裝路徑,如下圖所示:

有了這個以後,我們需要執行命令啓動支持遠程調試功能的 Chrome。如果你的電腦是 Mac,那麼命令是:

"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"  --remote-debugging-port=9222 --no-first-run --no-default-browser-check --user-data-dir=$(mktemp -d -t 'chrome-remote_data_dir')

注意,由於地址中有空格,所以要把可執行文件的路徑用引號抱起來。

如果你的電腦是 Windows,那麼就很簡單了,執行命令:

文件路徑/chrome.exe --remote-debugging-port=9222

啓動以後如下圖所示:

此時,你先不要動這個通過命令啓動的 Chrome。你先打開普通的瀏覽器,輸入網址:http://127.0.0.1:9222/json/version,如下圖所示:

記住其中的webSocketDebuggerUrl後面的地址。這就是我們遠程鏈接的地址。

今天我們以 Puppeteer 爲例,介紹如何連接這個遠程的 Chrome。

在連之前,我們首先做一件事情,在通過命令啓動的這個 Chrome 中,打開我們的登錄練習頁面,然後手動登錄它。如下圖所示:

然後,我們來寫一段 Puppeteer 的代碼:

const puppeteer = require('puppeteer-core')

async function run(){
  var address = 'ws://127.0.0.1:9222/devtools/browser/f6ede2a1-cf7b-4a0d-b0ea-9c0cd24d240d'
  const browser = await puppeteer.connect({
  browserWSEndpoint: address,
});
  const page = await browser.newPage();
response = await page.goto('http://exercise.kingname.info/exercise_login_success'{ waitUntil: 'load', timeout: 0 });
}
run()

這段代碼最核心的就兩行,連接遠程的 Chrome:

var address = 'ws://127.0.0.1:9222/devtools/browser/f6ede2a1-cf7b-4a0d-b0ea-9c0cd24d240d'
  const browser = await puppeteer.connect({
  browserWSEndpoint: address,
});

運行效果如下圖所示:

可以看到,代碼控制瀏覽器打開了一個新的標籤頁,並且立刻就能打開登錄成功後的頁面,不需要再次登錄。

大家可以試一試,現在在終端窗口裏面按下 Ctrl + C 把當前的爬蟲代碼強行關閉,然後再啓動一次,你會發現依然是登錄以後的頁面。

這樣一來,以後遇到需要登錄的網站,只需要使用這個遠程調試模式,先啓動一個支持遠程調試的 Chrome 瀏覽器,然後手動在瀏覽器上完成登錄操作,接下來爬蟲代碼就再也不需要考慮登錄這個動作了,爬蟲可以直接訪問登錄後的頁面。

你自己測試的過程中,可能會發現標籤頁越開越多。其實不用擔心,這是因爲我爲了演示登錄後的頁面,沒有關閉當前標籤頁導致的。你的爬蟲執行完操作以後,可以使用await page.close()關閉當前標籤頁。只要至少保留一個標籤頁不關閉,那麼這個瀏覽器窗口就可以一直使用。

參考文獻

[1] 登錄練習: http://exercise.kingname.info/exercise_login_success

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/z15mp2nDf0dFBf4R03U2-A