如何解决 selenium 的退出问题? - 关于 Python 函数的运行机制.

最近在搞爬虫,然后顺便写了写基于 selenium 框架的模拟登陆脚本供以后需要时用,然而在这时我发现了一个问题:

代码一开始是这样的:

    from selenium import webdriver

    driver = webdriver.Chrome()
    driver.maximize_window()

    driver.get('http://mail.163.com')

    driver.find_element_by_id('switchAccountLogin').click()
    iframe = driver.find_element_by_xpath('//*[@id="loginDiv"]/iframe')  # 使用Xpath选定位到iframe
    driver.switch_to.frame(iframe)          # 切换iframe
    # iframe = driver.find_element_by_xpath("//iframe[contains(@id, 'x-URS-iframe')]")  # 使用Xpath提供的contains定位
    # driver.switch_to.frame(iframe)
    driver.find_element_by_name('email').send_keys('name')
    driver.find_element_by_name('password').send_keys('password')
    driver.find_element_by_id('dologin').click()

然后进行了简单的改造

    from selenium import webdriver

    class Mail163:

        def __init__(self, name, password):
            self.name = name
            self.password = password
            self.driver = webdriver.Chrome()

        def run(self):
            # driver.maximize_window()
            self.driver.get('http://mail.163.com')
            self.driver.find_element_by_id('switchAccountLogin').click()
            iframe = self.driver.find_element_by_xpath('//*[@id="loginDiv"]/iframe')  # 使用Xpath选定位到iframe
            self.driver.switch_to.frame(iframe)  # 切换iframe
            # iframe = driver.find_element_by_xpath("//iframe[contains(@id, 'x-URS-iframe')]")  # 使用Xpath提供的contains定位
            # driver.switch_to.frame(iframe)
            self.driver.find_element_by_name('email').send_keys(self.name)
            self.driver.find_element_by_name('password').send_keys(self.password)
            self.driver.find_element_by_id('dologin').click()


    if __name__ == "__main__":
        Mail163('111', 'aaa').run()

这个时候我发现,原来运行代码之后,Chrome 依然存在;而在将其函数化之后,运行完了代码 Chrome 便会直接闪退

这时我便想到,这可能跟 Python 的函数运行机制有关,所以我连忙查了一下资料,终于发现了其原理。

在代码中,Mail163 调用时,触发了 selenium/webdriver/common/service.pyService#__del__ 方法; Service#__del__ 调用了同类中的 Service#stop 方法; Service#stop 调用了同类中的 Service#send_remote_shutdown_command 方法; Service#send_remote_shutdown_command 中的 url_request.urlopen("%s/shutdown" % self.service_url) 导致浏览器关闭。

因此结论就很明显了,当 webdriver局部域内被定义时,其代码运行结束后会进行 del 的操作去做资源清理(垃圾回收)

所以如果需要在登录操作运行完后保持 Chrome 的运行,可以将 webdrive 定义部分代码 drive = webdriver.Chrome() 放到函数体外,从而避免被清理。