【问题标题】:Find PID of browser process launched by Selenium WebDriver查找 Selenium WebDriver 启动的浏览器进程的 PID
【发布时间】:2013-09-12 05:57:05
【问题描述】:

在 C# 中,我启动了一个浏览器进行测试,我想获取 PID,以便在我的 winforms 应用程序上我可以杀死任何剩余的已启动的幽灵进程

driver = new FirefoxDriver();

如何获取 PID?

【问题讨论】:

    标签: c# selenium webdriver selenium-webdriver pid


    【解决方案1】:
            int _processId = -1;
    
            var cService = ChromeDriverService.CreateDefaultService();
            cService.HideCommandPromptWindow = true;
    
            // Optional
            var options = new ChromeOptions();
            options.AddArgument("--headless");
    
            IWebDriver webdriver = new ChromeDriver(cService, options);
            _processId = cService.ProcessId;
    
            Console.Write("Process Id : " + _processId);
    
            webdriver.Navigate().GoToUrl("https://www.google.lk");
    
            webdriver.Close();
            webdriver.Quit();
            webdriver.Dispose();
    

    【讨论】:

    • 这应该是公认的答案。 DriverService 类是提供信息(PID)以检索当前打开的浏览器实例的进程的类。非常有用,在使用浏览器的多个实例时也是如此。这对我帮助很大。感谢分享这个答案!
    • 这怎么只有一张赞成票!这是唯一需要的答案。
    • 我同意 - 这是最好的答案。刚刚投了赞成票!
    • 如果我错了当然纠正我,这只会获取 DriverServer 进程的 PID,而不是与之关联的浏览器。
    • 是的,这会返回 DriverService 进程 ID - 属性摘要明确指出:“获取正在运行的驱动程序服务可执行文件的进程 ID” - 答案具有误导性
    【解决方案2】:
    var g = Guid.NewGuid();
    driver.Navigate().GoToUrl("about:blank");
    driver.ExecuteScript($"document.title = '{g}'");
    var pid = Process.GetProcessesByName("firefox").First(p => 
    p.MainWindowTitle.Contains(g.ToString()));
    

    【讨论】:

    • 简单解释一下答案
    • 您可以简单地通过javascript设置页面标题并循环遍历所有浏览器实例,找到您之前设置的唯一标题并找到pid
    • 非常感谢,这对我有用,只需在设置文档标题后添加Thread.Sleep(TimeSpan.FromSeconds(3));
    【解决方案3】:

    看起来更像是一个 C# 问题,而不是特定于 Selenium 的问题。

    这是一个非常古老的非确定性答案,如果您想尝试一下,请重新考虑。

    我的逻辑是您使用Process.GetProcessesByName Method 获取名称为firefox 的所有进程PID,然后启动FirefoxDriver,然后再次获取进程的PID,比较它们以获得刚刚启动的PID。在这种情况下,特定驱动程序启动了多少进程并不重要(例如,Chrome 启动多个,Firefox 仅启动一个)。

    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium.Firefox;
    
    namespace TestProcess {
        [TestClass]
        public class UnitTest1 {
            [TestMethod]
            public void TestMethod1() {
                IEnumerable<int> pidsBefore = Process.GetProcessesByName("firefox").Select(p => p.Id);
    
                FirefoxDriver driver = new FirefoxDriver();
                IEnumerable<int> pidsAfter = Process.GetProcessesByName("firefox").Select(p => p.Id);
    
                IEnumerable<int> newFirefoxPids = pidsAfter.Except(pidsBefore);
    
                // do some stuff with PID if you want to kill them, do the following
                foreach (int pid in newFirefoxPids) {
                    Process.GetProcessById(pid).Kill();
                }
            }
        }
    }
    

    【讨论】:

    • 不确定。其他并行运行的测试可能会在两个“GetProcessesByName”调用之间创建进程
    【解决方案4】:

    我没有尝试使用 Firefox,但这是使用 Chrome 的方式:

            // creating a driver service
            var driverService = ChromeDriverService.CreateDefaultService();
            _driver = new ChromeDriver(driverService);
    
            //create list of process id
            var driverProcessIds = new List<int> { driverService.ProcessId };
    
            //Get all the childs generated by the driver like conhost, chrome.exe...
            var mos = new System.Management.ManagementObjectSearcher($"Select * From Win32_Process Where ParentProcessID={driverService.ProcessId}");
            foreach (var mo in mos.Get())
            {
                var pid = Convert.ToInt32(mo["ProcessID"]);
                driverProcessIds.Add(pid);
            }
    
            //Kill all
            foreach (var id in driverProcessIds)
            {
                System.Diagnostics.Process.GetProcessById(id).Kill();
            }
    

    【讨论】:

      【解决方案5】:

      尝试使用父进程id:

        public static Process GetWindowHandleByDriverId(int driverId)
          {
              var processes = Process.GetProcessesByName("chrome")
                  .Where(_ => !_.MainWindowHandle.Equals(IntPtr.Zero));
              foreach (var process in processes)
              {
                  var parentId = GetParentProcess(process.Id);
                  if (parentId == driverId)
                  {
                      return process;
                  }
      
              }
              return null;
          }
      
          private static int GetParentProcess(int Id)
          {
              int parentPid = 0;
              using (ManagementObject mo = new ManagementObject($"win32_process.handle='{Id}'"))
              {
                  mo.Get();
                  parentPid = Convert.ToInt32(mo["ParentProcessId"]);
              }
              return parentPid;
          }
      

      【讨论】:

      • 这似乎比公认的答案更好,因为它不是查找浏览器 pid 的蛮力方法。此外,WebDriver 现在具有 CurrentWindowHandle 属性,因此您甚至不需要在 PC 上查找所有 Chrome。
      • 这将杀死所有 chrome 实例,即使不是测试或者是否是另一个并行运行的测试...
      • 'CurrentWindowHandle' 属性是 String 类型,该值一旦转换为 Int64,在尝试将其传递给 IntPtr/UIntPtr 构造函数时将引发算术溢出异常。因此该句柄似乎不是 Win32 窗口句柄,因此它无助于查找进程。至少对于我的 Firefox。
      【解决方案6】:

      要获取进程 ID 并尝试杀死它,您可以使用 Process 类。感兴趣的方法有:

      • GetProcessesByName
      • 杀死

      通过名称解析进程后,您可以查询它的属性:process.Id 获取 id。请记住,某些浏览器,例如 Google Chrome 有多个正在运行的进程(Chrome 每个选项卡至少有一个正在运行的进程)。所以如果你想杀死它,你需要杀死所有的进程。

      【讨论】:

        【解决方案7】:

        开箱即用,selenium 不会公开驱动程序进程 ID 或浏览器 hwnd,但这是可能的。 下面是获取hwnd的逻辑

        • 驱动初始化时,获取hub的url并提取端口号
        • 从端口号中,找到正在使用该端口进行监听的进程ID,即。驱动程序PID
        • 导航后,从 iexplore 的所有实例中查找父 PID 与驱动程序的 pid 匹配,即浏览器 pid。
        • 获取浏览器 pid 的 Hwnd 找到浏览器 hwnd 后,您可以使用 win32 api 将 selenium 带到前台。

        这里不可能发布完整代码,将浏览器放在前面的完整工作解决方案(C#)在我的博客上

        http://www.pixytech.com/rajnish/2016/09/selenium-webdriver-get-browser-hwnd/

        【讨论】:

        • 请在这里分享代码,因为链接不再有效
        【解决方案8】:

        你可以给启动窗口起一个名字,并通过名字找到进程

        Driver = new TouchChromeDriver(service, options, TimeSpan.FromSeconds(30));
                Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);
        
                var conts = GetHashCode();
                (Driver as IJavaScriptExecutor).ExecuteScript($"document.title = '{conts}'");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                var pc = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle == $"{conts} - Google Chrome");
                if (pc != null)
                    pidChromeWindow = pc.Id;
        
                pidChromeDriver = service.ProcessId;
        

        【讨论】:

        • 你好 Kotyara!感谢您提供这个问题的答案。我看到你是新来的,所以我会提供一些建议 - 如果对提议的解决方案为什么以及如何工作有一些解释,人们更有可能接受答案并投票。目前这段代码 sn-p 可以工作,但使用它的人不一定能理解——这可能导致调试和故障查找困难。
        • 嗨@TheHitchenator 谢谢,我以后会记住这一点
        猜你喜欢
        • 2012-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-07
        • 2021-05-16
        • 2016-11-08
        • 1970-01-01
        相关资源
        最近更新 更多