
解决 Selenium 自动化中的常见疑难杂症
这里记录一些关于 Selenium的常用操作和疑难杂症。
有一些细节的知识点就不重复介绍了,因为之前的文章中都有!
如果对本文中的知识点有疑问的,可以先阅读我以前分享的文章!
知识点📖📖
| 模块 | 链接 | 作用 | 
|---|---|---|
| selenium | https://www.selenium.dev/zh-cn/documentation/ | 支持 web 浏览器自动化的一系列工具和库的综合项目 | 
如果有看不懂的地方,可以结合我以前的文章一起看。
TodoList:
- 使用crx扩展插件进行代理修改(后续更新
- ...
初始化webdriver
- 
ChromeService 是一个Service类,负责启动和停止 chromedriver。这个进程是运行自动化脚本的基础。
- 
webdriver-manager 可以自动下载和管理 WebDriver 二进制文件,用于自动管理 webdriver驱动
            
            
              py
              
              
            
          
          from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
def init_driver(options=None) -> webdriver.Chrome:
    """
    初始化浏览器驱动.
    Args:
        options(Options): chrome配置选项
    Returns:
        driver(WebDriver): 浏览器驱动对象
    """
    return webdriver.Chrome(
        service=ChromeService(ChromeDriverManager().install()),
        options=options
    )使用代理
- 使用crx扩展插件进行代理修改(后续更新
            
            
              py
              
              
            
          
          from selenium import webdriver
from selenium.webdriver.chrome.options import Options
if __name__ == '__main__':
    options = Options()
    proxy = "http://127.0.0.1:9527"
    options.add_argument(f'--proxy-server={proxy}')
    driver = init_driver(options=options)
    driver.get('https://www.bilibili.com/')运行结果如下:
- 可以请下的看到,所有请求的Remote Address都是127.0.0.1:7890

指定 Chrome 浏览器端口
启动浏览器
代码贴心的给出多项selenium 优化选项,根据需要来选择~
            
            
              py
              
              
            
          
          import subprocess
def start_chrome(browser_path, commands_list=None) -> None:
    """
    启动浏览器。
    Args:
        browser_path(str): 浏览器安装的路径
        commands_list(List[str]): 启动浏览器的命令行参数,默认为None
    Returns:
        None
    """
    commands = [browser_path]
    commands.extend(commands_list)
    # 启动浏览器
    subprocess.Popen(commands)
if __name__ == '__main__':
    # 设置浏览器的路径和启动参数
    path = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
    port = 9527
    cmd_map = {
        '指定浏览器配置': r'--user-data-dir=F:\selenium',
        '指定远程调试端口': '--remote-debugging-port={}'.format(port),
        # '无头模式': '--headless',
        # '无沙盒模式': '--no-sandbox',
        # '指定页面加载策略': '--no-sandbox',
        # '禁用弹出拦': '--disable-popup-blocking',
        # '禁用图片加载': '--blink-settings=imagesEnabled=false',
        # '禁用GPU硬件加速': '--disable-gpu',
        # '禁用js': True,
    }
    start_chrome(path, list(cmd_map.values()))连接浏览器
注意!这里
Selenium WebDriver将附加到一个已经运行的 Chrome 实例上,而不是启动一个新的浏览器实例。这意味着 WebDriver 将使用现有浏览器实例的设置,包括网络和代理配置。即无法使用上处的方法进行指定代理。
具体步骤如下:
- 导入 Selenium 相关模块。
- 创建 Chrome 浏览器的选项(Options)对象,并将调试端口设置为 "127.0.0.1:9527",这意味着浏览器将连接到 Chrome 浏览器的开发者工具(DevTools)端口,以便进行远程调试。
- 初始化 Chrome WebDriver,将上述选项传递给 WebDriver。
- 打开 Chrome 浏览器,并连接到指定的调试端口。
            
            
              py
              
              
            
          
          from selenium import webdriver
from selenium.webdriver.chrome.options import Options
if __name__ == '__main__':
    options = Options()
    options.add_experimental_option("debuggerAddress", "127.0.0.1:9527")
    driver = webdriver.Chrome(options=options)
    url = 'https://www.bilibili.com'
    driver.get(url)
    print(driver.title)	# 哔哩哔哩 (゜-゜)つロ 干杯~-bilibili无法连接指定端口 Chrome浏览器
在命令行中启动 Chrome 浏览器时候,不要使用
--headless!!!会导致Selenium无法连接。
问题复现
一般的,我们使用以下命令去指定chrome浏览器端口,--headless 可能是有意或无意添加的
            
            
              bash
              
              
            
          
          [
	"--remote-debugging-port=9527",
	"--headless"
]
# 或者 命令行
chrome.exe --remote-debugging-port=9527 --user-data-dir="F:\selenium\AutomationProfile" --headless这个时候,会发现,没有打开任何窗口。因为是无头模式!!!
在命令行执行 netstat -ano | findstr :9527,如下图所示:

现在你去访问:http://127.0.0.1:9527/json/version,可以看到下图所示:
- 这表明远程调试接口是开启的

但如果我们使用以下代码去连接端口为 9527 的浏览器,则会报错!!!
            
            
              py
              
              
            
          
          options.add_experimental_option("debuggerAddress", "127.0.0.1:9527")
driver = webdriver.Chrome(options=options)如果没有意外!则会抛出以下异常:
            
            
              bash
              
              
            
          
          selenium.common.exceptions.WebDriverException: Message: unknown error: cannot connect to chrome at 127.0.0.1:9527
from unknown error: unable to discover open pages这个问题其实是不应该发生的!!!
因为 无头模式 可能改变了与调试接口的交互方式或者其他相关配置,从而影响到了 Selenium 的连接。
如何解决
杀死全部的9527端口的进程,并注意在命令行中启动 Chrome 浏览器时候,不要使用
--headless。
这个命令的目的是终止在指定端口上运行的进程,以便释放端口并停止与之相关的应用程序。请注意,使用 taskkill 命令会强制终止进程,因此要小心使用,以免意外终止重要的进程。
这个时候,我们需要在命令行执行以下命令,作用是终止在端口 9527 上运行的进程。(详细解释看下面)
- 
netstat -ano | findstr :9527:这部分命令用于查找在端口 9527 上运行的进程的 PID。netstat列出了所有网络连接,而findstr :9527过滤出包含端口 9527 的行,显示它们的 PID。
- 
for /f "tokens=5" %a in (...) do ...:for命令用于处理上述命令的输出。它将提取netstat输出中的 PID,并将其存储在%a变量中。
- 
taskkill /F /PID %a:一旦 PID 被提取并存储在%a中,taskkill命令将使用这个 PID 终止相关进程。
            
            
              bash
              
              
            
          
          for /f "tokens=5" %a in ('netstat -ano ^| findstr :9527') do taskkill /F /PID %akill PID
            
            
              bash
              
              
            
          
          for /f "tokens=5" %a in ('netstat -ano ^| findstr :9527') do taskkill /F /PID %a这段命令是一个用于在 Windows 命令提示符中终止在特定端口(9527)上运行的进程的复合命令。下面是这个命令的解释:
- 
for /f "tokens=5" %a in ('netstat -ano ^| findstr :9527') do ...:这部分命令使用for循环来处理输出结果。它的作用是执行以下操作:- for /f:这表示使用- for命令来进行循环迭代。
- "tokens=5":这指定了循环要提取的令牌(token),在这里我们提取第五个令牌。在这个上下文中,第五个令牌是- netstat输出中的进程标识符(PID)。
- %a:这是一个变量,用于存储从- netstat命令输出中提取的 PID。
 
- 
('netstat -ano ^| findstr :9527'):这部分是在for命令内部的命令,它会产生一系列数字,这些数字代表在端口 9527 上运行的进程的 PID。它的工作步骤如下:- netstat -ano:这部分执行- netstat命令,用于列出所有活动网络连接及其相关信息。- -ano标志告诉- netstat显示所有连接的详细信息,并显示每个连接的 PID。
- ^|:这是一个管道符号- |,用于将- netstat的输出传递给下一个命令,即- findstr。
- findstr :9527:这部分命令用于过滤- netstat输出,只保留包含端口号- 9527的行,这些行包括了我们关心的进程信息。
 
- 
taskkill /F /PID %a:一旦for循环提取了netstat输出中的 PID(存储在%a中),这部分命令使用taskkill命令来终止这些进程。具体地:- taskkill:这是用于终止进程的命令。
- /F:这是- taskkill的标志,表示要强制终止进程,即无需用户确认。
- /PID %a:这是指定要终止的进程的 PID,其中- %a包含了在- for循环中提取的 PID。
 
因此,整个命令的作用是找到所有在端口 9527 上运行的进程的 PID,然后使用 taskkill 命令将它们终止掉。这可以帮助我们清除特定端口上的活动进程。需要注意使用此命令,以免终止不必要的进程。
未完待续
将持续更新,常见的Selenium的操作 和 疑难杂症等!