Beispiel #1
0
        /// <summary>
        /// Attaches Puppeteer to an existing Chromium instance. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for connecting.</param>
        /// <returns>A connected browser.</returns>
        public async Task <Browser> ConnectAsync(ConnectOptions options)
        {
            try
            {
                if (_chromiumLaunched)
                {
                    throw new InvalidOperationException("Unable to create or connect to another chromium process");
                }
                _chromiumLaunched = true;

                var connectionDelay   = options.SlowMo;
                var keepAliveInterval = 0;

                _connection = await Connection.Create(options.BrowserWSEndpoint, connectionDelay, keepAliveInterval, _loggerFactory).ConfigureAwait(false);

                return(await Browser.CreateAsync(_connection, options.IgnoreHTTPSErrors, true, null, () =>
                {
                    try
                    {
                        var closeTask = _connection.SendAsync("Browser.close", null);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, ex.Message);
                    }
                    return null;
                }).ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create connection", ex);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Attaches Puppeteer to an existing Chromium instance. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for connecting.</param>
        /// <returns>A connected browser.</returns>
        public async Task <Browser> ConnectAsync(ConnectOptions options)
        {
            EnsureSingleLaunchOrConnect();

            if (!string.IsNullOrEmpty(options.BrowserURL) && !string.IsNullOrEmpty(options.BrowserWSEndpoint))
            {
                throw new PuppeteerException("Exactly one of browserWSEndpoint or browserURL must be passed to puppeteer.connect");
            }

            try
            {
                var browserWSEndpoint = string.IsNullOrEmpty(options.BrowserURL)
                    ? options.BrowserWSEndpoint
                    : await GetWSEndpointAsync(options.BrowserURL).ConfigureAwait(false);

                var connection = await Connection.Create(browserWSEndpoint, options, _loggerFactory).ConfigureAwait(false);

                var response = await connection.SendAsync <GetBrowserContextsResponse>("Target.getBrowserContexts").ConfigureAwait(false);

                return(await Browser
                       .CreateAsync(connection, response.BrowserContextIds, options.IgnoreHTTPSErrors, options.DefaultViewport, null)
                       .ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                throw new ChromiumProcessException("Failed to create connection", ex);
            }
        }
Beispiel #3
0
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching Chrome</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options)
        {
            if (_chromiumLaunched)
            {
                throw new InvalidOperationException("Unable to create or connect to another chromium process");
            }
            _chromiumLaunched = true;
            var chromeArguments  = InitChromeArgument(options);
            var chromeExecutable = options.ExecutablePath;

            if (string.IsNullOrEmpty(chromeExecutable))
            {
                var browserFetcher = new BrowserFetcher();
                chromeExecutable = browserFetcher.RevisionInfo(BrowserFetcher.DefaultRevision).ExecutablePath;
            }
            if (!File.Exists(chromeExecutable))
            {
                throw new FileNotFoundException("Failed to launch chrome! path to executable does not exist", chromeExecutable);
            }

            _chromeProcess = CreateChromeProcess(options, chromeArguments, chromeExecutable);
            try
            {
                var connectionDelay   = options.SlowMo;
                var browserWSEndpoint = await WaitForEndpoint(_chromeProcess, options.Timeout).ConfigureAwait(false);

                try
                {
                    var keepAliveInterval = 0;
                    _connection = await Connection
                                  .Create(browserWSEndpoint, connectionDelay, keepAliveInterval, _loggerFactory)
                                  .ConfigureAwait(false);

                    var browser = await Browser.CreateAsync(
                        _connection,
                        Array.Empty <string>(),
                        options.IgnoreHTTPSErrors,
                        !options.AppMode,
                        _chromeProcess,
                        GracefullyCloseChrome
                        )
                                  .ConfigureAwait(false);

                    await EnsureInitialPageAsync(browser).ConfigureAwait(false);

                    return(browser);
                }
                catch (Exception ex)
                {
                    throw new ChromeProcessException("Failed to create connection", ex);
                }
            }
            catch
            {
                KillChrome();
                await _chromeCloseTcs.Task.ConfigureAwait(false);

                throw;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Attaches Puppeteer to an existing Chromium instance. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for connecting.</param>
        /// <returns>A connected browser.</returns>
        public async Task <Browser> ConnectAsync(ConnectOptions options)
        {
            try
            {
                if (_chromiumLaunched)
                {
                    throw new InvalidOperationException("Unable to create or connect to another chromium process");
                }
                _chromiumLaunched = true;

                var connectionDelay   = options.SlowMo;
                var keepAliveInterval = options.KeepAliveInterval;

                _connection = await Connection.Create(options.BrowserWSEndpoint, connectionDelay, keepAliveInterval);

                return(await Browser.CreateAsync(_connection, options, null, () =>
                {
                    var closeTask = _connection.SendAsync("Browser.close", null);
                    return null;
                }));
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create connection", ex);
            }
        }
Beispiel #5
0
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching the browser</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            EnsureSingleLaunchOrConnect();
            _product = options.Product;
            var executable = await GetOrFetchBrowserExecutableAsync(options).ConfigureAwait(false);

            Process = options.Product switch
            {
                Product.Chrome => new ChromiumLauncher(executable, options),
                Product.Firefox => new FirefoxLauncher(executable, options),
                _ => throw new ArgumentException("Invalid product"),
            };

            try
            {
                await Process.StartAsync().ConfigureAwait(false);

                try
                {
                    var connection = await Connection
                                     .Create(Process.EndPoint, options, _loggerFactory)
                                     .ConfigureAwait(false);

                    var browser = await Browser
                                  .CreateAsync(connection, Array.Empty <string>(), options.IgnoreHTTPSErrors, options.DefaultViewport, Process, options.TargetFilter)
                                  .ConfigureAwait(false);

                    await browser.WaitForTargetAsync(t => t.Type == TargetType.Page).ConfigureAwait(false);

                    return(browser);
                }
                catch (Exception ex)
                {
                    throw new ProcessException("Failed to create connection", ex);
                }
            }
            catch
            {
                await Process.KillAsync().ConfigureAwait(false);

                throw;
            }
        }
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching Chrome</param>
        /// <param name="chromiumRevision">The revision of Chrome to launch.</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options, int chromiumRevision)
        {
            if (_chromiumLaunched)
            {
                throw new InvalidOperationException("Unable to create or connect to another chromium process");
            }
            _chromiumLaunched = true;
            var chromeArguments  = InitChromeArgument(options);
            var chromeExecutable = options.ExecutablePath;

            if (string.IsNullOrEmpty(chromeExecutable))
            {
                var downloader   = Downloader.CreateDefault();
                var revisionInfo = downloader.RevisionInfo(Downloader.CurrentPlatform, chromiumRevision);
                chromeExecutable = revisionInfo.ExecutablePath;
            }
            if (!File.Exists(chromeExecutable))
            {
                throw new FileNotFoundException("Failed to launch chrome! path to executable does not exist", chromeExecutable);
            }

            CreateChromeProcess(options, chromeArguments, chromeExecutable);

            try
            {
                var connectionDelay   = options.SlowMo;
                var browserWSEndpoint = await WaitForEndpoint(_chromeProcess, options.Timeout, options.DumpIO);

                var keepAliveInterval = options.KeepAliveInterval;

                _connection = await Connection.Create(browserWSEndpoint, connectionDelay, keepAliveInterval, _loggerFactory);

                _processLoaded = true;

                if (options.LogProcess)
                {
                    _logger.LogInformation("Process Count: {ProcessCount}", Interlocked.Increment(ref _processCount));
                }

                return(await Browser.CreateAsync(_connection, options, _chromeProcess, KillChrome));
            }
            catch (Exception ex)
            {
                ForceKillChrome();
                throw new ChromeProcessException("Failed to create connection", ex);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Attaches Puppeteer to an existing Chromium instance. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for connecting.</param>
        /// <returns>A connected browser.</returns>
        public async Task <Browser> ConnectAsync(ConnectOptions options)
        {
            EnsureSingleLaunchOrConnect();

            try
            {
                var connection = await Connection.Create(options.BrowserWSEndpoint, options, _loggerFactory).ConfigureAwait(false);

                var response = await connection.SendAsync <GetBrowserContextsResponse>("Target.getBrowserContexts");

                return(await Browser
                       .CreateAsync(connection, response.BrowserContextIds, options.IgnoreHTTPSErrors, options.DefaultViewport, null)
                       .ConfigureAwait(false));
            }
            catch (Exception ex)
            {
                throw new ChromiumProcessException("Failed to create connection", ex);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Attaches Puppeteer to an existing Chromium instance. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for connecting.</param>
        /// <returns>A connected browser.</returns>
        public async Task <Browser> ConnectAsync(ConnectOptions options)
        {
            try
            {
                var connectionDelay   = options.SlowMo;
                var keepAliveInterval = options.KeepAliveInterval;

                _connection = await Connection.Create(options.BrowserWSEndpoint, connectionDelay, keepAliveInterval);

                return(await Browser.CreateAsync(_connection, options, null, () =>
                {
                    var closeTask = _connection.SendAsync("Browser.close", null);
                    return null;
                }));
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to create connection", ex);
            }
        }
Beispiel #9
0
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching the browser</param>
        /// <param name="product">The browser to launch (Chrome, Firefox)</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options)
        {
            EnsureSingleLaunchOrConnect();

            string executable = GetOrFetchBrowserExecutable(options);

            Process = new ChromiumLauncher(executable, options);

            try
            {
                await Process.StartAsync().ConfigureAwait(false);

                try
                {
                    var connection = await Connection
                                     .Create(Process.EndPoint, options)
                                     .ConfigureAwait(false);

                    var browser = await Browser
                                  .CreateAsync(connection, Array.Empty <string>(), options.IgnoreHTTPSErrors, options.DefaultViewport, Process)
                                  .ConfigureAwait(false);

                    await browser.WaitForTargetAsync(t => t.Type == TargetType.Page).ConfigureAwait(false);

                    return(browser);
                }
                catch (Exception ex)
                {
                    throw new ProcessException("Failed to create connection", ex);
                }
            }
            catch
            {
                await Process.KillAsync().ConfigureAwait(false);

                throw;
            }
        }
Beispiel #10
0
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching Chrome</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options)
        {
            EnsureSingleLaunchOrConnect();

            var chromiumExecutable = GetOrFetchChromeExecutable(options);

            Process = new ChromiumProcess(chromiumExecutable, options, _loggerFactory);
            try
            {
                await Process.StartAsync().ConfigureAwait(false);

                try
                {
                    var connection = await Connection
                                     .Create(Process.EndPoint, options, _loggerFactory)
                                     .ConfigureAwait(false);

                    var browser = await Browser
                                  .CreateAsync(connection, Array.Empty <string>(), options.IgnoreHTTPSErrors, options.DefaultViewport, Process)
                                  .ConfigureAwait(false);

                    await EnsureInitialPageAsync(browser).ConfigureAwait(false);

                    return(browser);
                }
                catch (Exception ex)
                {
                    throw new ChromiumProcessException("Failed to create connection", ex);
                }
            }
            catch
            {
                await Process.KillAsync().ConfigureAwait(false);

                throw;
            }
        }
Beispiel #11
0
        /// <summary>
        /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed.
        /// </summary>
        /// <param name="options">Options for launching Chrome</param>
        /// <param name="chromiumRevision">The revision of Chrome to launch.</param>
        /// <returns>A connected browser.</returns>
        /// <remarks>
        /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a>
        /// for a description of the differences between Chromium and Chrome.
        /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users.
        /// </remarks>
        public async Task <Browser> LaunchAsync(LaunchOptions options, int chromiumRevision)
        {
            var chromeArguments = new List <string>(DefaultArgs);

            _options = options;

            if (options.AppMode)
            {
                options.Headless = false;
            }
            else
            {
                chromeArguments.AddRange(AutomationArgs);
            }

            var userDataDirOption = options.Args.FirstOrDefault(i => i.StartsWith(UserDataDirArgument, StringComparison.Ordinal));

            if (string.IsNullOrEmpty(userDataDirOption))
            {
                if (string.IsNullOrEmpty(options.UserDataDir))
                {
                    _temporaryUserDataDir = GetTemporaryDirectory();
                    chromeArguments.Add($"{UserDataDirArgument}={_temporaryUserDataDir}");
                }
                else
                {
                    chromeArguments.Add($"{UserDataDirArgument}={options.UserDataDir}");
                }
            }
            else
            {
                _options.UserDataDir = userDataDirOption.Replace($"{UserDataDirArgument}=", string.Empty);
            }

            if (options.Devtools)
            {
                chromeArguments.Add("--auto-open-devtools-for-tabs");
                options.Headless = false;
            }

            if (options.Headless)
            {
                chromeArguments.AddRange(new[] {
                    "--headless",
                    "--disable-gpu",
                    "--hide-scrollbars",
                    "--mute-audio"
                });
            }

            var chromeExecutable = options.ExecutablePath;

            if (string.IsNullOrEmpty(chromeExecutable))
            {
                var downloader   = Downloader.CreateDefault();
                var revisionInfo = downloader.RevisionInfo(Downloader.CurrentPlatform, chromiumRevision);
                chromeExecutable = revisionInfo.ExecutablePath;
            }
            if (!File.Exists(chromeExecutable))
            {
                throw new FileNotFoundException("Failed to launch chrome! path to executable does not exist", chromeExecutable);
            }

            if (options.Args.Any())
            {
                chromeArguments.AddRange(options.Args);
            }

            _chromeProcess = new Process();
            _chromeProcess.EnableRaisingEvents       = true;
            _chromeProcess.StartInfo.UseShellExecute = false;
            _chromeProcess.StartInfo.FileName        = chromeExecutable;
            _chromeProcess.StartInfo.Arguments       = string.Join(" ", chromeArguments);

            SetEnvVariables(_chromeProcess.StartInfo.Environment, options.Env, Environment.GetEnvironmentVariables());

            if (!options.DumpIO)
            {
                _chromeProcess.StartInfo.RedirectStandardOutput = false;
                _chromeProcess.StartInfo.RedirectStandardError  = false;
            }

            _chromeProcess.Exited += async(sender, e) =>
            {
                await AfterProcessExit();
            };

            try
            {
                var connectionDelay   = options.SlowMo;
                var browserWSEndpoint = await WaitForEndpoint(_chromeProcess, options.Timeout, options.DumpIO);

                var keepAliveInterval = options.KeepAliveInterval;

                _connection = await Connection.Create(browserWSEndpoint, connectionDelay, keepAliveInterval);

                _processLoaded = true;

                if (options.LogProcess)
                {
                    Console.WriteLine($"PROCESS COUNT: {Interlocked.Increment(ref _processCount)}");
                }

                return(await Browser.CreateAsync(_connection, options, _chromeProcess, KillChrome));
            }
            catch (Exception ex)
            {
                ForceKillChrome();
                throw new ChromeProcessException("Failed to create connection", ex);
            }
        }
Beispiel #12
0
        internal static async Task <Browser> LaunchAsync(Dictionary <string, object> options, int chromiumRevision)
        {
            var chromeArguments = new List <string>(_defaultArgs);

            if (options.ContainsKey("appMode"))
            {
                options["headless"] = false;
            }
            else
            {
                chromeArguments.AddRange(_automationArgs);
            }

            if (options.ContainsKey("args") &&
                ((string[])options["args"]).Any(i => i.StartsWith("--user-data-dir", StringComparison.Ordinal)))
            {
                if (!options.ContainsKey("userDataDir"))
                {
                    _temporaryUserDataDir = GetTemporaryDirectory();
                    chromeArguments.Add($"--user-data-dir=${_temporaryUserDataDir}");
                }
                else
                {
                    chromeArguments.Add($"--user-data-dir=${options["userDataDir"]}");
                }
            }

            if (options.TryGetValue("devtools", out var hasDevTools) && (bool)hasDevTools)
            {
                chromeArguments.Add("--auto-open-devtools-for-tabs");
                options["headless"] = false;
            }

            if (options.TryGetValue("headless", out var isHeadless) && (bool)isHeadless)
            {
                chromeArguments.AddRange(new[] {
                    "--headless",
                    "--disable-gpu",
                    "--hide-scrollbars",
                    "--mute-audio"
                });
            }

            var chromeExecutable = (options.GetValueOrDefault("executablePath") ?? "").ToString();

            if (string.IsNullOrEmpty(chromeExecutable))
            {
                var downloader   = Downloader.CreateDefault();
                var revisionInfo = downloader.RevisionInfo(Downloader.CurrentPlatform, chromiumRevision);
                chromeExecutable = revisionInfo.ExecutablePath;
            }

            if (options.ContainsKey("args"))
            {
                chromeArguments.AddRange((string[])options["args"]);
            }

            _chromeProcess = new Process();
            _chromeProcess.StartInfo.FileName  = chromeExecutable;
            _chromeProcess.StartInfo.Arguments = string.Join(" ", chromeArguments);

            SetEnvVariables(_chromeProcess.StartInfo.Environment,
                            options.ContainsKey("env") ? (IDictionary <string, string>)options["env"] : null,
                            (IDictionary)Environment.GetEnvironmentVariables());

            if (!options.ContainsKey("dumpio"))
            {
                _chromeProcess.StartInfo.RedirectStandardOutput = false;
                _chromeProcess.StartInfo.RedirectStandardError  = false;
            }

            _chromeProcess.Exited += async(sender, e) =>
            {
                _chromeClosed = true;
                await KillChrome();
            };

            try
            {
                var connectionDelay   = (int)(options.GetValueOrDefault("slowMo") ?? 0);
                var browserWSEndpoint = await WaitForEndpoint(_chromeProcess,
                                                              (int)(options.GetValueOrDefault("timeout") ?? 30 * 100),
                                                              options.ContainsKey("dumpio"));

                _connection = await Connection.Create(browserWSEndpoint, connectionDelay);

                return(await Browser.CreateAsync(_connection, options, KillChrome));
            }
            catch (Exception ex)
            {
                await ForceKillChrome();

                throw new Exception("Failed to create connection", ex);
            }
        }