如何启动Chrome进程并等待其终止

3
我正在尝试启动一个Chrome进程(在应用程序模式下),然后等待用户关闭它。
问题:Chrome进程不会阻塞。好像在启动进程时,Chrome会生成另一个进程并从原始进程返回。为了我的软件包能够正常工作,我需要能够确定Chrome应用程序窗口何时关闭。
我知道可以使用selenium来解决这个问题,但我非常希望让我的软件包尽可能轻量化。
据我所知,没有任何标志可以传递给Chrome可执行文件以强制其阻塞。
我的代码如下,将成功启动Chrome窗口,但随即立即返回。打印的调试信息显示该进程立即完成。
package main

import (
    "fmt"
    "os/exec"
    "runtime"
)

func openChrome(url string, appMode bool) error {
    var urlArgs []string
    if appMode {
        urlArgs = []string{"--app=" + url}
    } else {
        urlArgs = []string{"--chrome-frame", url}
    }

    switch runtime.GOOS {
    case "windows":
        var chrome string
        if runtime.GOARCH == "386" {
            chrome = "C:/Program Files/Google/Chrome/Application/chrome.exe"
        } else {
            chrome = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
        }
        cmd := exec.Command(chrome, urlArgs...)
        err := cmd.Run()
        fmt.Println(cmd.ProcessState.Pid())
        fmt.Println(cmd.ProcessState.Exited())
        fmt.Println(cmd.ProcessState.Success())
        fmt.Println(cmd.Process.Pid)
        if err != nil {
            return err
        }

    case "darwin":
        urlArgs = append([]string{"-b", "com.google.Chrome", "--args"}, urlArgs...)
        var cmd *exec.Cmd
        if runtime.GOARCH == "386" {
            cmd = exec.Command("open", urlArgs...)
        } else {
            cmd = exec.Command("open", urlArgs...)
        }
        err := cmd.Start()
        if err != nil {
            return err
        }

    default:
        cmd := exec.Command("google-chrome", urlArgs...)
        err := cmd.Start()
        if err != nil {
            return err
        }
    }

    return nil
}

func main() {
    openChrome("https://stackoverflow.com/", true)
}

通过命令终端启动Chrome可执行文件会产生相同的结果;窗口会按预期打开和操作,但命令的执行不会被阻塞:
C:\WINDOWS\system32>"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"

C:\WINDOWS\system32>

那么如何启动Chrome进程并检测实际生成的进程何时终止?


1
Chrome在Windows上做一些不寻常的事情,而像它何时“启动”或“终止”这样的概念会给你带来麻烦;实际上,它是通过一个包装器启动的,该包装器分离出实际的浏览器(作为更新过程的一部分),同时还运行多个浏览器进程,此外,即使关闭了所有浏览器标签,它也可以在后台保持长时间运行的进程。因此,基于Chrome何时“退出”来构建任何逻辑可能是徒劳的。 - undefined
1个回答

2

在处理类似项目时,我也曾遇到你的情况,并一直努力解决它,最终成功了,而且没有使用任何外部代码。

这是一个 Go 程序,启动一个新的 Chrome 浏览器进程,并在新窗口中打开 URL "https://google.dk/"。 (如果您有本地 Web 服务器,则还可以使用 http://localhost:12345 等)

对于此解决方案,重要的是要使用 --user-data-dir,否则它将无法附加到进程上。 --user-data-dir 将文件安装在所选位置内(Chrome 文件)。 在此示例中,我选择了 Chrome localappdata 位置。 注意:当使用时,每个应用程序的大小不断变化,在 16mb 到 100mb 之间。

该程序设置信号处理程序,以便在接收到 SIGINT 或 SIGTERM 信号时优雅地关闭程序。 接收到信号后,该程序将终止 Chrome 进程并退出。 使用 exec.Command 函数启动 Chrome 进程,该函数创建并返回 *exec.Cmd 结构体。

调用 cmd.Start 函数以启动 Chrome 进程。然后,程序设置信号处理程序以监听 SIGINT 和 SIGTERM 信号,并启动 goroutine 处理这些信号。 接收到信号后,goroutine 将终止 Chrome 进程并退出程序。 最后,程序使用 cmd.Wait 函数等待 Chrome 进程完成。

package main

import (
    "os"
    "os/exec"
    "os/signal"
    "syscall"
)

func main() {
    // Start a new Chrome process
    path := "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
    //path = "chrome.exe"
    cmd := exec.Command(path, "--app=https://google.dk/", "--user-data-dir="+os.Getenv("localappdata")+"/Google/Chrome/InstalledApps/NewCompanyName/NewProjectName")
    cmd.Start()

    // Set up a signal handler to gracefully shutdown the program
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
    go func() {
        <-sigs
        cmd.Process.Kill()
        os.Exit(0)
    }()

    // Wait for the process to finish
    cmd.Wait()
}

我希望这能对你有所帮助,它完美地适用于我的项目,请告诉我。 这个解决方案仅适用于Windows,但你也可以为Linux添加一个启动器,它更简单并且使用的是Chromium。
注意:我还没有找到一种解决方案,当程序被任务管理器杀死后,Chrome前端“应用程序”仍在运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接