18c5ad83da
- Removed obsolete data providers: `AnchorCollectionDataProvider`, `ContentsDataProvider`, and others, consolidating logic into new composable providers. - Added `ComposeDataProviders`, `SelectDataProvider`, and `RelationalDataProvider` for improved flexibility and reusability. - Introduced `IManySelectionComposableDataProvider` interface to support multiple-node selection. - Enhanced `UnitDownloader` with more robust progress tracking. - Updated package references and project dependencies for consistency. - Improved error handling in `StealthConfig` initialization for better fallback on browser drivers. - Incremented project version to 2.4.5.
125 lines
4.8 KiB
C#
125 lines
4.8 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;
|
|
|
|
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; }
|
|
|
|
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 ---------- */
|
|
|
|
public static StealthConfig Create(
|
|
bool showBrowser = false,
|
|
string? downloadDir = null,
|
|
TimeSpan? timeOut = null,
|
|
Browser preferredBrowser = Browser.Firefox,
|
|
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 {
|
|
driver = preferredBrowser switch {
|
|
Browser.Chrome or Browser.Chromium
|
|
=> new ChromeDriver(GetChromeOptions(downloadDir, headless)),
|
|
Browser.Edge
|
|
=> new EdgeDriver(GetEdgeOptions(downloadDir, headless)),
|
|
Browser.Firefox or _
|
|
=> new FirefoxDriver(GetFirefoxOptions(downloadDir, headless)),
|
|
};
|
|
}
|
|
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 fallback 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();
|
|
}
|
|
}
|
|
}
|