Exemple #1
0
        private static async Task <RevisionInfo> DownloadChromiumAsync(BrowserFetcherOptions options)
        {
            var fetcher = Puppeteer.CreateBrowserFetcher(options);

            if (fetcher.LocalRevisions().Contains(BrowserFetcher.DefaultRevision))
            {
                return(fetcher.RevisionInfo(BrowserFetcher.DefaultRevision));
            }

            try
            {
                Logger?.Debug($"Downloading Chromium r{BrowserFetcher.DefaultRevision}...");

                var revisionInfo = await fetcher.DownloadAsync(BrowserFetcher.DefaultRevision);

                Logger?.Debug($"Chromium downloaded to {revisionInfo.FolderPath}");

                return(revisionInfo);
            }
            catch (Exception ex)
            {
                Logger?.Error($"ERROR: Failed to download Chromium r{BrowserFetcher.DefaultRevision}!)");
                Logger?.Error(ex.Message);
            }

            return(null);
        }
Exemple #2
0
        public async Task ShouldDownloadAndExtractLinuxBinary()
        {
            var downloadsFolder = Path.Combine(Directory.GetCurrentDirectory(), ".test-chromium");
            var browserFetcher  = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions
            {
                Platform = Platform.Linux,
                Path     = downloadsFolder,
                Host     = TestConstants.ServerUrl
            });
            var revisionInfo = browserFetcher.RevisionInfo(123456);

            Server.SetRedirect(revisionInfo.Url.Substring(TestConstants.ServerUrl.Length), "/chromium-linux.zip");
            Assert.False(revisionInfo.Local);
            Assert.Equal(Platform.Linux, revisionInfo.Platform);
            Assert.False(await browserFetcher.CanDownloadAsync(100000));
            Assert.True(await browserFetcher.CanDownloadAsync(123456));

            revisionInfo = await browserFetcher.DownloadAsync(123456);

            Assert.True(revisionInfo.Local);
            Assert.Equal("LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));
            Assert.Equal(new[] { 123456 }, browserFetcher.LocalRevisions());
            browserFetcher.Remove(123456);
            Assert.Empty(browserFetcher.LocalRevisions());

            new DirectoryInfo(downloadsFolder).Delete(true);
        }
Exemple #3
0
        public async void accessSite()
        {
            BrowserFetcherOptions bo = new BrowserFetcherOptions();
            var browserFetcher       = Puppeteer.CreateBrowserFetcher(bo);
            var revisionInfo         = browserFetcher.RevisionInfo(BrowserFetcher.DefaultRevision);

            if (browserFetcher.LocalRevisions().Count() == 0)
            {
                revisionInfo = await browserFetcher.DownloadAsync(BrowserFetcher.DefaultRevision);
            }

            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                ExecutablePath = revisionInfo.ExecutablePath,
                Headless       = false
            });

            var page = await browser.NewPageAsync();//gnb_login_button0

            await page.GoToAsync("https://www.jejuair.net/jejuair/kr/main.do");

            await page.WaitForSelectorAsync("button.gnb_login_button0");

            await page.ClickAsync("button.gnb_login_button0");
        }
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation($"{nameof( PdfTestFunction )} function processed a request.");

            // TODO: Move browserFetcher to startUp class
            Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions( ));
            await new BrowserFetcher( ).DownloadAsync(BrowserFetcher.DefaultRevision);

            log.LogInformation($"{nameof( PdfTestFunction )} downloaded browser version:{BrowserFetcher.DefaultRevision}.");

            var browser = await Puppeteer.LaunchAsync(new LaunchOptions( ));

            log.LogInformation($"{nameof( PdfTestFunction )} launched browser.");

            var page = await browser.NewPageAsync( );

            await page.GoToAsync("https://www.google.com");

            log.LogInformation($"{nameof( PdfTestFunction )} browser go to page.");

            var testpdf = await page.PdfDataAsync( );

            log.LogInformation($"PDF size {testpdf.Length}");

            await browser.CloseAsync( );

            return(new FileContentResult(testpdf, "application/pdf"));
        }
        public async Task ShouldDownloadAndExtractFirefoxLinuxBinary()
        {
            using var browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions
            {
                Platform = Platform.Linux,
                Path     = _downloadsFolder,
                Host     = TestConstants.ServerUrl,
                Product  = Product.Firefox
            });
            var expectedVersion = "75.0a1";
            var revisionInfo    = browserFetcher.RevisionInfo(expectedVersion);

            Server.SetRedirect(
                revisionInfo.Url.Substring(TestConstants.ServerUrl.Length),
                "/firefox.zip");
            Assert.False(revisionInfo.Local);
            Assert.Equal(Platform.Linux, revisionInfo.Platform);
            Assert.False(await browserFetcher.CanDownloadAsync("100000"));
            Assert.True(await browserFetcher.CanDownloadAsync(expectedVersion));

            try
            {
                revisionInfo = await browserFetcher.DownloadAsync(expectedVersion);

                Assert.True(revisionInfo.Local);
                Assert.Equal("FIREFOX LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
#if NETCOREAPP //This will not be run on net4x anyway.
                    Mono.Unix.FileAccessPermissions permissions = ConvertPermissions(LinuxSysCall.ExecutableFilePermissions);

                    Assert.Equal(permissions, UnixFileSystemInfo.GetFileSystemEntry(revisionInfo.ExecutablePath).FileAccessPermissions & permissions);
#endif
                }
                Assert.Equal(new[] { expectedVersion }, browserFetcher.LocalRevisions());
                browserFetcher.Remove(expectedVersion);
                Assert.Empty(browserFetcher.LocalRevisions());

                //Download should return data from a downloaded version
                //This section is not in the Puppeteer test.
                await browserFetcher.DownloadAsync(expectedVersion);

                Server.Reset();
                revisionInfo = await browserFetcher.DownloadAsync(expectedVersion);

                Assert.True(revisionInfo.Local);
                Assert.Equal("FIREFOX LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));
            }
            finally
            {
                EnsureDownloadsFolderIsDeleted();
            }
        }
