Files
Beam/Beam.Stealth/StealthConfig.cs
T
qwsdcvghyu89 b5faf58b1a feat: add support for remote WebDriver and improve StealthConfig browser logic
- Added `RemoteAddress` property to `StealthConfig` for remote WebDriver support.
- Refactored browser driver creation logic with `DriverDefinition` for enhanced consistency.
- Improved error handling in browser fallback mechanism.
- Incremented project version to 2.4.6.
2025-11-14 04:36:03 +11:00

135 lines
5.4 KiB
C#

using System;
using System.IO;
using Microsoft.Extensions.Logging;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Edge;
using OpenQA.Selenium.Remote;
namespace Beam.Stealth {
public enum Browser {
Firefox = 0,
Chrome = 1,
Chromium = 2,
Edge = 3,
}
public sealed class StealthConfig : IDisposable {
public bool ShowBrowser { get; init; }
public TimeSpan TimeOut { get; init; } = Timeout.InfiniteTimeSpan;
public string DownloadsDirectory { get; }
public ILogger? Logger { get; init; }
public required IWebDriver Driver { get; init; }
public string? RemoteAddress { get; init; }
private StealthConfig(string downloadDir) => DownloadsDirectory = downloadDir;
/* ---------- browser-specific option builders ---------- */
private static FirefoxOptions GetFirefoxOptions(string downloadDir, bool headless) {
var o = new FirefoxOptions();
if (headless) o.AddArgument("--headless");
o.SetPreference("browser.download.folderList", 2); // use custom dir
o.SetPreference("browser.download.dir", downloadDir);
o.SetPreference("browser.download.useDownloadDir", true);
o.SetPreference("browser.helperApps.neverAsk.saveToDisk",
"application/octet-stream,application/pdf,application/zip");
o.SetPreference("pdfjs.disabled", true); // open PDFs externally
o.SetPreference("browser.download.manager.showWhenStarting", false);
return o;
}
private static ChromeOptions GetChromeOptions(string downloadDir, bool headless) {
var o = new ChromeOptions();
if (headless) o.AddArgument("--headless=new");
// download prefs
o.AddUserProfilePreference("download.default_directory", downloadDir);
o.AddUserProfilePreference("download.prompt_for_download", false);
o.AddUserProfilePreference("safebrowsing.enabled", false);
// common stability flags
o.AddArgument("--no-sandbox");
o.AddArgument("--disable-dev-shm-usage");
return o;
}
private static EdgeOptions GetEdgeOptions(string downloadDir, bool headless) {
var o = new EdgeOptions();
if (headless) o.AddArgument("--headless=new");
o.AddUserProfilePreference("download.default_directory", downloadDir);
o.AddUserProfilePreference("download.prompt_for_download", false);
o.AddUserProfilePreference("safebrowsing.enabled", false);
return o;
}
/* ---------- factory ---------- */
private record DriverDefinition(Func<DriverOptions, IWebDriver> Factory, DriverOptions Options);
public static StealthConfig Create(
bool showBrowser = false,
string? downloadDir = null,
TimeSpan? timeOut = null,
Browser preferredBrowser = Browser.Firefox,
string? remoteAddress = null,
ILogger? logger = null) {
// pick or create a dedicated download folder
downloadDir ??= Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(downloadDir);
bool headless = !showBrowser;
IWebDriver? driver = null;
List<Exception>? errors = [];
while (preferredBrowser <= Browser.Edge) {
try {
DriverDefinition def = preferredBrowser switch {
Browser.Chrome or Browser.Chromium
=> new((DriverOptions opts) => new ChromeDriver(opts as ChromeOptions), GetChromeOptions(downloadDir, headless)),
Browser.Edge
=> new((DriverOptions opts) => new EdgeDriver(opts as EdgeOptions), GetEdgeOptions(downloadDir, headless)),
Browser.Firefox or _
=> new((DriverOptions opts) => new FirefoxDriver(opts as FirefoxOptions), GetFirefoxOptions(downloadDir, headless)),
};
if (remoteAddress is not null)
driver = new RemoteWebDriver(new Uri(remoteAddress), def.Options);
else
driver = def.Factory(def.Options);
break;
}
catch (Exception e) {
if (preferredBrowser != Browser.Edge)
logger?.LogWarning(e, "Failed to create driver for browser {Browser}, falling back to {Fallback}", preferredBrowser, Enum.GetName(preferredBrowser + 1));
else {
logger?.LogCritical(e, "Failed to create driver for browser {Browser}, no more fallbacks remaining!", preferredBrowser);
}
preferredBrowser++;
errors.Add(e);
}
}
if (driver is null)
throw new AggregateException(errors);
return new StealthConfig(downloadDir) {
ShowBrowser = showBrowser,
TimeOut = timeOut ?? Timeout.InfiniteTimeSpan,
Logger = logger,
Driver = driver
};
}
public void Dispose() {
Driver.Dispose();
}
}
}