Python Webdriver 重新使用已經打開的瀏覽器實例
因為Webdriver每次實例化都會新開一個全新的瀏覽器會話,在有些情況下需要復用之前打開未關閉的會話。比如爬蟲,希望結束腳本時,讓瀏覽器處於空閑狀態。當腳本重新運行時,它將繼續使用這個會話工作。還就是在做自動化測試時,前面做了一大推操作,但是由於程序出錯,重啟時不用再繼續前面復雜的操作。
個人覺得這種功能非常有用,但是官方居然沒有提供這種功能的API,苦苦搜搜,在網上找了兩個java版的http://blog.csdn.net/wwwqjpcom/article/details/51232302 和 http://woxiangbo.iteye.com/blog/2372683
看了下源碼其實java和python的驅動原理過程都非常相似。
打開一個Chrome會話:
from selenium import webdriver driver = webdriver.Chrome()
運行上面的腳本,它將啟動瀏覽器並退出。因為沒有調用quit()
方法,所以瀏覽器會話仍會存在。但是代碼里創建的driver
對象已經不在了,理論上不能用腳本控制這個瀏覽器。它將變成一個僵屍瀏覽器,只能手動殺死它。
通過webdriver啟動一個瀏覽器會話大概會有這樣三個階段:
- 1、啟動的瀏覽器驅動代理(hromedriver,Firefox的驅動程序,等等);
- 2、創建一個命令執行器。用來向代理發送操作命令;
- 3、使用代理建立一個新的瀏覽器會話,該代理將與瀏覽器進行通信。用
sessionId
來標識會話。
因此只要拿到階段2中的執行器和階段3中的sessionID
就能恢復上次的會話。這兩個有api可以直接獲取:
from selenium import webdriver driver = webdriver.Chrome() executor_url = driver.command_executor._url session_id = driver.session_id print(session_id) print(executor_url) driver.get("http://www.spiderpy.cn/")
得到類似這樣的輸出(第一個是會話的sessionId,第二個就是命令執行器連接):
397d725f042a076f7d4a82f7d3fead13
http://127.0.0.1:52869
一切就緒,下面就開始實現復用之前會話的功能,在Stack Overflow上面講的實現是這樣的:
from selenium import webdriver driver = webdriver.Chrome() executor_url = driver.command_executor._url session_id = driver.session_id driver.get("http://www.spiderpy.cn/") print(session_id) print(executor_url) driver2 = webdriver.Remote(command_executor=executor_url, desired_capabilities={}) driver2.session_id = session_id print(driver2.current_url)
可能是因為版本原因吧,反正在我環境中運行時,效果是實現了,能夠重新連接到上一個會話,但是卻打開了一個新的空白會話。看了下Remote
類的源碼,發現是因為每次實例化都會調用start_session
這個方法新建一個會話。所以解決方法就是繼承並重寫這個類。自定義一個ReuseChrome
這個類重寫start_session
方法使它不再新建session,使用傳入的session_id:
from selenium.webdriver import Remote from selenium.webdriver.chrome import options from selenium.common.exceptions import InvalidArgumentException class ReuseChrome(Remote): def __init__(self, command_executor, session_id): self.r_session_id = session_id Remote.__init__(self, command_executor=command_executor, desired_capabilities={}) def start_session(self, capabilities, browser_profile=None): """ 重寫start_session方法 """ if not isinstance(capabilities, dict): raise InvalidArgumentException("Capabilities must be a dictionary") if browser_profile: if "moz:firefoxOptions" in capabilities: capabilities["moz:firefoxOptions"]["profile"] = browser_profile.encoded else: capabilities.update({'firefox_profile': browser_profile.encoded}) self.capabilities = options.Options().to_capabilities() self.session_id = self.r_session_id self.w3c = False
然后在第二次連接是使用重寫的ReuseChrome
類:
from selenium import webdriver # 第一次使用Chrome() 新建瀏覽器會話 driver = webdriver.Chrome() # 記錄 executor_url 和 session_id 以便復用session executor_url = driver.command_executor._url session_id = driver.session_id # 訪問百度 driver.get("http://www.spiderpy.cn/") print(session_id) print(executor_url) # 假如driver對象不存在,但瀏覽器未關閉 del driver # 使用ReuseChrome()復用上次的session driver2 = ReuseChrome(command_executor=executor_url, session_id=session_id) # 打印current_url為百度的地址,說明復用成功 print(driver2.current_url) driver2.get("https://www.baidu.com")
這樣就能順利連接到上次沒關閉的瀏覽器會話。