Exemple #6
0
        public async Task ShouldDownloadAndExtractLinuxBinary()
        {
            var browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions
            {
                Platform = Platform.Linux,
                Path     = _downloadsFolder,
                Host     = TestConstants.ServerUrl
            });
            var revisionInfo = browserFetcher.RevisionInfo(123456);

            Server.SetRedirect(revisionInfo.Url.Substring(TestConstants.ServerUrl.Length), "/chromium-linux.zip");
            Assert.False(revisionInfo.Local);
            Assert.Equal(Platform.Linux, revisionInfo.Platform);
            Assert.False(await browserFetcher.CanDownloadAsync(100000));
            Assert.True(await browserFetcher.CanDownloadAsync(123456));

            try
            {
                revisionInfo = await browserFetcher.DownloadAsync(123456);

                Assert.True(revisionInfo.Local);
                Assert.Equal("LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
#if NETCOREAPP //don't need to run this code if we're not netcore app since net471 won't run on NIX. And UnixFileSystemInfo is not available for net471
                    Assert.Equal(
                        LinuxPermissionsSetter.ExecutableFilePermissions,
                        UnixFileSystemInfo.GetFileSystemEntry(revisionInfo.ExecutablePath).FileAccessPermissions & LinuxPermissionsSetter.ExecutableFilePermissions);
#endif
                }
                Assert.Equal(new[] { 123456 }, browserFetcher.LocalRevisions());
                browserFetcher.Remove(123456);
                Assert.Empty(browserFetcher.LocalRevisions());

                //Download should return data from a downloaded version
                //This section is not in the Puppeteer test.
                await browserFetcher.DownloadAsync(123456);

                Server.Reset();
                revisionInfo = await browserFetcher.DownloadAsync(123456);

                Assert.True(revisionInfo.Local);
                Assert.Equal("LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));
            }
            finally
            {
                EnsureDownloadsFolderIsDeleted();
            }
        }
        public async Task ShouldDownloadAndExtractLinuxBinary()
        {
            var browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions
            {
                Platform = Platform.Linux,
                Path     = _downloadsFolder,
                Host     = TestConstants.ServerUrl
            });
            var revisionInfo = browserFetcher.RevisionInfo(123456);

            Server.SetRedirect(revisionInfo.Url.Substring(TestConstants.ServerUrl.Length), "/chromium-linux.zip");
            Assert.False(revisionInfo.Local);
            Assert.Equal(Platform.Linux, revisionInfo.Platform);
            Assert.False(await browserFetcher.CanDownloadAsync(100000));
            Assert.True(await browserFetcher.CanDownloadAsync(123456));

            try
            {
                revisionInfo = await browserFetcher.DownloadAsync(123456);

                Assert.True(revisionInfo.Local);
                Assert.Equal("LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));

                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    Assert.Equal(
                        BrowserFetcher.BrowserPermissionsInLinux,
                        LinuxSysCall.GetFileMode(revisionInfo.ExecutablePath) & BrowserFetcher.BrowserPermissionsInLinux);
                }
                Assert.Equal(new[] { 123456 }, browserFetcher.LocalRevisions());
                browserFetcher.Remove(123456);
                Assert.Empty(browserFetcher.LocalRevisions());

                //Download should return data from a downloaded version
                //This section is not in the Puppeteer test.
                await browserFetcher.DownloadAsync(123456);

                Server.Reset();
                revisionInfo = await browserFetcher.DownloadAsync(123456);

                Assert.True(revisionInfo.Local);
                Assert.Equal("LINUX BINARY\n", File.ReadAllText(revisionInfo.ExecutablePath));
            }
            finally
            {
                EnsureDownloadsFolderIsDeleted();
            }
        }
