使用selenium操作时,每次使用webdriver.Firefox()都要重新弹出火狐窗口,效率非常低,所以我一直在查,selenium能不能在已打开的浏览器上操作,发现该模块没有这个功能,那说明只能自己来了,百度了很久,只觉得这位老哥@wwwqjpcom的有帮助,那就在他研究的基础上改进下吧!原网址https://blog.csdn.net/wwwqjpcom/article/details/51232302
他的python思路是:
1.先手动打开geckodriver.exe
2.运行本体的类WebDriver,设定好url跟选定firefox,启动浏览器,然后把id跟url保存在data文件内
3.然后在另外一个py文件内获取data内的id跟url,启动自己写的myWebDriver上对已启动浏览器操作,这样就不需要再开启一个浏览器这么费劲了!!
经过测试,完全可以!
但是太特么费劲,居然还得手动运行geckodriver,还得分2个程序,不符合python的优雅性,所以我想着能不能把原selenium代码琢磨透,写出更优美的呢!!
日他奶奶个锤子,实力不够!看代码看得头晕,例如说RemoteConnection这是什么方法?是在这个文件的吗,怎么找不到,原来是从另外的文件导入的,那么再到那个文件去看,又看到一个函数,这个文件也没有啊!奶奶个锤子,又是别的文件导入,头发都挠得快没了,就像一条河,很多支流汇入,然后这些支流也有很多小溪,源头也有很多,最后都汇进了这条大河,方便是方便,好看是好看,但是回查会很痛苦,想搞懂一个方法的用途,真的很折腾,得全部吃透才行。如果pycharm能有什么功能快速回查、或者显示其方法的用途(例子会更好),这样就能很高效率的弄懂他人所写的模块了!
==================================================
回到正题,在专研简化的过程中,session_url跟session_id确实如原博主所说,这就是selenium的关键,只要在启动的程序中替换了webdriver随机产生的id跟url,就不需要重新开启一个浏览器了,而geckodriver.exe就是关键,想要通过selenium启动firefox,就得靠这个程序。
默认的webdriver.Firefox()运行时,先是启动gecko,打开火狐浏览器,代码运行结束后,gecko也跟着关闭。我试着把代码延时,在另外的py文件中运行原博主的myfirefox,发现可以在该浏览器操作,所以想要有这个效果,那么gecko就得持续开着!
所以此时思路有2个,一是修改firefox()代码,让gecko不关闭,但是追踪了下,原来gecko的启动在另外的文件,如果要修改,会非常麻烦,而且怕影响其他程序,所以只能采取第二种了
那就是整个selenium最核心的webdriver了——webdriver.remote.webdriver.WebDriver(),也就是原博主使用的那个,用它来启动浏览器,而且还得持续开着geckodriver.exe,然后用myfirefox在启动了的火狐浏览器操作。
说几点要注意的:
1.运行程序中没有geckodrive,myfirefox会报错
2.有了geckodriver,但是没有火狐没启动,或者不是对应的ID、url,还是报错
3.用webdriver启动的浏览器,第一个窗口不能关!!!!关了就出错,可能第一个窗口就是对应的ID
好了,那么现在再梳理梳理,具体操作如下
· 当geckodriver.exe没运行,那就先启动,然后调用WebDriver(), 启动浏览器,然后把ID跟URL保存在data文件内
· 那么geckodriver.exe运行,而火狐不在,那么能用WebDriver() 吗?或者是myFirefox? 都不行,会显示错误Message: Session is already started !! 那么Firefox() 呢?肯定行!但有个卵蛋用,不能在它上面操作啊!
所以解决方法就是把已经存在的geckodriver.exe结束程序,然后运行第一步!
· 除了上面的情况,还有可能已经打开的火狐跟geckodriver不是对应的,或者手抖把第一个窗口给关了,那么使用myFirefox 都会报错,所以我使用了try,一旦不行,那么就结束程序,重新打开浏览器
要点
1 使用初始webdriver启动火狐浏览器
2 使用原博主自编的myfirefox 在原浏览器操作
3 pickle 保存字典
4 使用win32api模块 打开程序
5 使用psutil模块检测后台程序,关闭程序
import os,pickle, psutil,win32api,logging from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver import myFirefox class myfox(): '''目的:不需要每次都重新打开浏览器''' def __init__(self): self.file=r'C:\Users\Administrator\AppData\Roaming\Python\Python35\site-packages\selenium\webdriver\firefox\params.data' self.gecko=r'C:\Users\Administrator\AppData\Local\Programs\Python\Python35\Scripts\geckodriver.exe' self.url="http://127.0.0.1:4444" self.capabilities=DesiredCapabilities.FIREFOX #实际就是选定firefox浏览器 def creatfirefox(self): '''先运行geckodriver,启动浏览器,记录ID跟URL,返回driver''' win32api.ShellExecute(0, 'open', self.gecko, '', '', 0) # 先在后台运行geckodriver driver = webdriver.remote.webdriver.WebDriver(command_executor=self.url, desired_capabilities=self.capabilities, ) params={} params["session_id"] = driver.session_id params["server_url"] = driver.command_executor._url with open(self.file,'wb') as f: pickle.dump(params, f) return driver def work(self): '''先判断geckodriver启动没有,没启动就直接运行,启动了先try,不行就删除geckodriver,再次运行friefox''' p_name = [psutil.Process(i).name() for i in psutil.pids()]#罗列进程的程序,如果gecko没有,直接创建启动 if 'geckodriver.exe' not in p_name: driver=self.creatfirefox() else: try: #已经有gecko了,试试能不能在旧的浏览器上执行myfirefox(有可能对应的浏览器已经关闭了) with open(self.file, 'rb') as f: params = pickle.load(f) driver = myFirefox.myWebDriver(service_url=params["server_url"], session_id=params["session_id"]) driver.refresh() except Exception as e: #当不能直接在旧浏览器上操作时,那就删了gecko重新再运行 logging.error('浏览器跟geckodriver不对应!!\n%s'% e) [p.kill() for p in psutil.process_iter() if p.name() == 'geckodriver.exe'] #os.system("taskkill /F /IM geckodriver.exe") 这种方法会有乱码!! driver = self.creatfirefox() return driver driver=myfox().work() driver.get('http://www.baidu.com/')
这是原博主的myfirefox
try: | |
import http.client as http_client | |
except ImportError: | |
import httplib as http_client | |
import socket | |
from selenium.webdriver.firefox.webdriver import WebDriver as Firefox | |
from selenium.webdriver.firefox.remote_connection import FirefoxRemoteConnection | |
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities | |
from selenium.webdriver.remote.remote_connection import RemoteConnection | |
from selenium.webdriver.remote.errorhandler import ErrorHandler | |
from selenium.webdriver.remote.switch_to import SwitchTo | |
from selenium.webdriver.remote.mobile import Mobile | |
from selenium.webdriver.remote.file_detector import FileDetector, LocalFileDetector | |
from selenium.webdriver.remote.command import Command | |
class myWebDriver(Firefox): | |
def __init__(self, capabilities=None, service_url=None, session_id=None): | |
if service_url is None and session_id is None: | |
raise NameError | |
if capabilities is None: | |
capabilities = DesiredCapabilities.FIREFOX.copy() | |
self.capabilities = dict(capabilities) | |
self.w3c = True | |
executor = FirefoxRemoteConnection(remote_server_addr=service_url) | |
self.session_id=session_id | |
self.command_executor = executor | |
self.command_executor.w3c = self.w3c | |
if type(self.command_executor) is bytes or isinstance(self.command_executor, str): | |
self.command_executor = RemoteConnection(self.command_executor, keep_alive=True) | |
self._is_remote = True | |
self.error_handler = ErrorHandler() | |
self._switch_to = SwitchTo(self) | |
self._mobile = Mobile(self) | |
self.file_detector = LocalFileDetector() | |
def quit(self): | |
"""Quits the driver and close every associated window.""" | |
try: | |
self.execute(Command.QUIT) | |
except (http_client.BadStatusLine, socket.error): | |
# Happens if Firefox shutsdown before we've read the response from | |
# the socket. | |
pass |
实际操作
这时因为已经关了火狐,只留下geckodriver没关
成功打开了!!!
然后在这基础上操作
打开百度,搜索python
成功了!!收工!