您现在的位置是:首页 > 技术教程 正文

代码实现对selenium的驱动器WebDrive的配置

admin 阅读: 2024-03-27
后台-插件-广告管理-内容页头部广告(手机)

1.条件

1.使用的浏览器是Microsoft Edge。

2.简述过程(代码实现)

1.pip 安装

2.下载

3.解压

4.运行

3.发现一个报错

1)原因

在给出代码之前,我发现一个报错,很离谱。且听笔者慢慢细说。首先,安装了selenium4.11.2,也配置edge webdriver。在其中一个项目中,解释器是python3.10,运行如下代码

  1. from selenium import webdriver
  2. browser = webdriver.Edge()
  3. browser.get('https://www.baidu.com')

发现报错了,报错的原因,在最后有这样一段话

selenium.common.exceptions.NoSuchDriverException: Message: Unable to obtain driver for MicrosoftEdge using Selenium Manager.; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location

如果去网上搜原因,如下结果

selenium打开浏览器报错成功解决selenium.common.exceptions.NoSuchDriverException: Message: Unable to obtain..._sinnp的博客-CSDN博客

可惜,可以这位大佬的解决不适应于笔者的报错。虽然报错是一样的,但是终究还是不一样,具体情况具体分析。

2)推理

因此笔者把报错全部写出来

  1. Traceback (most recent call last):
  2. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\selenium_manager.py", line 124, in run
  3. stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
  4. AttributeError: 'str' object has no attribute 'decode'. Did you mean: 'encode'?
  5. The above exception was the direct cause of the following exception:
  6. Traceback (most recent call last):
  7. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\driver_finder.py", line 38, in get_path
  8. path = SeleniumManager().driver_location(options) if path is None else path
  9. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\selenium_manager.py", line 90, in driver_location
  10. output = self.run(args)
  11. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\selenium_manager.py", line 129, in run
  12. raise WebDriverException(f"Unsuccessful command executed: {command}") from err
  13. selenium.common.exceptions.WebDriverException: Message: Unsuccessful command executed: C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\windows\selenium-manager.exe --browser MicrosoftEdge --output json
  14. The above exception was the direct cause of the following exception:
  15. Traceback (most recent call last):
  16. File "C:\Users\520\PycharmProjects\pythonProject4\selenium的故事\6.py", line 2, in
  17. browser = webdriver.Edge()
  18. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\edge\webdriver.py", line 45, in __init__
  19. super().__init__(
  20. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\chromium\webdriver.py", line 51, in __init__
  21. self.service.path = DriverFinder.get_path(self.service, options)
  22. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\driver_finder.py", line 41, in get_path
  23. raise NoSuchDriverException(msg) from err
  24. selenium.common.exceptions.NoSuchDriverException: Message: Unable to obtain driver for MicrosoftEdge using Selenium Manager.; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location

从browser = webdriver.Edge()开始。

往下走,走到这里 self.service.path = DriverFinder.get_path(self.service, options),进去看看源代码。再进get_path方法,其中代码如下

  1. @staticmethod
  2. def get_path(service: Service, options: BaseOptions) -> str:
  3. path = service.path
  4. try:
  5. path = SeleniumManager().driver_location(options) if path is None else path
  6. except Exception as err:
  7. msg = f"Unable to obtain driver for {options.capabilities['browserName']} using Selenium Manager."
  8. raise NoSuchDriverException(msg) from err
  9. if path is None or not Path(path).is_file():
  10. raise NoSuchDriverException(f"Unable to locate or obtain driver for {options.capabilities['browserName']}")
  11. return path

可以尝试打印path,第一个path为空,第二个path没有打印出来就报错了。再看报错中的内容,其中有这段话

  1. Traceback (most recent call last):
  2. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\driver_finder.py", line 38, in get_path
  3. path = SeleniumManager().driver_location(options) if path is None else path

也指出这行代码有问题,所以进入这行代码中的driver_location方法,看看其中的内容,再看下一个报错

  1. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\selenium_manager.py", line 89, in driver_location
  2. output = self.run(args)

可以在driver_location方法发现有这行代码,所以猜测这行代码有问题,也可以打印一些变量,比如,args,最后可以确定这个猜测。

因此,进入self.run方法。其中主要代码如下

  1. @staticmethod
  2. def run(args: List[str]) -> dict:
  3. """
  4. Executes the Selenium Manager Binary.
  5. :Args:
  6. - args: the components of the command being executed.
  7. :Returns: The log string containing the driver location.
  8. """
  9. if logger.getEffectiveLevel() == logging.DEBUG:
  10. args.append("--debug")
  11. args.append("--output")
  12. args.append("json")
  13. command = " ".join(args)
  14. logger.debug(f"Executing process: {command}")
  15. try:
  16. if sys.platform == "win32":
  17. completed_proc = subprocess.run(
  18. args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW
  19. )
  20. else:
  21. completed_proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  22. stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
  23. stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
  24. output = json.loads(stdout)
  25. result = output["result"]

再看报错

  1. Traceback (most recent call last):
  2. File "C:\Users\520\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\pythonProject4\lib\site-packages\selenium\webdriver\common\selenium_manager.py", line 123, in run
  3. stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
  4. AttributeError: 'str' object has no attribute 'decode'. Did you mean: 'encode'?

很明显是self.run中的stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")有问题,报错的原因是str没有这个decode属性,确实是没有。

打印一下completed_proc,返回的结果如下

CompletedProcess(args=['C:\\Users\\520\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\pythonProject4\\lib\\site-packages\\selenium\\webdriver\\common\\windows\\selenium-manager.exe', '--browser', 'MicrosoftEdge', '--output', 'json'], returncode=0, stdout='{\n "logs": [\n {\n "level": "INFO",\n "timestamp": 1692601797,\n "message": "Driver path: C:\\\\Users\\\\520\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python310\\\\msedgedriver.exe"\n },\n {\n "level": "INFO",\n "timestamp": 1692601797,\n "message": "Browser path: C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe"\n }\n ],\n "result": {\n "code": 0,\n "message": "C:\\\\Users\\\\520\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python310\\\\msedgedriver.exe",\n "driver_path": "C:\\\\Users\\\\520\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python310\\\\msedgedriver.exe",\n "browser_path": "C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe"\n }\n}', stderr=b'')

返回是个CompletedProcess对象,没错,再次打印completed_proc.stdout,代码如下

  1. {
  2. "logs": [
  3. {
  4. "level": "INFO",
  5. "timestamp": 1692601871,
  6. "message": "Driver path: C:\\Users\\520\\AppData\\Local\\Programs\\Python\\Python310\\msedgedriver.exe"
  7. },
  8. {
  9. "level": "INFO",
  10. "timestamp": 1692601871,
  11. "message": "Browser path: C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
  12. }
  13. ],
  14. "result": {
  15. "code": 0,
  16. "message": "C:\\Users\\520\\AppData\\Local\\Programs\\Python\\Python310\\msedgedriver.exe",
  17. "driver_path": "C:\\Users\\520\\AppData\\Local\\Programs\\Python\\Python310\\msedgedriver.exe",
  18. "browser_path": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
  19. }
  20. }

这个结果是字符串,很明显,str是没有decode属性。以此这个才是报错的根本原因。

3)思考