Exemple #8
0
        public static IServiceCollection AddPdfGenerator(this IServiceCollection services, IConfiguration configuration)
        {
            services.TryAddSingleton(sp =>
            {
                var logger  = sp.GetRequiredService <ILogger <PdfGenerator> >();
                var options = new BrowserFetcherOptions()
                {
                    Product  = Product.Chrome,
                    Path     = Path.Combine(configuration.GetValue("CHROME_CACHE_PATH", Path.GetTempPath()), "chrome/"),
                    Platform = Platform.Linux
                };

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    options.Platform = Platform.Win64;
                }

                logger.LogInformation("Setting up Puppeteer to use {0} on platform {1} and caching in {2}", options.Product, options.Platform, options.Path);

                var fetcher = Puppeteer.CreateBrowserFetcher(options);

                var currentRevisions = fetcher.LocalRevisions();
                if (currentRevisions.Any())
                {
                    var info = fetcher.GetRevisionInfoAsync().GetAwaiter().GetResult();
                    logger.LogInformation("Found cached Puppeteer {0} in {0}", info.Revision, info.ExecutablePath);
                    if (info.Downloaded)
                    {
                        return(info);
                    }
                }
                logger.LogInformation("Downloading Puppeteer");
                return(fetcher.DownloadAsync().GetAwaiter().GetResult());
            });

            services.TryAddScoped <IPdfGenerator, PdfGenerator>();

            return(services);
        }
        /// <summary>
        /// <para>设置一个 Chromium 浏览器 启动选项 的对象,并返回这个对象;此方法兼容 Windows7 / Windows Server 2008</para>
        /// <para>异常可能:程序运行目录下 Chromium 浏览器不可用。</para>
        /// </summary>
        /// <param name="checkIsDownload">检查 是否下载 Chromium 浏览器;默认 false</param>
        /// <param name="isDisplay">Chromium 运行时 是否显示界面;默认 true</param>
        /// <param name="args">要传递给 Chromium 浏览器实例的其他参数。( 此方法会自动传入 "--no-sandbox" 参数 )
        /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para>
        /// </param>
        /// <param name="ignoredDefaultArgs">如果给出数组,则过滤掉给定的 Puppeteer.DefaultArgs 默认参数。
        /// ( 此方法会自动设置 "--enable-automation" 过滤掉这个参数 )
        /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para>
        /// </param>
        /// <returns></returns>
        private static async Task <LaunchOptions> SetChromiumLaunchOptions(
            bool checkIsDownload        = false,
            bool isDisplay              = true,
            string[] args               = null,
            string[] ignoredDefaultArgs = null)
        {
            return(await Task.Run(async() =>
            {
                BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions());
                RevisionInfo revisionInfo = browserFetcher.RevisionInfo(BrowserFetcher.DefaultRevision);

                #region 检查下载 Chromium
                if (!(revisionInfo.Downloaded && revisionInfo.Local))
                {
                    if (checkIsDownload)
                    {
                        #region  载地址 解析;参考于源代码:https://github.com/hardkoded/puppeteer-sharp/blob/37ea56934281209830254df3ec3ffe37c57cfac2/lib/PuppeteerSharp/BrowserFetcher.cs

                        // https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/706915/chrome-win.zip 下载地址( 样例 )

                        // const string DefaultDownloadHost = "https://storage.googleapis.com";
                        // const int DefaultRevision = 706915;

                        // [Platform.Linux] = "{0}/chromium-browser-snapshots/Linux_x64/{1}/{2}.zip",
                        // [Platform.MacOS] = "{0}/chromium-browser-snapshots/Mac/{1}/{2}.zip",
                        // [Platform.Win32] = "{0}/chromium-browser-snapshots/Win/{1}/{2}.zip",
                        // [Platform.Win64] = "{0}/chromium-browser-snapshots/Win_x64/{1}/{2}.zip"

                        // case Platform.Linux:
                        //     return "chrome-linux";
                        // case Platform.MacOS:
                        //     return "chrome-mac";
                        // case Platform.Win32:
                        // case Platform.Win64:
                        //     return revision > 591479 ? "chrome-win" : "chrome-win32";

                        #endregion

                        // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可下载
                        bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision);
                        if (isCan)
                        {
                            // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间
                            await browserFetcher.DownloadAsync(revisionInfo.Revision);
                        }
                        else
                        {
                            throw new Exception($"程序检测出 Chromium 浏览器(默认版本 {revisionInfo.Revision})无法更新!");
                        }
                    }
                    else
                    {
                        throw new Exception("程序运行目录下 Chromium 浏览器不可用。请开发人员检查 程序运行目录下 是否正确安装 Chromium 浏览器。");
                    }
                }
                #endregion

                #region 兼容 Windows7 / Windows Server 2008
                LaunchOptions launchOptions = default(LaunchOptions);
                // 这个判断是为了兼容 Windows7 和 Windows Server 2008
                if (OSHelper.IsWin7Under())
                {
                    launchOptions = new LaunchOptions
                    {
                        WebSocketFactory = async(uri, socketOptions, cancellationToken) =>
                        {
                            WebSocket client = SystemClientWebSocket.CreateClientWebSocket();
                            if (client is System.Net.WebSockets.Managed.ClientWebSocket managed)
                            {
                                managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0);
                                await managed.ConnectAsync(uri, cancellationToken);
                            }
                            else
                            {
                                ClientWebSocket coreSocket = client as ClientWebSocket;
                                coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0);
                                await coreSocket.ConnectAsync(uri, cancellationToken);
                            }
                            return client;
                        }
                    };
                }
                else
                {
                    launchOptions = new LaunchOptions();
                }
                #endregion

                #region 设置 Args 参数
                string[] argss = default(string[]);
                if (args != null && args.Length > 0)
                {
                    List <string> argsList = args.ToList <string>();
                    argsList.Add("--no-sandbox");
                    argss = argsList.ToArray();
                }
                else
                {
                    argss = new string[] { "--no-sandbox" };
                }
                launchOptions.Args = argss; //这些参数将会传递给 Chromium
                #endregion

                #region 设置 IgnoredDefaultArgs 参数
                string[] defaultArgs = default(string[]);
                if (ignoredDefaultArgs != null && ignoredDefaultArgs.Length > 0)
                {
                    List <string> ignoredDefaultArgsList = ignoredDefaultArgs.ToList <string>();
                    ignoredDefaultArgsList.Add("--enable-automation");
                    defaultArgs = ignoredDefaultArgsList.ToArray();
                }
                else
                {
                    defaultArgs = new string[] { "--enable-automation" };
                }
                launchOptions.IgnoredDefaultArgs = defaultArgs; //这些参数将被 Chromium 忽略
                #endregion

                launchOptions.Headless = !isDisplay; // Headless : true 是无头模式,无界面;false,有界面
                return launchOptions;
            }));
        }
        /// <summary>
        /// <para>设置一个 Chromium 浏览器 启动选项 的对象,并返回这个对象;此方法兼容 Windows7 / Windows Server 2008</para>
        /// <para>异常可能:程序运行目录下 Chromium 浏览器不可用。</para>
        /// </summary>
        /// <param name="checkIsDownload">检查 是否下载 Chromium 浏览器;默认 false</param>
        /// <param name="isDisplay">Chromium 运行时 是否显示界面;默认 true</param>
        /// <param name="args">要传递给 Chromium 浏览器实例的其他参数。( 此方法会自动传入 "--no-sandbox" 参数 )
        /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para>
        /// </param>
        /// <param name="ignoredDefaultArgs">如果给出数组,则过滤掉给定的 Puppeteer.DefaultArgs 默认参数。
        /// ( 此方法会自动设置 "--enable-automation" 过滤掉这个参数 )
        /// <para>参考:https://peter.sh/experiments/chromium-command-line-switches/#no-sandbox </para>
        /// </param>
        /// <returns></returns>
        private static async Task <LaunchOptions> SetChromiumLaunchOptions(
            bool checkIsDownload        = false,
            bool isDisplay              = true,
            string[] args               = null,
            string[] ignoredDefaultArgs = null)
        {
            return(await Task.Run(async() =>
            {
                BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions());
                RevisionInfo revisionInfo = browserFetcher.RevisionInfo(BrowserFetcher.DefaultChromiumRevision);

                #region 检查下载 Chromium
                if (!(revisionInfo.Downloaded && revisionInfo.Local))
                {
                    if (checkIsDownload)
                    {
                        // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可下载
                        bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision);
                        if (isCan)
                        {
                            // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间
                            await browserFetcher.DownloadAsync(revisionInfo.Revision);
                        }
                        else
                        {
                            throw new Exception($"程序检测出 Chromium 浏览器(默认版本 {revisionInfo.Revision})无法更新!");
                        }
                    }
                    else
                    {
                        throw new Exception("程序运行目录下 Chromium 浏览器不可用。请开发人员检查 程序运行目录下 是否正确安装 Chromium 浏览器。");
                    }
                }
                #endregion

                #region 兼容 Windows7 / Windows Server 2008
                LaunchOptions launchOptions = default(LaunchOptions);
                // 这个判断是为了兼容 Windows7 和 Windows Server 2008
                if (OSHelper.IsWin7Under())
                {
                    launchOptions = new LaunchOptions
                    {
                        WebSocketFactory = async(uri, socketOptions, cancellationToken) =>
                        {
                            WebSocket client = SystemClientWebSocket.CreateClientWebSocket();
                            if (client is System.Net.WebSockets.Managed.ClientWebSocket managed)
                            {
                                managed.Options.KeepAliveInterval = TimeSpan.FromSeconds(0);
                                await managed.ConnectAsync(uri, cancellationToken);
                            }
                            else
                            {
                                ClientWebSocket coreSocket = client as ClientWebSocket;
                                coreSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(0);
                                await coreSocket.ConnectAsync(uri, cancellationToken);
                            }
                            return client;
                        }
                    };
                }
                else
                {
                    launchOptions = new LaunchOptions();
                }
                #endregion

                #region 设置 Args 参数
                string[] argss = default(string[]);
                if (args != null && args.Length > 0)
                {
                    List <string> argsList = args.ToList <string>();
                    argsList.Add("--no-sandbox");
                    argss = argsList.ToArray();
                }
                else
                {
                    argss = new string[] { "--no-sandbox" };
                }
                launchOptions.Args = argss; // 这些参数将会传递给 Chromium
                #endregion

                #region 设置 IgnoredDefaultArgs 参数
                string[] defaultArgs = default(string[]);
                if (ignoredDefaultArgs != null && ignoredDefaultArgs.Length > 0)
                {
                    List <string> ignoredDefaultArgsList = ignoredDefaultArgs.ToList <string>();
                    ignoredDefaultArgsList.Add("--enable-automation");
                    defaultArgs = ignoredDefaultArgsList.ToArray();
                }
                else
                {
                    defaultArgs = new string[] { "--enable-automation" };
                }
                launchOptions.IgnoredDefaultArgs = defaultArgs; // 这些参数将被 Chromium 忽略
                #endregion

                launchOptions.Headless = !isDisplay; // Headless : true 是无头模式,无界面;false,有界面
                return launchOptions;
            }));
        }
        // 无头浏览器测试
        private void btn_chromiumTest_Click(object sender, EventArgs e)
        {
            this.Invoke(new Action(() =>
            {
                this.btn_chromiumTest.Enabled = false;
                this.rTxt_log.Clear();
            }));

            Task.Run(async() =>
            {
                #region 无头浏览器下载更新

                BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions());
                RevisionInfo revisionInfo     = browserFetcher.RevisionInfo(BrowserFetcher.DefaultChromiumRevision);

                if (revisionInfo.Downloaded && revisionInfo.Local)
                {
                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器检查完成,无需更新! \n");
                    }));
                }
                else
                {
                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器检查完成,需要更新! \n");
                        this.rTxt_log.AppendText("正在检查更新... \n");
                    }));

                    // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可下载
                    bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision);
                    if (!isCan)
                    {
                        this.Invoke(new Action(() =>
                        {
                            this.rTxt_log.AppendText($"程序检测出无头浏览器(默认版本 {revisionInfo.Revision})无法更新! \n");
                            this.btn_chromiumTest.Enabled = true;
                        }));
                        return;
                    }

                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("正在更新无头浏览器... \n");
                    }));

                    // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间
                    await browserFetcher.DownloadAsync(revisionInfo.Revision);

                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器更新完成。 \n");
                    }));
                }

                #endregion

                this.Invoke(new Action(() =>
                {
                    this.rTxt_log.AppendText("开始测试无头浏览器... \n");
                }));

                await TestHeadlessChromiumAsync();

                this.Invoke(new Action(() =>
                {
                    this.rTxt_log.AppendText("无头浏览器测试完成。 \n");
                    this.btn_chromiumTest.Enabled = true;
                }));
            });
        }
        // 无头浏览器测试
        private void btn_chromiumTest_Click(object sender, EventArgs e)
        {
            this.Invoke(new Action(() =>
            {
                this.btn_chromiumTest.Enabled = false;
                this.rTxt_log.Clear();
            }));

            Task.Run(async() =>
            {
                #region 无头浏览器下载更新

                BrowserFetcher browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions());
                RevisionInfo revisionInfo     = browserFetcher.RevisionInfo(BrowserFetcher.DefaultRevision);

                #region  载地址 解析;参考于源代码:https://github.com/hardkoded/puppeteer-sharp/blob/37ea56934281209830254df3ec3ffe37c57cfac2/lib/PuppeteerSharp/BrowserFetcher.cs

                // https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/706915/chrome-win.zip 下载地址( 样例 )

                // const string DefaultDownloadHost = "https://storage.googleapis.com";
                // const int DefaultRevision = 706915;

                // [Platform.Linux] = "{0}/chromium-browser-snapshots/Linux_x64/{1}/{2}.zip",
                // [Platform.MacOS] = "{0}/chromium-browser-snapshots/Mac/{1}/{2}.zip",
                // [Platform.Win32] = "{0}/chromium-browser-snapshots/Win/{1}/{2}.zip",
                // [Platform.Win64] = "{0}/chromium-browser-snapshots/Win_x64/{1}/{2}.zip"

                // case Platform.Linux:
                //     return "chrome-linux";
                // case Platform.MacOS:
                //     return "chrome-mac";
                // case Platform.Win32:
                // case Platform.Win64:
                //     return revision > 591479 ? "chrome-win" : "chrome-win32";

                #endregion

                if (revisionInfo.Downloaded && revisionInfo.Local)
                {
                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器检查完成,无需更新! \n");
                    }));
                }
                else
                {
                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器检查完成,需要更新! \n");
                        this.rTxt_log.AppendText("正在检查更新... \n");
                    }));

                    // 检查 revisionInfo.Revision 这个版本的 Chromium 浏览器 是否 可用\可下载
                    bool isCan = await browserFetcher.CanDownloadAsync(revisionInfo.Revision);
                    if (!isCan)
                    {
                        this.Invoke(new Action(() =>
                        {
                            this.rTxt_log.AppendText($"程序检测出无头浏览器(默认版本 {revisionInfo.Revision})无法更新! \n");
                            this.btn_chromiumTest.Enabled = true;
                        }));
                        return;
                    }

                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("正在更新无头浏览器... \n");
                    }));

                    // 下载 revisionInfo.Revision 这个版本的无头浏览器;可能需要等待一些时间
                    await browserFetcher.DownloadAsync(revisionInfo.Revision);

                    this.Invoke(new Action(() =>
                    {
                        this.rTxt_log.AppendText("无头浏览器更新完成。 \n");
                    }));
                }

                #endregion

                this.Invoke(new Action(() =>
                {
                    this.rTxt_log.AppendText("开始测试无头浏览器... \n");
                }));

                await TestHeadlessChromiumAsync();

                this.Invoke(new Action(() =>
                {
                    this.rTxt_log.AppendText("无头浏览器测试完成。 \n");
                    this.btn_chromiumTest.Enabled = true;
                }));
            });
        }