測試和爬蟲對selenium并不會陌生,現有的教程已經非常多。但是因為 selenium 封裝的方法比較底層,是以靈活性非常高,我們可以基于這種靈活性來實作非常豐富的定制功能。
這篇文章介紹一個操作,可以讓selenium 控制浏覽器共用同一個 session。他的應用場景是:共用登入狀态、中斷後持續運作。
在傳統的自動化腳本中,一旦程式運作完成,我們就再也擷取不到該浏覽器的會話對象了。當你下一次想重新運作腳本時,可能會有比較多的重複步驟,通過這種方式,我們可以繞過這些重複步驟,直接使用之前的會話對象。
一個典型的場景就是記住使用者登入狀态。我們可以先用第一個腳本實作登入,然後把這次的浏覽器會話存下來, 然後我們可以實作第二個腳本,第三個腳本,直接使用這個登入後的浏覽器操作後面的步驟。
隻要第一個浏覽器的會話沒有失效,則後面每次我需要運作時,都可以使用這個會話。

半永久的 chrome
首先,我們通過 selenium 建立一個半永久的 chrome 會話,代碼是每一個會 selenium 的小夥伴閉着眼睛都能寫出來的。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')
需要注意的是,我們在後面沒有執行 driver.quit() 函數。這有什麼差別呢? quit 後 chromedriver.exe 程序就直接退出了,但是沒有 quit 的 chromedriver 程序是會保留在背景運作的, 是以當你運作上面的代碼後,你可以發現 chromedriver 程序還停留在背景,而加了 quit 函數後,程序就會消失。
你可以通過任務管理器檢視,或者在 cmd 指令行輸入
tasklist | findStr chromedriver
通過
taskkill /im chromedriver.exe -f
指令強制終止程序。
要 chromedriver.exe 成為半永久,而不是運作腳本就結束,隻需要保持程序在運作,不添加 driver.quit() 就可以啦。隻要你的電腦不重新開機,那麼就可以一直利用這個 chromedriver.exe 提供服務。
擷取 session id 和 webdriver 服務位址
每個浏覽器會話,在 selenium 中都會有一個唯一的 session id, 他記錄了浏覽器的所有狀态,包括使用者目錄,使用者登入的狀态, 隻要 selenium 使用的 session id 是一緻的,那麼浏覽器的狀态就是一緻的。
其次,chromedriver 服務有一個遠端的連接配接位址,隻要連接配接該位址,就可以使用同一個 chromedriver 服務。
在 selenium 中,可以這樣擷取到 session id 和遠端位址:
session_id = driver.session_id
remote_executor = driver.command_executor._url
連接配接半永久的 selenium session
有了 session id 和服務位址,接下來就可以通過 selenium 初始化用戶端建立連結了。 selenium 中的 Chrome 對象預設每次都會初始化一個新的 chromedriver 服務,雖然在最新的 selenium4 中,這種情況有所改善,但是我們在這還是采用更加通用的方式,使用 Remote 對象來建立連接配接。
caps = {
"capabilities": {
"firstMatch": [
{"browserName": "chrome"},
]
}
}
driver2 = webdriver.Remote(remote_executor, desired_capabilities=caps)
driver2.close()
driver2.session_id = session_id
driver2.find_element('id', 'kw').send_keys('hello')
這裡用了比較标準的 webdriver capbilities 參數,如果覺得麻煩, caps 可以直接用 {} 代替。 Remote 會通路半永久的chromedriver 服務位址,然後我們把這個 driver2 的 session_id 設定成同一個 session, 因為 driver2 會重新建立一個新的 tab,是以我們通過 driver.close() 先把這個多餘的 tab 關掉。
總結
可能你會覺得,這種方式和直接用一次浏覽器操作并沒有什麼差別。實際上,效果其實和隻使用一次 selenium driver 對象是差不多的,但是,在實際應用中,你的自動化程式不可能永遠都在正常運作的狀态。
如果程式中斷,你将無法再擷取之前的 driver 對象了。 而通過這種方式,管理 driver 對象和運作是分開的,就算程式中斷,浏覽器對象還在背景。 你可以像下載下傳大檔案的時候使用斷點續傳那樣,無論什麼時候中斷,都能重新擷取之前的浏覽器。
完整的代碼:
from selenium import webdriver
# 半永久的 chrome session
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')
# 擷取 service url 和 session_id
remote_executor = driver.command_executor._url
session_id = driver.session_id
# 連接配接之前的 session
caps = {
"capabilities": {
"firstMatch": [
{"browserName": "chrome"},
]
}
}
driver2 = webdriver.Remote(remote_executor, desired_capabilities=caps)
driver2.close()
driver2.session_id = session_id
driver2.find_element('id', 'kw').send_keys('hello')