为什么print(completed_proc.stdout),打印的对象的类型是str,很明显根据代码的理解,应该打印是个bytes类型,才会有decode。可以去官网看看解释,如下图。

 返回的是字节序列或者字符串,这个或有意思

因为笔者的电脑上有·python310和python311,但笔者使用python311作为编辑器创建的项目,运行代码没有报错,而且打印的completed_proc.stdout是字节序列,因此没有报错。

为什么同样的代码,在不用python环境中运行结果不一样,至于原因我也不知道。

4)修改

既然completed_proc.stdout是字符串,那么直接注释掉decode,代码如下

  1. stdout=completed_proc.stdout
  2. # stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
  3. # stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
  4. output = json.loads(stdout)

运行没有报错。

4.正文

上面的报错只是个插曲。现在要实现真正的配置了,首先我看到这位大佬的代码

https://blog.csdn.net/weixin_49958813/article/details/125580029

写得好,于是我就有个想法,这位大佬的代码中只有更新。感觉不完善。

因此,代码如下:

  1. import time
  2. from xml.dom import minidom as xml
  3. from xml.dom.minicompat import NodeList
  4. from xml.dom.minidom import Element
  5. from tqdm import tqdm
  6. import requests
  7. import re
  8. import getpass
  9. from zipfile import ZipFile
  10. from logging import StreamHandler,getLogger,DEBUG
  11. from colorlog import ColoredFormatter
  12. import sys
  13. from pathlib import Path
  14. import subprocess
  15. class WebDriver:
  16. def __init__(self,output_path,zip_file=None):
  17. self.has_zip=False
  18. self.dom = xml.parse(r'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.VisualElementsManifest.xml')
  19. self.logger=self.log()
  20. self.output_path=output_path
  21. self.zip_file='C:/Users/'+self.user+'/Downloads/edgedriver.zip'
  22. def log(self):
  23. """
  24. 日志的配置
  25. :return:
  26. """
  27. colors = {
  28. 'DEBUG': 'bold_red',
  29. 'INFO': 'bold_blue',
  30. 'WARNING': 'bold_yellow',
  31. }
  32. logger = getLogger(__file__)
  33. stream_handler = StreamHandler()
  34. logger.setLevel(DEBUG)
  35. color_formatter = ColoredFormatter(
  36. fmt='%(log_color)s %(asctime)s %(filename)s %(funcName)s line:%(lineno)d %(levelname)s : %(message)s',
  37. datefmt='%Y-%m-%d %H:%M:%S',
  38. log_colors=colors
  39. )
  40. stream_handler.setFormatter(color_formatter)
  41. logger.addHandler(stream_handler)
  42. return logger
  43. def decompression(self,delete_zip=True):
  44. """
  45. 解压
  46. :return:
  47. """
  48. if self.has_zip:
  49. zip=ZipFile(self.zip_file)
  50. zip.extractall(self.output_path)
  51. zip.close()
  52. self.logger.info(f'解压成功,webdriver的路径为{self.output_path}')
  53. if delete_zip:
  54. Path(self.zip_file).unlink()
  55. self.logger.debug('删除webdriver.zip文件')
  56. else:
  57. self.logger.warning('没有发现webdriver.zip文件')
  58. def download(self):
  59. """
  60. 下载webriver
  61. :return:
  62. """
  63. if Path(self.zip_file).exists():
  64. self.has_zip=True
  65. self.logger.info('找到webdriver.zip文件,即将积压')
  66. return
  67. self.logger.info('没有发现webdriver.zip,即将下载!')
  68. version=self.get_version
  69. url = 'https://msedgedriver.azureedge.net/' + version + '/edgedriver_win64.zip'
  70. self.logger.info('正在发送请求...')
  71. response=requests.get(url=url)
  72. self.logger.info('请求成功')
  73. total=response.headers['Content-Length']
  74. total = int(total)
  75. self.logger.info('文件大小为 '+str(total)+' B')
  76. with open(self.zip_file,'wb') as f:
  77. with tqdm(total=total,desc="webdriver下载") as p:
  78. for i in response.iter_content(1024*100):
  79. f.write(i)
  80. time.sleep(0.2)
  81. p.update(1024*100)
  82. self.logger.debug('webdriver.zip 下载完成!!')
  83. self.has_zip=True
  84. def __display(self):
  85. """
  86. 安装、运行、更新
  87. :return:
  88. """
  89. try:
  90. from selenium import webdriver
  91. from selenium.common.exceptions import SessionNotCreatedException,NoSuchDriverException
  92. self.logger.info('selenium存在,即将打开edge')
  93. browser = webdriver.Edge()
  94. browser.get('https://www.baidu.com')
  95. browser.quit()
  96. self.logger.info('edge关闭,运行成功')
  97. except ModuleNotFoundError as e:
  98. self.logger.warning('selenium 不存在,即将安装...')
  99. cmd='pip install -i https://pypi.tuna.tsinghua.edu.cn/simple selenium'
  100. result=subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
  101. self.logger.debug('安装过程:\n'+result.stdout)
  102. self.logger.info('下载selenium成功,')
  103. self.logger.info('等待安装..')
  104. time.sleep(10)
  105. self.__display()
  106. except SessionNotCreatedException as e:
  107. self.logger.warning('需要更新webdriver!!!!')
  108. self.download()
  109. self.decompression()
  110. self.logger.info('更新成功')
  111. self.logger.info('再次运行seleniun')
  112. self.__display()
  113. def up_to_date(self):
  114. """
  115. 更新webdriver版本
  116. :return:
  117. """
  118. @property
  119. def get_version(self):
  120. """
  121. 得到edge的版本
  122. :return:
  123. """
  124. dom = self.dom.documentElement
  125. nodeList:NodeList = dom.getElementsByTagName('VisualElements')
  126. element:Element=nodeList[0]
  127. text=element.toxml()
  128. version='.'.join(re.findall('(\d+)\.(\d+)\.(\d+)\.(\d+)', text)[0])
  129. return version
  130. @property
  131. def user(self):
  132. """
  133. 得到当前的使用者
  134. :return:
  135. """
  136. return getpass.getuser()
  137. def install(self):
  138. self.__display()
  139. if __name__ == '__main__':
  140. webdriver=WebDriver(output_path=sys.path[6])
  141. webdriver.install()

这个代码,可以直接安装selenium和webdriver,并且可以更新。如果遇到上面的报错,如果报错的内容是一样的,那么可以按照其中的内容修改,如果有其他报错,可看个人具体分析。

对于其他浏览器,查不多。

5.结果

 笔者发现好像第一次运行,会自动下载msedgedriver.exe,selenium变高级了,以前都没有。笔者的路径如下

C:/Users/520/.cache/selenium/msedgedriver/win64/115.0.1901.203/msedgedriver.exe

 

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索
排行榜