Python Webdriver 從新使用已經打開的瀏覽器實例

由於Webdriver每次實例化都會新開一個全新的瀏覽器會話,在有些狀況下須要複用以前打開未關閉的會話。好比爬蟲,但願結束腳本時,讓瀏覽器處於空閒狀態。當腳本從新運行時,它將繼續使用這個會話工做。還就是在作自動化測試時,前面作了一大推操做,可是因爲程序出錯,重啓時不用再繼續前面複雜的操做。java

我的以爲這種功能很是有用,可是官方竟然沒有提供這種功能的API,苦苦搜搜,在網上找了兩個java版的http://blog.csdn.net/wwwqjpcom/article/details/51232302 和 http://woxiangbo.iteye.com/blog/2372683
看了下源碼其實java和python的驅動原理過程都很是類似。python

打開一個Chrome會話:web

from selenium import webdriver
driver = webdriver.Chrome()

運行上面的腳本,它將啓動瀏覽器並退出。由於沒有調用quit()方法,因此瀏覽器會話仍會存在。可是代碼裏建立的driver對象已經不在了,理論上不能用腳本控制這個瀏覽器。它將變成一個殭屍瀏覽器,只能手動殺死它。chrome

經過webdriver啓動一個瀏覽器會話大概會有這樣三個階段:shell

  • 一、啓動的瀏覽器驅動代理(hromedriver,Firefox的驅動程序,等等);
  • 二、建立一個命令執行器。用來向代理髮送操做命令;
  • 三、使用代理創建一個新的瀏覽器會話,該代理將與瀏覽器進行通訊。用sessionId來標識會話。

所以只要拿到階段2中的執行器和階段3中的sessionID就能恢復上次的會話。這兩個有api能夠直接獲取: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上面講的實現是這樣的:session

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:ide

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")

這樣就能順利鏈接到上次沒關閉的瀏覽器會話。

文章地址: http://www.spiderpy.cn/blog/detail/36

相關文章
相關標籤/搜索