feat(core): update DTOs, Trade Republic client, Yahoo scrapers, and dynamic settings
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace FinlyticCore.Services.PlaywrightScrapper;
|
||||
|
||||
public interface IPlaywrightExecutionService
|
||||
{
|
||||
/// <summary>
|
||||
/// Führt eine Scrape-Aktion auf einer einzelnen Seite innerhalb eines isolierten Kontexts aus.
|
||||
/// Der Kontext und die Page werden automatisch nach der Ausführung disposed.
|
||||
/// </summary>
|
||||
Task<T> ExecuteInPageAsync<T>(
|
||||
Func<IPage, Task<T>> action,
|
||||
BrowserNewContextOptions? contextOptions = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Führt eine Multi-Page Scrape-Aktion (z. B. bei Tabs/Popups) in einem Konfiguration-Kontext aus.
|
||||
/// </summary>
|
||||
Task<T> ExecuteInContextAsync<T>(
|
||||
Func<IBrowserContext, Task<T>> action,
|
||||
BrowserNewContextOptions? contextOptions = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public class PlaywrightExecutionService : IPlaywrightExecutionService
|
||||
{
|
||||
private readonly IPlaywrightBrowserFactory _browserFactory;
|
||||
|
||||
public PlaywrightExecutionService(IPlaywrightBrowserFactory browserFactory)
|
||||
{
|
||||
_browserFactory = browserFactory;
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteInPageAsync<T>(
|
||||
Func<IPage, Task<T>> action,
|
||||
BrowserNewContextOptions? contextOptions = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await using var context = await _browserFactory.CreateContextAsync(contextOptions, cancellationToken);
|
||||
var page = await context.NewPageAsync();
|
||||
|
||||
try
|
||||
{
|
||||
return await action(page);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await page.CloseAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T> ExecuteInContextAsync<T>(
|
||||
Func<IBrowserContext, Task<T>> action,
|
||||
BrowserNewContextOptions? contextOptions = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await using var context = await _browserFactory.CreateContextAsync(contextOptions, cancellationToken);
|
||||
return await action(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Playwright;
|
||||
|
||||
namespace FinlyticCore.Services.PlaywrightScrapper;
|
||||
|
||||
public interface IPlaywrightBrowserFactory : IAsyncDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Stellt sicher, dass die IBrowser-Instanz verbunden ist.
|
||||
/// </summary>
|
||||
Task<IBrowser> GetBrowserAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt einen isolierten, vorkonfigurierten Browser-Kontext.
|
||||
/// </summary>
|
||||
Task<IBrowserContext> CreateContextAsync(BrowserNewContextOptions? options = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public class PlaywrightBrowserFactory : IPlaywrightBrowserFactory
|
||||
{
|
||||
private readonly ILogger<PlaywrightBrowserFactory> _logger;
|
||||
private readonly SemaphoreSlim _browserLock = new(1, 1);
|
||||
|
||||
private IPlaywright? _playwright;
|
||||
private IBrowser? _browser;
|
||||
|
||||
public PlaywrightBrowserFactory(ILogger<PlaywrightBrowserFactory> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<IBrowser> GetBrowserAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_browser != null && _browser.IsConnected) return _browser;
|
||||
|
||||
await _browserLock.WaitAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
if (_browser != null && _browser.IsConnected) return _browser;
|
||||
|
||||
_playwright ??= await Playwright.CreateAsync();
|
||||
_browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
|
||||
{
|
||||
Headless = true,
|
||||
Args = new[]
|
||||
{
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-dev-shm-usage",
|
||||
"--disable-gpu"
|
||||
}
|
||||
});
|
||||
|
||||
_logger.LogInformation("[PlaywrightFactory] Shared Chromium Instance successfully launched.");
|
||||
return _browser;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_browserLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IBrowserContext> CreateContextAsync(BrowserNewContextOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var browser = await GetBrowserAsync(cancellationToken);
|
||||
|
||||
options ??= GetDefaultContextOptions();
|
||||
return await browser.NewContextAsync(options);
|
||||
}
|
||||
|
||||
public static BrowserNewContextOptions GetDefaultContextOptions() => new()
|
||||
{
|
||||
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
||||
ViewportSize = new ViewportSize { Width = 1280, Height = 900 },
|
||||
Locale = "en-US",
|
||||
ExtraHTTPHeaders = new Dictionary<string, string>
|
||||
{
|
||||
["Accept-Language"] = "en-US,en;q=0.9"
|
||||
}
|
||||
};
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_browser != null)
|
||||
{
|
||||
await _browser.CloseAsync();
|
||||
await _browser.DisposeAsync();
|
||||
}
|
||||
|
||||
_playwright?.Dispose();
|
||||
_browserLock.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user