feat: 브라우저 설치 확인 및 드라이버 생성 개선

- 브라우저 설치 여부 확인 메서드 추가 (Chrome, Edge)
- TestDriver 메서드를 우선순위 기반 테스트로 개선 (Edge > Chrome)
- 드라이버 콘솔창 숨김 기능 추가 (HideCommandPromptWindow)
- 웹드라이버 감지 방지 스크립트 안전성 개선
- 관리자 권한 없이도 브라우저 설치 확인 가능

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-12 19:32:37 +09:00
parent c3a309092e
commit 4d1450d2c5

View File

@@ -1,4 +1,6 @@
using OpenQA.Selenium;
using AR;
using BokBonCheck;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Chromium;
using OpenQA.Selenium.Edge;
@@ -19,22 +21,43 @@ namespace UniMarc.SearchModel
{
public static class SeleniumHelper
{
static ChromiumDriver _driver;
static string pathname_userdata = "WebDriverUserData";
public enum eBrowserType
{
edge,
chrome
}
//####### public
public static string DriverPath { get; private set; }
public static eBrowserType Browser = eBrowserType.edge;
/// <summary>
/// test 혹은 create 가 성공하면 이 값이 True 가 됩니다.
/// </summary>
public static bool IsReady { get; private set; } = false;
/// <summary>
/// 사용자데이터 폴더의 기본 경로를 반환합니다.
/// </summary>
public static string UserData_BaseDirectory
{
get
{
return System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"WebDriver", "UserData");
}
}
/// <summary>
/// 드라이버파일을 다운로드 하고 완료된 경우 드라이버 실행파일 명을 반환합니다.
/// </summary>
/// <param name="versiontype">MatchingBrowser,Latest</param>
/// <returns></returns>
public static string Download(string versiontype = "MatchingBrowser")
public static async Task<string> Download(string versiontype = "MatchingBrowser", DownloadProgressForm progressForm = null)
{
if (progressForm != null)
progressForm.UpdateProgress(30, $"{Browser} 드라이버 다운로드 중...");
var dnpath = new System.IO.DirectoryInfo("WebDriver\\Download");
if (dnpath.Exists == false) dnpath.Create();
var drv = new DriverManager(dnpath.FullName);
@@ -43,94 +66,260 @@ namespace UniMarc.SearchModel
if (Browser == eBrowserType.edge) config = new EdgeConfig();
else if (Browser == eBrowserType.chrome) config = new ChromeConfig();
return drv.SetUpDriver(config, versiontype);
DriverPath = drv.SetUpDriver(config, versiontype);
if (DriverPath.isEmpty() == false && System.IO.File.Exists(DriverPath))
{
Console.WriteLine($"드라이버 다운로드 성공: {DriverPath}");
}
else
{
Console.WriteLine($"드라이버파일이 존재하지 않습니다 파일명:{DriverPath}");
}
await Task.Delay(1);
return DriverPath;
}
/// <summary>
/// 랜덤으로 사용자 폴더를 생성하여 폴더명을 반환합니다
/// 현재 실행되는 폴더에 WebDriver 폴더를 생성하고, 브라우저 종류와 타임스탬프, 랜덤 ID를 포함한 폴더명을 만듭니다.
/// </summary>
/// <returns></returns>
static string MakeUserDataPath()
{
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
string randomId = Guid.NewGuid().ToString("N").Substring(0, 8);
var userDataDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"WebDriver", $"Edge_{timestamp}_{randomId}");
var userDataDir = System.IO.Path.Combine(UserData_BaseDirectory, $"{Browser}_{timestamp}_{randomId}");
var userpath = new System.IO.DirectoryInfo(userDataDir);
if (userpath.Exists == false) userpath.Create();
return userpath.FullName;
}
public static ChromiumDriver MakeDriver()
/// <summary>
/// 설치된 브라우저를 확인하고 우선순위에 따라 드라이버 생성 테스트를 실행합니다
/// 우선순위: Edge > Chrome
/// </summary>
/// <returns>테스트 성공 여부</returns>
public static async Task<bool> TestDriver(DownloadProgressForm progressForm = null)
{
ChromiumDriver driver = nul;
var options = MakeBaseOption();
if (Browser == eBrowserType.edge)
try
{
driver = new EdgeDriver((EdgeOptions)options); // Edge 드라이버 초기화
}
else if (Browser == eBrowserType.chrome)
{
driver = new ChromeDriver((ChromeOptions)options); // Edge 드라이버 초기화
}
if( driver != null)
{
// 웹드라이버 감지 방지
((IJavaScriptExecutor)_driver).ExecuteScript("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})");
}
// 설치된 브라우저 확인
bool edgeInstalled = IsEdgeInstalled();
bool chromeInstalled = IsChromeInstalled();
return driver;
}
static ChromiumOptions MakeBaseOption()
{
EdgeOptions options = nul;
if (Browser == eBrowserType.edge)
{
options = new EdgeOptions();
//options.AddArgument($"--user-data-dir={userDataDir}");
options.AddArgument("--no-first-run");
options.AddArgument("--no-default-browser-check");
options.AddArgument("--disable-default-apps");
options.AddArgument("--disable-popup-blocking");
options.AddArgument("--disable-translate");
options.AddArgument("--disable-background-timer-throttling");
options.AddArgument("--disable-renderer-backgrounding");
options.AddArgument("--disable-backgrounding-occluded-windows");
options.AddArgument("--disable-client-side-phishing-detection");
options.AddArgument("--disable-sync");
options.AddArgument("--disable-extensions");
options.AddArgument("--disable-component-extensions-with-background-pages");
options.AddArgument("--disable-background-networking");
options.AddArgument("--disable-background-mode");
options.AddArgument("--no-sandbox");
options.AddArgument("--disable-dev-shm-usage");
options.AddArgument("--disable-blink-features=AutomationControlled");
options.AddArgument("--remote-debugging-port=0"); // 랜덤 포트 사용
if (progressForm != null)
progressForm.UpdateProgress(10, "설치된 브라우저 확인 중...");
// 둘 다 설치되어 있지 않으면 오류
if (!edgeInstalled && !chromeInstalled)
{
IsReady = false;
throw new Exception("Chrome 또는 Edge 브라우저가 설치되어 있지 않습니다. 브라우저를 설치한 후 다시 시도하세요.");
}
// Edge 우선 테스트 (설치되어 있는 경우)
if (edgeInstalled)
{
Console.WriteLine("Edge 브라우저로 드라이버 테스트를 시작합니다.");
if (progressForm != null)
progressForm.UpdateProgress(20, "Edge 브라우저 테스트 중...");
var originalBrowser = Browser;
Browser = eBrowserType.edge;
try
{
await Download(progressForm: progressForm);
var options = CreateBaseBrowserOption(true);
options.AddArgument("--log-level=3");
options.AddArgument("--silent");
options.AddArgument("--disable-blink-features=AutomationControlled");
options.AddArgument("--enable-aggressive-domstorage-flushing");
var driver = await CreateDriver(options, progressForm);
if (driver != null)
{
driver.Quit();
driver.Dispose();
IsReady = true;
Console.WriteLine("Edge 브라우저 드라이버 테스트 성공");
return true;
}
}
catch (Exception ex)
{
Console.WriteLine($"Edge 브라우저 테스트 실패: {ex.Message}");
Browser = originalBrowser;
}
}
// Chrome 테스트 (Edge 실패 시 또는 Edge가 설치되지 않은 경우)
if (chromeInstalled)
{
Console.WriteLine("Chrome 브라우저로 드라이버 테스트를 시작합니다.");
if (progressForm != null)
progressForm.UpdateProgress(60, "Chrome 브라우저 테스트 중...");
var originalBrowser = Browser;
Browser = eBrowserType.chrome;
try
{
await Download(progressForm: progressForm);
var options = CreateBaseBrowserOption(true);
options.AddArgument("--log-level=3");
options.AddArgument("--silent");
options.AddArgument("--disable-blink-features=AutomationControlled");
options.AddArgument("--enable-aggressive-domstorage-flushing");
var driver = await CreateDriver(options, progressForm);
if (driver != null)
{
driver.Quit();
driver.Dispose();
IsReady = true;
Console.WriteLine("Chrome 브라우저 드라이버 테스트 성공");
return true;
}
}
catch (Exception ex)
{
Console.WriteLine($"Chrome 브라우저 테스트 실패: {ex.Message}");
Browser = originalBrowser;
}
}
// 모든 테스트 실패
IsReady = false;
throw new Exception("설치된 모든 브라우저에서 드라이버 테스트가 실패했습니다.");
}
else if (Browser == eBrowserType.chrome)
catch (Exception ex)
{
options = new ChromeOptions();
//options.AddArgument($"--user-data-dir={userDataDir}");
options.AddArgument("--no-first-run");
options.AddArgument("--no-default-browser-check");
options.AddArgument("--disable-default-apps");
options.AddArgument("--disable-popup-blocking");
options.AddArgument("--disable-translate");
options.AddArgument("--disable-background-timer-throttling");
options.AddArgument("--disable-renderer-backgrounding");
options.AddArgument("--disable-backgrounding-occluded-windows");
options.AddArgument("--disable-client-side-phishing-detection");
options.AddArgument("--disable-sync");
options.AddArgument("--disable-extensions");
options.AddArgument("--disable-component-extensions-with-background-pages");
options.AddArgument("--disable-background-networking");
options.AddArgument("--disable-background-mode");
options.AddArgument("--no-sandbox");
options.AddArgument("--disable-dev-shm-usage");
options.AddArgument("--disable-blink-features=AutomationControlled");
options.AddArgument("--remote-debugging-port=0"); // 랜덤 포트 사용
IsReady = false;
Console.WriteLine($"드라이버 생성 테스트 중 오류: {ex.Message}");
if (progressForm != null)
progressForm.UpdateProgress(100, $"테스트 실패: {ex.Message}");
return false;
}
options.AddArgument("--window-size=1920,1080");
return options;
}
public static async Task<ChromiumDriver> CreateDriver(ChromiumOptions options = null, DownloadProgressForm progressForm = null)
{
if (progressForm != null)
progressForm.UpdateProgress(100, $"{Browser} 드라이버 생성 중...");
try
{
ChromiumDriver driver = null;
if (options == null)
{
Console.WriteLine("브라우저 옵션을 기본으로 설정합니다");
options = CreateBaseBrowserOption();
}
if (Browser == eBrowserType.edge)
{
// Edge 드라이버 서비스 생성 (콘솔창 숨김)
var edgeService = string.IsNullOrEmpty(DriverPath) ?
EdgeDriverService.CreateDefaultService() :
EdgeDriverService.CreateDefaultService(System.IO.Path.GetDirectoryName(DriverPath));
edgeService.HideCommandPromptWindow = true;
edgeService.SuppressInitialDiagnosticInformation = true;
driver = new EdgeDriver(edgeService, (EdgeOptions)options);
}
else if (Browser == eBrowserType.chrome)
{
// Chrome 드라이버 서비스 생성 (콘솔창 숨김)
var chromeService = string.IsNullOrEmpty(DriverPath) ?
ChromeDriverService.CreateDefaultService() :
ChromeDriverService.CreateDefaultService(System.IO.Path.GetDirectoryName(DriverPath));
chromeService.HideCommandPromptWindow = true;
chromeService.SuppressInitialDiagnosticInformation = true;
driver = new ChromeDriver(chromeService, (ChromeOptions)options);
}
await Task.Delay(1);
if (driver != null)
{
// 웹드라이버 감지 방지 (안전한 방법)
try
{
((IJavaScriptExecutor)driver).ExecuteScript(@"
if (typeof navigator.webdriver !== 'undefined') {
try {
delete navigator.webdriver;
} catch(e) {}
try {
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined,
configurable: true
});
} catch(e) {}
}
");
Console.WriteLine($"웹드라이버 감지 방지 스크립트 실행 완료");
}
catch (Exception ex)
{
Console.WriteLine($"웹드라이버 감지 방지 스크립트 실행 중 오류 (무시됨): {ex.Message}");
}
await Task.Delay(1);
}
IsReady = driver != null;
return driver;
}
catch (Exception ex)
{
IsReady = false;
Console.WriteLine($"드라이버 생성 중 오류: {ex.Message}");
return null;
}
}
static ChromiumOptions CreateBaseBrowserOption(bool hideBrowser = true, int width = 800, int height = 600)
{
ChromiumOptions options = null;
if (Browser == eBrowserType.edge)
{
options = new EdgeOptions();
}
else if (Browser == eBrowserType.chrome)
{
options = new ChromeOptions();
}
//options.AddArgument($"--user-data-dir={userDataDir}");
options.AddArgument("--no-first-run");
options.AddArgument("--no-default-browser-check");
options.AddArgument("--disable-default-apps");
options.AddArgument("--disable-popup-blocking");
options.AddArgument("--disable-translate");
options.AddArgument("--disable-background-timer-throttling");
options.AddArgument("--disable-renderer-backgrounding");
options.AddArgument("--disable-backgrounding-occluded-windows");
options.AddArgument("--disable-client-side-phishing-detection");
options.AddArgument("--disable-sync");
options.AddArgument("--disable-extensions");
options.AddArgument("--disable-component-extensions-with-background-pages");
options.AddArgument("--disable-background-networking");
options.AddArgument("--disable-background-mode");
options.AddArgument("--no-sandbox");
options.AddArgument("--disable-dev-shm-usage");
options.AddArgument("--disable-blink-features=AutomationControlled");
options.AddArgument("--remote-debugging-port=0"); // 랜덤 포트 사용
if (hideBrowser) options.AddArgument("--headless");
options.AddArgument($"--window-size={width},{height}");
return options;
}
public static void KillExistingDrivers()
{
string[] processNames = { };
@@ -163,7 +352,7 @@ namespace UniMarc.SearchModel
}
// 임시 WebDriver 사용자 데이터 폴더들 정리
CleanupTempUserDataDirectories();
ClearDriverCache();
// 프로세스가 완전히 종료될 때까지 대기
Thread.Sleep(2000);
@@ -176,28 +365,35 @@ namespace UniMarc.SearchModel
}
static void CleanupTempUserDataDirectories()
/// <summary>
/// 사용자데이터 폴더를 정리합니다.
/// </summary>
static void ClearDriverCache()
{
try
{
var tempPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pathname_userdata, $"{Browser}");
string[] directories = System.IO.Directory.GetDirectories(tempPath);
if (directories.Length > 0)
Console.WriteLine("Chrome 드라이버 캐시 정리 시작...");
if (System.IO.Directory.Exists(UserData_BaseDirectory))
{
Console.WriteLine($"기존 임시 사용자 데이터 폴더 {directories.Length}개를 정리하는 중...");
foreach (string dir in directories)
string[] directories = System.IO.Directory.GetDirectories(UserData_BaseDirectory);
if (directories.Length > 0)
{
try
Console.WriteLine($"기존 임시 사용자 데이터 폴더 {directories.Length}개를 정리하는 중...");
foreach (string dir in directories)
{
System.IO.Directory.Delete(dir, true);
}
catch (Exception ex)
{
Console.WriteLine($"폴더 삭제 중 오류: {ex.Message}");
try
{
System.IO.Directory.Delete(dir, true);
}
catch (Exception ex)
{
Console.WriteLine($"폴더 삭제 중 오류: {ex.Message}");
}
}
}
}
}
catch (Exception ex)
{
@@ -205,6 +401,25 @@ namespace UniMarc.SearchModel
}
}
public static void Dispose()
{
try
{
KillExistingDrivers();
ClearDriverCache();
}
catch (Exception ex)
{
Console.WriteLine($"Exception-Dispose={ex.Message}");
}
finally {
IsReady = false;
}
}
#region "브라우저별 버젼 확인"
/// <summary>
/// 현재 설치된 브라우저 버전을 확인합니다.
/// </summary>
@@ -326,5 +541,215 @@ namespace UniMarc.SearchModel
return $"Edge version check failed: {ex.Message}";
}
}
#endregion
#region "브라우저 설치 확인"
/// <summary>
/// Chrome 브라우저가 설치되어 있는지 확인합니다.
/// 관리자 권한 없이도 작동합니다.
/// </summary>
/// <returns>Chrome 설치 여부</returns>
public static bool IsChromeInstalled()
{
try
{
// 1. 레지스트리 확인 (CurrentUser)
using (var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Google\Chrome\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
// 2. 레지스트리 확인 (LocalMachine) - 읽기 권한은 일반 사용자도 가능
try
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Google\Chrome\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
}
catch
{
// 접근 권한이 없어도 계속 진행
}
// 3. WOW6432Node 확인
try
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Google\Chrome\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
}
catch
{
// 접근 권한이 없어도 계속 진행
}
// 4. 기본 설치 경로 확인
string[] chromePaths = {
@"C:\Program Files\Google\Chrome\Application\chrome.exe",
@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Google\Chrome\Application\chrome.exe")
};
foreach (string path in chromePaths)
{
if (System.IO.File.Exists(path))
return true;
}
return false;
}
catch (Exception ex)
{
Console.WriteLine($"Chrome 설치 확인 중 오류: {ex.Message}");
return false;
}
}
/// <summary>
/// Edge 브라우저가 설치되어 있는지 확인합니다.
/// 관리자 권한 없이도 작동합니다.
/// </summary>
/// <returns>Edge 설치 여부</returns>
public static bool IsEdgeInstalled()
{
try
{
// 1. 레지스트리 확인 (CurrentUser)
using (var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Edge\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
// 2. 레지스트리 확인 (LocalMachine) - 읽기 권한은 일반 사용자도 가능
try
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Edge\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
}
catch
{
// 접근 권한이 없어도 계속 진행
}
// 3. WOW6432Node 확인
try
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Edge\BLBeacon"))
{
if (key != null && key.GetValue("version") != null)
return true;
}
}
catch
{
// 접근 권한이 없어도 계속 진행
}
// 4. 기본 설치 경로 확인
string[] edgePaths = {
@"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
@"C:\Program Files\Microsoft\Edge\Application\msedge.exe"
};
foreach (string path in edgePaths)
{
if (System.IO.File.Exists(path))
return true;
}
// 5. Windows 10/11의 기본 Edge 확인 (시스템 앱)
try
{
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Classes\MSEdgeHTM"))
{
if (key != null)
return true;
}
}
catch
{
// 접근 권한이 없어도 계속 진행
}
return false;
}
catch (Exception ex)
{
Console.WriteLine($"Edge 설치 확인 중 오류: {ex.Message}");
return false;
}
}
/// <summary>
/// 설치된 브라우저 목록을 반환합니다.
/// </summary>
/// <returns>설치된 브라우저 목록</returns>
public static List<eBrowserType> GetInstalledBrowsers()
{
var installedBrowsers = new List<eBrowserType>();
if (IsChromeInstalled())
installedBrowsers.Add(eBrowserType.chrome);
if (IsEdgeInstalled())
installedBrowsers.Add(eBrowserType.edge);
return installedBrowsers;
}
/// <summary>
/// 현재 설정된 브라우저가 설치되어 있는지 확인합니다.
/// </summary>
/// <returns>현재 브라우저 설치 여부</returns>
public static bool IsBrowserInstalled()
{
switch (Browser)
{
case eBrowserType.chrome:
return IsChromeInstalled();
case eBrowserType.edge:
return IsEdgeInstalled();
default:
return false;
}
}
/// <summary>
/// 브라우저 설치 상태 정보를 문자열로 반환합니다.
/// </summary>
/// <returns>브라우저 설치 상태 정보</returns>
public static string GetBrowserInstallationStatus()
{
var status = new StringBuilder();
status.AppendLine("=== 브라우저 설치 상태 ===");
bool chromeInstalled = IsChromeInstalled();
bool edgeInstalled = IsEdgeInstalled();
status.AppendLine($"Chrome: {(chromeInstalled ? "" : "")}");
if (chromeInstalled)
status.AppendLine($" 버전: {GetChromeVersion()}");
status.AppendLine($"Edge: {(edgeInstalled ? "" : "")}");
if (edgeInstalled)
status.AppendLine($" 버전: {GetEdgeVersion()}");
status.AppendLine($"현재 설정: {Browser} ({(IsBrowserInstalled() ? " " : " ")})");
return status.ToString();
}
#endregion
}
}