微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

java – 如何确定浏览器关闭的时间?

我正在使用Selenium Webdriver自动化网站(填写表格并点击)以节省用户的时间.我遇到了一个恼人的问题:

Selenium does not seem to support any event listeners for the browsers
themselves. When the browser is closed driver.quit() is not called
and an unusable driver remains which throws varIoUs exceptions. Having
no way to kNow when the browser is closed, I cannot create a new
driver instance.

我需要的是在浏览器关闭通知我的程序的一些方法.

用户可能因为任何破坏我程序的原因而关闭浏览器.如果不重新启动应用程序,用户将无法再次运行自动化任务.知道浏览器何时关闭将允许我调用driver.quit()并在用户想要再次运行时创建一个新的驱动程序实例.

当浏览器死亡时,抛出的错误在浏览器中并不统一,这个问题变得更加复杂.使用Firefox,我可能会使用Chrome NullPointer和WebDriverExceptions获得UnreachablebrowserException.

为了澄清,我知道如何关闭驱动程序和浏览器,但我不知道它们何时被外部源关闭.这可以在Selenium 2中以跨浏览器的方式完成(如果是,如何)或者我是否需要找到另一种方式(如另一个库)来观看浏览器窗口?

解决方法:

我已经在Selenium中已经包含的JNA(Java Native Access)3.4的帮助下解决了这个问题.我的目标平台仅限Windows,但制作这种跨平台不需要太多工作.我必须做以下事情:

>在启动WebDriver之前收集所有浏览器进程ID(可以使用tasklist或powershell Get-Process等实用程序完成).如果您确定在启动应用程序之前没有运行任何浏览器进程,则可以省略此步骤.
>初始化驱动程序.
>再次收集所有浏览器进程,然后取两者之间的差异.
>使用LittlePanda评论链接代码作为基础,我们可以在新线程上创建一个观察者服务.当所有进程都关闭时,这将提醒所有侦听器.
> Kernel32.INSTANCE.OpenProcess方法允许我们从pid创建HANDLE对象.
>使用这些句柄,我们可以让线程等到所有进程都使用Kernel32.INSTANCE.WaitForMultipleObjects方法发出信号.

这是我使用的代码,以便它可以帮助其他人:

public void startAutomation() throws IOException { 
        Set<Integer> pidsBefore = getbrowserPIDs(browserType);
        automator.initDriver(browserType); //calls new ChromeDriver() for example
        Set<Integer> pidsAfter = getbrowserPIDs(browserType);
        pidsAfter.removeAll(pidsBefore);

        ProcessGroupExitWatcher watcher = new ProcessGroupExitWatcher(pidsAfter);
        watcher.addProcessExitListener(new ProcessExitListener() {
            @Override
            public void processFinished() {
                if (automator != null) {
                    automator.closeDriver(); //calls driver.quit()
                    automator = null;
                }
            }
        });
        watcher.start();
        //do webdriver stuff
}

private Set<Integer> getbrowserPIDs(String browserType) throws IOException {
    Set<Integer> processIds = new HashSet<Integer>();

    //powershell was convenient, tasklist is probably safer but requires more parsing
    String cmd = "powershell get-process " + browserType + " | foreach { $_.id }";
    Process processes = Runtime.getRuntime().exec(cmd);
    processes.getoutputStream().close(); //otherwise powershell hangs
    BufferedReader input = new BufferedReader(new InputStreamReader(processes.getInputStream()));
    String line;

    while ((line = input.readLine()) != null) {
        processIds.add(Integer.parseInt(line));
    }
    input.close();

    return processIds;
}

以及观察者的代码

/**
* Takes a <code>Set</code> of Process IDs and notifies all listeners when all
* of them have exited.<br>
*/
public class ProcessGroupExitWatcher extends Thread {
    private List<HANDLE> processHandles;
    private List<ProcessExitListener> listeners = new ArrayList<ProcessExitListener>();

    /**
     * Initializes the object and takes a set of pids and creates a list of
     * <CODE>HANDLE</CODE>s from them.
     *
     * @param processIds
     *           process id numbers of the processes to watch.
     * @see HANDLE
     */
    public ProcessGroupExitWatcher(Set<Integer> processIds) {
        processHandles = new ArrayList<HANDLE>(processIds.size());
        //create Handles from the process ids
        for (Integer pid : processIds) {
            processHandles.add(Kernel32.INSTANCE.OpenProcess(Kernel32.SYNCHRONIZE, false, pid)); //synchronize must be used
        }
    }

    public void run() {
        //blocks the thread until all handles are signaled
        Kernel32.INSTANCE.WaitForMultipleObjects(processHandles.size(), processHandles.toArray(new HANDLE[processHandles.size()]), true,
            Kernel32.INFINITE);
       for (ProcessExitListener listener : listeners) {
            listener.processFinished();
       }
    }

    /**
     * Adds the listener to the list of listeners who will be notified when all
     * processes have exited.
     *
     * @param listener
     */
     public void addProcessExitListener(ProcessExitListener listener) {
         listeners.add(listener);
     }

    /**
     * Removes the listener.
     * 
     * @param listener
     */
    public void removeProcessExitListener(ProcessExitListener listener) {
         listeners.remove(listener);
    }
}

注意:以这种方式使用powershell时,将执行用户配置文件脚本.这可能会产生意外的输出,从而破坏了上述代码.因此,建议使用任务列表.

原文地址:https://codeday.me/bug/20190623/1274856.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