# ⚠️ 중요: 대화 시작시 이 파일을 반드시 읽으세요! # 답변은 가급적이면 한글로! # UniMarc 프로젝트 - Claude 작업 가이드 > **Claude에게**: 대화를 시작할 때마다 이 파일을 먼저 읽어서 프로젝트 컨텍스트를 파악하세요. ## 프로젝트 개요 - **프로젝트명**: UniMarc (도서관 자료 관리 시스템) - **기술스택**: C# WinForms, .NET Framework 4.7.2 - **데이터베이스**: MySQL - **주요기능**: 마크 작성, 복본조사, DLS 연동, 도서 정보 관리 ## 데이터베이스 정보 - Server=1.215.250.130;Port=3306;Database=unimarc;uid=root;pwd=Admin21234; ## 코딩 컨벤션 - 파일명: PascalCase (예: DLS_Copy.cs) - 클래스명: PascalCase - 메서드명: PascalCase - 변수명: camelCase - 상수명: UPPER_CASE ## 주요 디렉토리 구조 - `/마크/`: 마크 관련 폼들 - `/납품관리/`: 납품 관리 관련 폼들 - `/마스터/`: 마스터 데이터 관리 폼들 - `/홈/`: 메인 화면 관련 폼들 - `/회계/`: 회계 관련 폼들 ## 개발 시 주의사항 1. WebView2 사용 시 async/await 패턴 적용 2. 데이터베이스 연결은 Helper_DB 클래스 사용 3. 에러 처리는 try-catch 블록으로 처리 4. 한글 주석 사용 ## 빌드 및 배포 - Visual Studio 2019 이상 필요 - NuGet 패키지 복원 후 빌드 - WebView2 런타임 필요 - NetFX 프로젝트이므로 dotnet 명령은 사용 불가 ## MsBuild 실행파일 위치 (경로에 공백이 있으니 쌍따옴표로 감싸야 함) ## 매개변수 입력할때 platform 은 제거하고 그냥 프로젝트명만 입력 F:\(VHD) Program Files\Microsoft Visual Studio\2022\MSBuild\Current\Bin\msbuild.exe ## 프로젝트 파일명 UniMarc.csproj ## 도서관 검색기(크롤링) 클래스 작성 가이드 ### 개요 도서관 웹사이트에서 도서 검색 결과를 크롤링하는 클래스들을 구현합니다. 각 도서관 사이트의 특성에 따라 HTTP 방식 또는 Selenium 방식을 선택합니다. ### 방식 선택 기준 - **HTTP 방식**: URL이 변경되는 사이트 (GET 파라미터로 검색) - **Selenium 방식**: URL이 변경되지 않는 사이트 (POST 폼 제출) ### 1. HTTP 방식 (GET 요청) **참고 파일**: `SuncheonLibSearcher.cs` **특징**: - HttpClient 사용 - URL 파라미터로 검색 - 빠른 실행 속도 - HttpApiMode = true **주요 구현 포인트**: ```csharp // URL 구성 var searchUrl = $"{SiteUrl}?search={encodedSearchTerm}&libCode={AreaCode}"; // HTTP 헤더 추가 (500 에러 방지) request.Headers.Add("User-Agent", "Mozilla/5.0..."); request.Headers.Add("Accept", "text/html,application/xhtml+xml..."); // HTML에서 결과 수 정규식 추출 var patterns = new[] { @"총\s*]*class=""cred""[^>]*>(\d+)\s*건" }; ``` ### 2. Selenium 방식 (크롤링) **참고 파일**: `GwangjuCityLibSearcher.cs` **특징**: - Selenium WebDriver 사용 - 폼 제출 방식 - 복잡한 UI 상호작용 가능 - HttpApiMode = false **주요 구현 포인트**: ```csharp // 도서관 선택 (드롭다운) var libSelect = wait.Until(d => d.FindElement(By.CssSelector("select[name='libCode']"))); var selectElement = new SelectElement(libSelect); selectElement.SelectByValue(AreaCode); // 검색어 입력 var searchInput = wait.Until(d => d.FindElement(By.Id("bookSearchQuery"))); searchInput.Clear(); searchInput.SendKeys(searchTerm); // 검색 버튼 클릭 var searchButton = wait.Until(d => d.FindElement(By.CssSelector("button.bookSearchBtn"))); searchButton.Click(); // 페이지 로딩 대기 await WaitForPageChange(wait); ``` ### 3. 공통 인터페이스 구현 모든 검색기는 `ILibrarySearcher` 인터페이스를 구현해야 합니다: ```csharp public interface ILibrarySearcher { Task SearchAsync(string searchTerm); Task StartDriver(bool showdriver = false); void StopDriver(); string SiteName { get; } string SiteUrl { get; } bool HttpApiMode { get; set; } int No { get; set; } } ``` ### 4. Check_copyWD.cs에 등록 새로운 검색기를 만든 후 반드시 Check_copyWD.cs의 생성자에 추가: ```csharp // 예시: 완도군립도서관 idx = 1200; _searchService.AddSearcher(new WandoLibSearcher(idx++, "MA", "완도군립도서관")); _searchService.AddSearcher(new WandoLibSearcher(idx++, "MB", "노화공공도서관")); ``` ### 5. 결과 추출 패턴 HTML에서 검색 결과 수를 추출하는 일반적인 패턴들: ```csharp var patterns = new[] { @"총\s*]*>(\d+)\s*건", @"검색결과\s*총\s*(\d+)\s*건", @"]*class=""heighlight""[^>]*>(\d+)", @"총\s*(\d+)\s*권\(개\)" }; ``` ### 6. 에러 처리 - 검색 결과 없음: `return 0` - 추출 실패: `return -1` - 예외 발생: BookSearchResult의 ErrorMessage에 설정 ### 현재 구현된 검색기 목록 1. HTTP 방식: SuncheonLibSearcher, MokpoLibSearcher, GwangsanLibSearcher, YeosuLibSearcher 2. Selenium 방식: GwangjuCityLibSearcher, GoheungLibSearcher, BukguLibSearcher 계열, JeonbukEduLibSearcher 각 방식의 장단점을 고려하여 사이트 특성에 맞는 방식을 선택하여 구현하세요.