이미 많은 분들께서 아시다시피 Playwright는 .NET을 포함하여 Node, Python, Java 등의 프로그래밍 언어에서 웹 브라우저를 원격으로 제어할 수 있게 도와주는 프레임워크로 이미 많은 곳에서 테스트와 크롤러 목적으로 접목해서 사용하고 있습니다. 최근에는 Gen AI 덕분에 RAG에 있어서도 매우 중요한 역할을 담당하고 있다고도 볼 수 있을 것 같습니다.
이것을 File-based App으로 구현할 수 있다면 당연히 요긴할 것이므로 약간의 리서치를 거쳐 C# 파일 하나로 끝나는 하이퍼링크 크롤러 샘플을 만들어보았습니다. 이 코드를 시작점으로 삼아 다양한 응용 예제를 만들어보시거나, 혹 Playwright가 익숙하지 않다면 바이브코딩의 출발점으로 이 샘플을 사용해보는 것도 괜찮을 것이라 생각합니다.
#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk.Web
#:property PublishAot=False
#:package Microsoft.Playwright@1.54.0
// Synopsis
// dotnet run crawler.cs (TargetUrl will be https://forum.dotnetdev.kr/)
// dotnet run crawler.cs --targeturl=https://www.naver.com/
using Microsoft.Playwright;
using PlaywrightProgram = Microsoft.Playwright.Program;
// Install Playwright dependencies
Console.WriteLine("Installing playwright dependencies...");
PlaywrightProgram.Main(["install"]);
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = true, });
var page = await browser.NewPageAsync();
var configLoader = new ConfigurationBuilder();
configLoader.AddEnvironmentVariables().AddCommandLine(args);
var config = configLoader.Build();
if (!Uri.TryCreate(config["TargetUrl"], UriKind.Absolute, out var targetUrl) || targetUrl == null)
targetUrl = new Uri("https://forum.dotnetdev.kr/");
Console.WriteLine($"Navigating {targetUrl} site...");
await page.GotoAsync(targetUrl.AbsoluteUri);
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
var allLinks = await page.QuerySelectorAllAsync("a");
var foundLinks = new HashSet<string>();
foreach (var eachLink in allLinks)
{
var hrefValue = (await eachLink.GetAttributeAsync("href") ?? string.Empty).Trim();
if (Uri.TryCreate(hrefValue, UriKind.RelativeOrAbsolute, out var createdUri) && createdUri != null)
{
var normalizedUri = (createdUri.IsAbsoluteUri ? createdUri : new Uri(targetUrl, createdUri)).AbsoluteUri;
if (!foundLinks.Contains(normalizedUri, StringComparer.Ordinal))
foundLinks.Add(normalizedUri);
}
}
foreach (var eachLink in foundLinks)
Console.WriteLine(eachLink);