feat: 도서관 검색 시스템 대폭 확장 및 크롤링 가이드 추가
- 새로운 도서관 검색기 15개 추가 (HTTP/Selenium 방식) * HTTP 방식: 순천시립, 목포시립, 광산구, 여수시립 * Selenium 방식: 광주시립, 고흥군립, 북구통합, 전북교육청, 안산시립 등 - 도서관 검색기 작성 가이드를 CLAUDE.md에 추가 - ILibrarySearcher 인터페이스에 HttpApiMode 속성 추가 - 기존 검색기들 리팩토링 및 통합 (NamguLibrarySearcher 등) - Check_copyWD.cs에 모든 새로운 도서관 등록 완료 - 설정 관리 시스템 개선 (UserSetting 클래스 추가) 총 200개 이상의 도서관 지원으로 복본조사 범위 대폭 확대 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -41,4 +41,116 @@
|
||||
F:\(VHD) Program Files\Microsoft Visual Studio\2022\MSBuild\Current\Bin\msbuild.exe
|
||||
|
||||
## 프로젝트 파일명
|
||||
UniMarc.csproj
|
||||
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*<strong[^>]*class=""cred""[^>]*>(\d+)</strong>\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<BookSearchResult> 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*<strong[^>]*>(\d+)</strong>\s*건",
|
||||
@"검색결과\s*총\s*(\d+)\s*건",
|
||||
@"<span[^>]*class=""heighlight""[^>]*>(\d+)</span>",
|
||||
@"총\s*(\d+)\s*권\(개\)"
|
||||
};
|
||||
```
|
||||
|
||||
### 6. 에러 처리
|
||||
- 검색 결과 없음: `return 0`
|
||||
- 추출 실패: `return -1`
|
||||
- 예외 발생: BookSearchResult의 ErrorMessage에 설정
|
||||
|
||||
### 현재 구현된 검색기 목록
|
||||
1. HTTP 방식: SuncheonLibSearcher, MokpoLibSearcher, GwangsanLibSearcher, YeosuLibSearcher
|
||||
2. Selenium 방식: GwangjuCityLibSearcher, GoheungLibSearcher, BukguLibSearcher 계열, JeonbukEduLibSearcher
|
||||
|
||||
각 방식의 장단점을 고려하여 사이트 특성에 맞는 방식을 선택하여 구현하세요.
|
||||
@@ -4,12 +4,14 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using UniMarc.Properties;
|
||||
|
||||
namespace UniMarc
|
||||
{
|
||||
public static class PUB
|
||||
{
|
||||
public static arUtil.Log log;
|
||||
public static UserSetting setting;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
@@ -20,6 +22,9 @@ namespace UniMarc
|
||||
PUB.log.SubDirectory = logsubdir;
|
||||
PUB.log.FileNameFormat = "{yyMMdd}";
|
||||
#endregion
|
||||
|
||||
setting = new UserSetting();
|
||||
setting.Load();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
418
unimarc/unimarc/SearchModel/AnsanLibSearcher.cs
Normal file
418
unimarc/unimarc/SearchModel/AnsanLibSearcher.cs
Normal file
@@ -0,0 +1,418 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class AnsanLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://lib.ansan.go.kr/DetailSearch";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public AnsanLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"안산시립({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("AnsanLibSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"AnsanLibSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"AnsanLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. 먼저 모든 전체선택 버튼을 찾아서 클릭하여 기존 선택을 모두 해제
|
||||
Console.WriteLine("기존 선택 해제 중...");
|
||||
var allSelectButtons = wait.Until(d => d.FindElements(By.CssSelector("div.library span.btnAllSelect")));
|
||||
|
||||
foreach (var button in allSelectButtons)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 전체선택 버튼이 "전체선택"인지 "전체해제"인지 확인하고 필요시 클릭
|
||||
var buttonText = button.Text.Trim();
|
||||
Console.WriteLine($"전체선택 버튼 텍스트: {buttonText}");
|
||||
|
||||
// 전체선택 버튼을 두 번 클릭하여 모든 선택 해제 (선택 -> 해제)
|
||||
SafeClick(button);
|
||||
Thread.Sleep(300);
|
||||
SafeClick(button);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("전체선택 버튼 클릭 완료 (해제)");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"전체선택 버튼 클릭 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 지정된 도서관만 선택
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
Console.WriteLine($"특정 도서관 선택 중: {AreaCode}");
|
||||
|
||||
// div.library 안에서 해당 value를 가진 체크박스 찾기
|
||||
var libraryCheckbox = wait.Until(d => d.FindElement(By.CssSelector($"div.library input[type='checkbox'][value='{AreaCode}']")));
|
||||
|
||||
// 체크박스 선택
|
||||
SafeClick(libraryCheckbox);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// 선택 확인
|
||||
if (libraryCheckbox.Selected)
|
||||
{
|
||||
Console.WriteLine($"{AreaCode} 도서관 선택 완료");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{AreaCode} 도서관 선택 실패, 다시 시도");
|
||||
SafeClick(libraryCheckbox);
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("전체 도서관으로 검색 - 모든 도서관 선택");
|
||||
// AreaCode가 없으면 첫 번째 전체선택 버튼만 클릭하여 모든 도서관 선택
|
||||
if (allSelectButtons.Count > 0)
|
||||
{
|
||||
SafeClick(allSelectButtons[0]);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("모든 도서관 선택 완료");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected void SafeClick(IWebElement element)
|
||||
{
|
||||
// 안정적인 클릭을 위한 여러 방법 시도
|
||||
try
|
||||
{
|
||||
// 1. 요소가 보이도록 스크롤 후 일반 클릭
|
||||
((IJavaScriptExecutor)_driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
|
||||
Thread.Sleep(300);
|
||||
element.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. JavaScript로 클릭 시도
|
||||
((IJavaScriptExecutor)_driver).ExecuteScript("arguments[0].click();", element);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3. Actions 클래스 사용
|
||||
var actions = new Actions(_driver);
|
||||
actions.MoveToElement(element).Click().Perform();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 4. 체크박스의 경우 직접 체크 상태 변경
|
||||
if (element.TagName.ToLower() == "input" && element.GetAttribute("type") == "checkbox")
|
||||
{
|
||||
((IJavaScriptExecutor)_driver).ExecuteScript("arguments[0].checked = !arguments[0].checked;", element);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 일반 요소는 강제 클릭
|
||||
((IJavaScriptExecutor)_driver).ExecuteScript("arguments[0].dispatchEvent(new Event('click'));", element);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"모든 클릭 방법 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색어 입력
|
||||
try
|
||||
{
|
||||
var searchInput = wait.Until(d => d.FindElement(By.Id("advTitle")));
|
||||
searchInput.Clear();
|
||||
searchInput.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색어입력실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭
|
||||
try
|
||||
{
|
||||
var searchButton = wait.Until(d => d.FindElement(By.CssSelector("a.btTxt.bg.primary")));
|
||||
searchButton.Click();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼클릭실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
|
||||
if (noResultElements.Count > 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
// 2. 검색 결과 영역에서 직접 추출 시도
|
||||
try
|
||||
{
|
||||
// 결과 요약 정보가 있는 영역 찾기
|
||||
var resultInfoElements = driver.FindElements(By.CssSelector(".resultInfo, .result-info, .search-result, .totalResult"));
|
||||
foreach (var element in resultInfoElements)
|
||||
{
|
||||
var text = element.Text;
|
||||
var match = Regex.Match(text, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 3. 페이지 소스에서 정규식으로 추출 시도
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다") ||
|
||||
pageSource.Contains("자료가 없습니다") ||
|
||||
pageSource.Contains("총 0 건") ||
|
||||
pageSource.Contains("총 0건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기 (안산시 도서관 특화)
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"총\s*(\d+)\s*건",
|
||||
@"<em[^>]*>총\s*(\d+)\s*건\s*</em>",
|
||||
@"검색결과\s*:\s*총\s*(\d+)\s*건",
|
||||
@"전체\s*(\d+)\s*건",
|
||||
@"검색결과\s*총\s*(\d+)\s*건",
|
||||
@"검색\s*결과\s*\(\s*총\s*(\d+)\s*건\s*\)",
|
||||
@"총\s*<[^>]*>(\d+)</[^>]*>\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var pageSource = d.PageSource;
|
||||
// 검색 결과나 관련 요소가 나타나면 로드 완료
|
||||
return pageSource.Contains("검색결과") ||
|
||||
pageSource.Contains("총") ||
|
||||
pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("건");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(3000);
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
438
unimarc/unimarc/SearchModel/BukguLibSearcher.cs
Normal file
438
unimarc/unimarc/SearchModel/BukguLibSearcher.cs
Normal file
@@ -0,0 +1,438 @@
|
||||
using AR;
|
||||
using AR.Dialog;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UniMarc.SearchModel;
|
||||
using UniMarc.마크;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class BukguLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl { get; protected set; } = "https://lib.bukgu.gwangju.kr/main/bookSearchSmartlib.do?PID=0301";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public BukguLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"광주북구스마트도서관({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("BukguLibSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"BukguLibSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"BukguLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 전체 선택인 경우 - 모든 체크박스 선택
|
||||
if (string.IsNullOrEmpty(AreaCode) || AreaCode == "ALL")
|
||||
{
|
||||
var allCheckboxes1 = wait.Until(d => d.FindElements(By.CssSelector("input[name='libCode']")));
|
||||
foreach (var checkbox in allCheckboxes1)
|
||||
{
|
||||
if (!checkbox.Selected)
|
||||
{
|
||||
SafeClick(checkbox);
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("전체 도서관 선택됨");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 특정 도서관 선택인 경우
|
||||
var targetCheckboxId = $"lib{AreaCode}";
|
||||
var targetCheckbox = wait.Until(d => d.FindElement(By.Id(targetCheckboxId)));
|
||||
|
||||
if (targetCheckbox == null)
|
||||
{
|
||||
Console.WriteLine($"도서관 체크박스를 찾을 수 없습니다: {targetCheckboxId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 다른 체크박스들 해제
|
||||
var allCheckboxes = wait.Until(d => d.FindElements(By.CssSelector("input[name='libCode']")));
|
||||
foreach (var checkbox in allCheckboxes)
|
||||
{
|
||||
if (checkbox.GetAttribute("id") != targetCheckboxId && checkbox.Selected)
|
||||
{
|
||||
SafeClick(checkbox);
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
// 대상 체크박스 선택
|
||||
if (!targetCheckbox.Selected)
|
||||
{
|
||||
SafeClick(targetCheckbox);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{AreaCode} 도서관으로 변경됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{AreaCode} 도서관이 이미 선택되어 있음");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void SafeClick(IWebElement element)
|
||||
{
|
||||
// 안정적인 클릭을 위한 여러 방법 시도
|
||||
try
|
||||
{
|
||||
// 1. JavaScript로 클릭 시도
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click();", element);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. 요소가 보이도록 스크롤 후 클릭
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
|
||||
Thread.Sleep(500);
|
||||
element.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3. Actions 클래스 사용
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
var actions = new OpenQA.Selenium.Interactions.Actions(driver);
|
||||
actions.MoveToElement(element).Click().Perform();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 4. 마지막 방법: JavaScript로 직접 체크 상태 변경
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].checked = !arguments[0].checked;", element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색어 입력 - 다양한 선택자로 시도
|
||||
try
|
||||
{
|
||||
IWebElement searchInput = null;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
searchInput = wait.Until(d => d.FindElement(By.CssSelector("input[name='searchText']")));
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (searchInput == null)
|
||||
{
|
||||
result.ErrorMessage = "검색창을 찾을 수 없음";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
searchInput.Clear();
|
||||
searchInput.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색어입력실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭 - 다양한 선택자로 시도
|
||||
try
|
||||
{
|
||||
IWebElement searchButton = null;
|
||||
try
|
||||
{
|
||||
searchButton = wait.Until(d => d.FindElement(By.CssSelector("button[type='submit']")));
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
if (searchButton == null)
|
||||
{
|
||||
result.ErrorMessage = "검색버튼을 찾을 수 없음";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
searchButton.Click();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼클릭실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 1. totalCount 요소에서 직접 추출 시도
|
||||
try
|
||||
{
|
||||
var totalCountElement = driver.FindElement(By.CssSelector("p.totalCount"));
|
||||
if (totalCountElement != null)
|
||||
{
|
||||
// strong 태그에서 직접 숫자 추출 시도
|
||||
try
|
||||
{
|
||||
var strongElement = totalCountElement.FindElement(By.TagName("strong"));
|
||||
if (strongElement != null)
|
||||
{
|
||||
var countText = strongElement.Text.Trim();
|
||||
if (int.TryParse(countText, out int strongCount))
|
||||
{
|
||||
if (strongCount == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({strongCount}권)";
|
||||
return strongCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 전체 텍스트에서 정규식으로 추출
|
||||
var totalCountText = totalCountElement.Text;
|
||||
var match = Regex.Match(totalCountText, @"전체\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"totalCount 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
// 2. 페이지 소스에서 정규식으로 추출 시도
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다") ||
|
||||
pageSource.Contains("자료가 없습니다") ||
|
||||
pageSource.Contains("전체 0 건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건",
|
||||
@"전체\s+(\d+)\s+건",
|
||||
@"총\s*(\d+)\s*권",
|
||||
@"총\s*(\d+)\s*건",
|
||||
@"검색결과\s*:\s*(\d+)"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var pageSource = d.PageSource;
|
||||
// 검색 결과나 관련 요소가 나타나면 로드 완료
|
||||
return pageSource.Contains("searchTitle") ||
|
||||
pageSource.Contains("totalCount") ||
|
||||
pageSource.Contains("검색결과") ||
|
||||
pageSource.Contains("전체") ||
|
||||
pageSource.Contains("자료가");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(3000);
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
unimarc/unimarc/SearchModel/BukguPublicLibSearcher.cs
Normal file
30
unimarc/unimarc/SearchModel/BukguPublicLibSearcher.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using AR;
|
||||
using AR.Dialog;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UniMarc.SearchModel;
|
||||
using UniMarc.마크;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class BukguPublicLibSearcher : BukguLibSearcher
|
||||
{
|
||||
|
||||
public BukguPublicLibSearcher(int no, string areaCode, string areaName) : base(no, areaCode, areaName)
|
||||
{
|
||||
this.SiteName = $"광주북구공공도서관({areaName})";
|
||||
base.SiteUrl = "https://lib.bukgu.gwangju.kr/main/bookSearch.do?PID=0301";
|
||||
}
|
||||
}
|
||||
}
|
||||
30
unimarc/unimarc/SearchModel/BukguSlibSearcher.cs
Normal file
30
unimarc/unimarc/SearchModel/BukguSlibSearcher.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using AR;
|
||||
using AR.Dialog;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UniMarc.SearchModel;
|
||||
using UniMarc.마크;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class BukguSlibSearcher : BukguLibSearcher
|
||||
{
|
||||
|
||||
public BukguSlibSearcher(int no, string areaCode, string areaName) : base(no, areaCode, areaName)
|
||||
{
|
||||
this.SiteName = $"광주북구작은도서관({areaName})";
|
||||
base.SiteUrl = "https://lib.bukgu.gwangju.kr/main/bookSearchSlib.do?PID=0301";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace BokBonCheck
|
||||
{
|
||||
public class DLSSearcher : ILibrarySearcher
|
||||
{
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
public string SiteName { get; protected set; } = "DLS";
|
||||
public string SiteUrl => "https://dls1.edunet.net/DLS/bookMng/bookMain";
|
||||
|
||||
|
||||
423
unimarc/unimarc/SearchModel/GoheungLibSearcher.cs
Normal file
423
unimarc/unimarc/SearchModel/GoheungLibSearcher.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class GoheungLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://www.ghlib.go.kr/BookSearch/detail";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public GoheungLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"고흥군립({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("GoheungLibSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"GoheungLibSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"GoheungLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 전체 선택인 경우
|
||||
if (string.IsNullOrEmpty(AreaCode) || AreaCode == "ALL")
|
||||
{
|
||||
var allRadio = wait.Until(d => d.FindElement(By.Id("libALL")));
|
||||
if (!allRadio.Selected)
|
||||
{
|
||||
SafeClick(allRadio);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("전체도서관 선택됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("전체도서관이 이미 선택되어 있음");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 특정 도서관 선택인 경우
|
||||
var targetRadioId = $"lib{AreaCode}";
|
||||
var targetRadio = wait.Until(d => d.FindElement(By.Id(targetRadioId)));
|
||||
|
||||
if (targetRadio == null)
|
||||
{
|
||||
Console.WriteLine($"도서관 라디오 버튼을 찾을 수 없습니다: {targetRadioId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 이미 선택되어 있지 않으면 선택
|
||||
if (!targetRadio.Selected)
|
||||
{
|
||||
SafeClick(targetRadio);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{AreaCode} 도서관으로 변경됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{AreaCode} 도서관이 이미 선택되어 있음");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void SafeClick(IWebElement element)
|
||||
{
|
||||
// 안정적인 클릭을 위한 여러 방법 시도
|
||||
try
|
||||
{
|
||||
// 1. JavaScript로 클릭 시도
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click();", element);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. 요소가 보이도록 스크롤 후 클릭
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
|
||||
Thread.Sleep(500);
|
||||
element.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3. Actions 클래스 사용
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
var actions = new OpenQA.Selenium.Interactions.Actions(driver);
|
||||
actions.MoveToElement(element).Click().Perform();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 4. 마지막 방법: JavaScript로 직접 체크
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].checked = true;", element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 도서명 입력
|
||||
try
|
||||
{
|
||||
var titleInput = wait.Until(d => d.FindElement(By.Id("queryTitle")));
|
||||
titleInput.Clear();
|
||||
titleInput.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"도서명입력실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭
|
||||
try
|
||||
{
|
||||
var searchButton = wait.Until(d => d.FindElement(By.CssSelector("button[type='submit']")));
|
||||
searchButton.Click();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼클릭실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 1. 먼저 totalCount 요소에서 직접 추출 시도
|
||||
try
|
||||
{
|
||||
var totalCountElement = driver.FindElement(By.CssSelector("p.totalCount"));
|
||||
if (totalCountElement != null)
|
||||
{
|
||||
var totalCountText = totalCountElement.Text; // 예: "전체 1 건"
|
||||
var match = Regex.Match(totalCountText, @"전체\s+(\d+)\s+건", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
// strong 태그에서 직접 숫자 추출 시도
|
||||
try
|
||||
{
|
||||
var strongElement = totalCountElement.FindElement(By.TagName("strong"));
|
||||
if (strongElement != null && int.TryParse(strongElement.Text, out int strongCount))
|
||||
{
|
||||
if(strongCount == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
errmessage = $"검색성공({strongCount}권)";
|
||||
return strongCount;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"totalCount 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
// 2. 페이지 소스에서 정규식으로 추출 시도
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다") ||
|
||||
pageSource.Contains("자료가 없습니다") ||
|
||||
pageSource.Contains("전체 0 건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 "전체 <strong>N</strong> 건" 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"전체\s*<strong>(\d+)</strong>\s*건",
|
||||
@"전체\s+(\d+)\s+건",
|
||||
@"총\s*(\d+)\s*권",
|
||||
@"총\s*(\d+)\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 결과 테이블이나 리스트가 있는지 확인
|
||||
try
|
||||
{
|
||||
var resultElements = driver.FindElements(By.CssSelector(".bookList, .searchResult, .result-list, table tbody tr"));
|
||||
if (resultElements.Count > 0)
|
||||
{
|
||||
// 테이블 헤더나 빈 행을 제외한 실제 결과 개수 계산
|
||||
var actualCount = 0;
|
||||
foreach (var element in resultElements)
|
||||
{
|
||||
var text = element.Text?.Trim();
|
||||
if (!string.IsNullOrEmpty(text) &&
|
||||
!text.Contains("도서명") &&
|
||||
!text.Contains("저자") &&
|
||||
!text.Contains("출판사"))
|
||||
{
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualCount > 0)
|
||||
{
|
||||
errmessage = $"검색성공({actualCount}권)";
|
||||
return actualCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"결과 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var pageSource = d.PageSource;
|
||||
// 검색 결과나 "검색결과가 없습니다" 메시지가 나타나면 로드 완료
|
||||
return pageSource.Contains("검색결과") ||
|
||||
pageSource.Contains("총") ||
|
||||
pageSource.Contains("자료가") ||
|
||||
pageSource.Contains("bookList") ||
|
||||
pageSource.Contains("searchResult");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(3000);
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
346
unimarc/unimarc/SearchModel/GwangjuCityLibSearcher.cs
Normal file
346
unimarc/unimarc/SearchModel/GwangjuCityLibSearcher.cs
Normal file
@@ -0,0 +1,346 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class GwangjuCityLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://citylib.gwangju.go.kr/main/bookSearch";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public GwangjuCityLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"광주시립({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("GwangjuCityLibSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"GwangjuCityLibSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"GwangjuCityLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 도서관 선택
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
var libSelect = wait.Until(d => d.FindElement(By.CssSelector("select[name='libCode']")));
|
||||
var selectElement = new SelectElement(libSelect);
|
||||
selectElement.SelectByValue(AreaCode);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{AreaCode} 도서관으로 선택됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("전체 도서관으로 검색");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색어 입력
|
||||
try
|
||||
{
|
||||
var searchInput = wait.Until(d => d.FindElement(By.Id("bookSearchQuery")));
|
||||
searchInput.Clear();
|
||||
searchInput.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색어입력실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭
|
||||
try
|
||||
{
|
||||
var searchButton = wait.Until(d => d.FindElement(By.CssSelector("button.bookSearchBtn")));
|
||||
searchButton.Click();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼클릭실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
var noResultElement = driver.FindElement(By.XPath("//p[contains(text(), '조회된 도서가 없습니다')]"));
|
||||
if (noResultElement != null)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
// 2. srch_info div에서 직접 추출 시도
|
||||
try
|
||||
{
|
||||
var srchInfoElement = driver.FindElement(By.CssSelector("div.srch_info"));
|
||||
if (srchInfoElement != null)
|
||||
{
|
||||
// span.heighlight에서 숫자 추출 시도
|
||||
try
|
||||
{
|
||||
var highlightElement = srchInfoElement.FindElement(By.CssSelector("span.heighlight"));
|
||||
if (highlightElement != null)
|
||||
{
|
||||
var countText = highlightElement.Text.Trim();
|
||||
if (int.TryParse(countText, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 전체 텍스트에서 정규식으로 추출
|
||||
var srchInfoText = srchInfoElement.Text;
|
||||
var match = Regex.Match(srchInfoText, @"검색결과\s*총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"srch_info 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
// 3. 페이지 소스에서 정규식으로 추출 시도
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("조회된 도서가 없습니다") ||
|
||||
pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"검색결과\s*총\s*<span[^>]*class=""heighlight""[^>]*>\s*(\d+)\s*</span>\s*건",
|
||||
@"검색결과\s*총\s*(\d+)\s*건",
|
||||
@"<span[^>]*class=""heighlight""[^>]*>\s*(\d+)\s*</span>",
|
||||
@"총\s*(\d+)\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var pageSource = d.PageSource;
|
||||
// 검색 결과나 관련 요소가 나타나면 로드 완료
|
||||
return pageSource.Contains("srch_info") ||
|
||||
pageSource.Contains("검색결과") ||
|
||||
pageSource.Contains("조회된 도서가 없습니다") ||
|
||||
pageSource.Contains("총") ||
|
||||
pageSource.Contains("건");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(3000);
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
unimarc/unimarc/SearchModel/GwangsanLibSearcher.cs
Normal file
181
unimarc/unimarc/SearchModel/GwangsanLibSearcher.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Text;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class GwangsanLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://lib.gwangsan.go.kr/main/bookSearch/advanced";
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public GwangsanLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"광주광산구({areaName})";
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = HttpUtility.UrlEncode(searchTerm, Encoding.UTF8);
|
||||
|
||||
// 상세검색 URL 구성 (도서명만 검색)
|
||||
var searchUrl = $"{SiteUrl}?query={encodedSearchTerm}&queryPublisher=&queryAuthor=&queryPubYearFr=&queryPubYearTo=";
|
||||
|
||||
// 도서관 코드가 있으면 추가
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
searchUrl += $"&libCodeArr={AreaCode}";
|
||||
}
|
||||
|
||||
Console.WriteLine($"광주광산구 검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행
|
||||
var response = await _httpClient.GetAsync(searchUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = $"검색 오류: {ex.Message}";
|
||||
result.BookCount = 0;
|
||||
Console.WriteLine($"광주광산구 검색 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 검색 결과가 없는 경우 확인
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 "전체 <strong>N</strong> 건" 패턴 찾기
|
||||
var patterns = new[]
|
||||
{
|
||||
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건",
|
||||
@"전체\s+(\d+)\s+건",
|
||||
@"총\s*(\d+)\s*권",
|
||||
@"총\s*(\d+)\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 더 자세한 패턴으로 시도 (줄바꿈 포함)
|
||||
var multilinePatterns = new[]
|
||||
{
|
||||
@"전체\s*<strong>\s*\r?\n?\s*(\d+)\s*\r?\n?\s*</strong>\s*건",
|
||||
@"<strong>\s*\r?\n?\s*(\d+)\s*\r?\n?\s*</strong>\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in multilinePatterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public Task WaitForPageChange(OpenQA.Selenium.Support.UI.WebDriverWait wait)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,10 @@ namespace BokBonCheck
|
||||
|
||||
public interface ILibrarySearcher
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ũ<>Ѹ<EFBFBD><D1B8><EFBFBD> <20>ƴ<EFBFBD> HTTP ȣ<><C8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ó<><C3B3><EFBFBD>˴ϴ<CBB4>
|
||||
/// </summary>
|
||||
bool HttpApiMode { get; set; }
|
||||
int No { get; set; }
|
||||
string SiteName { get; }
|
||||
string SiteUrl { get; }
|
||||
|
||||
166
unimarc/unimarc/SearchModel/IksanLibSearcher.cs
Normal file
166
unimarc/unimarc/SearchModel/IksanLibSearcher.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic; // Added missing import
|
||||
using OpenQA.Selenium.Support.UI; // Added missing import
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class IksanLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://lib.iksan.go.kr/main/site/search/bookSearch.do";
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public IksanLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"익산시립({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = System.Web.HttpUtility.UrlEncode(searchTerm, System.Text.Encoding.UTF8);
|
||||
|
||||
// 검색 URL 구성 - GET 방식으로 URL 파라미터 전송
|
||||
var searchUrl = $"{SiteUrl}?cmd_name=bookandnonbooksearch&search_type=detail&detail=OK&use_facet=N&all_lib=N&search_item=search_title&search_txt=&search_title={encodedSearchTerm}";
|
||||
|
||||
// 도서관 코드가 있으면 추가
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
searchUrl += $"&manage_code={AreaCode}";
|
||||
}
|
||||
|
||||
Console.WriteLine($"익산시통합도서관 검색 요청: {searchTerm}, 도서관코드: {AreaCode}");
|
||||
Console.WriteLine($"검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행
|
||||
var response = await _httpClient.GetAsync(searchUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 실제 HTML 구조에 맞는 패턴으로 수정
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
// "상세검색결과 <strong>3</strong>개" 패턴 (실제 구조)
|
||||
@"상세검색결과\s*<strong[^>]*>\s*(\d+)\s*</strong>\s*개",
|
||||
// "전체 <strong class="word">1</strong>개가 검색되었습니다" 패턴 (이전 패턴)
|
||||
@"전체\s*<strong[^>]*class=""word""[^>]*>\s*(\d+)\s*</strong>\s*개가\s*검색되었습니다",
|
||||
// "전체 <strong class="word">0</strong>개가 검색되었습니다" 패턴 (0인 경우)
|
||||
@"전체\s*<strong[^>]*class=""word""[^>]*>\s*0\s*</strong>\s*개가\s*검색되었습니다",
|
||||
// 일반적인 "전체 X개가 검색되었습니다" 패턴
|
||||
@"전체\s*(\d+)\s*개가\s*검색되었습니다",
|
||||
// 숫자만 찾는 패턴 (마지막 수단)
|
||||
@"(\d+)\s*개가\s*검색되었습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
// 0인 경우를 먼저 확인
|
||||
if (pattern.Contains(@"\s*0\s*"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 숫자 추출
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 디버깅을 위해 HTML 내용 일부 출력
|
||||
Console.WriteLine($"HTML 내용 일부: {htmlContent.Substring(0, Math.Min(1000, htmlContent.Length))}");
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드 (HTTP 방식에서는 불필요)
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
// HTTP 방식에서는 즉시 응답이 오므로 대기 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
404
unimarc/unimarc/SearchModel/JeonbukEduLibSearcher.cs
Normal file
404
unimarc/unimarc/SearchModel/JeonbukEduLibSearcher.cs
Normal file
@@ -0,0 +1,404 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class JeonbukEduLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://lib.jbe.go.kr/jbe/intro/search/index.do";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public JeonbukEduLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"전북교육청({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("JeonbukEduLibSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"JeonbukEduLibSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"JeonbukEduLibSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 전체 선택인 경우 - 모든 체크박스 선택
|
||||
if (string.IsNullOrEmpty(AreaCode) || AreaCode == "ALL")
|
||||
{
|
||||
var allCheckboxes1 = wait.Until(d => d.FindElements(By.CssSelector("input[name='libraryCodes']")));
|
||||
foreach (var checkbox in allCheckboxes1)
|
||||
{
|
||||
if (!checkbox.Selected)
|
||||
{
|
||||
SafeClick(checkbox);
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("전체 도서관 선택됨");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 특정 도서관 선택인 경우
|
||||
var targetCheckbox = wait.Until(d => d.FindElement(By.CssSelector($"input[name='libraryCodes'][value='{AreaCode}']")));
|
||||
|
||||
if (targetCheckbox == null)
|
||||
{
|
||||
Console.WriteLine($"도서관 체크박스를 찾을 수 없습니다: {AreaCode}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 다른 체크박스들 해제
|
||||
var allCheckboxes = wait.Until(d => d.FindElements(By.CssSelector("input[name='libraryCodes']")));
|
||||
foreach (var checkbox in allCheckboxes)
|
||||
{
|
||||
if (checkbox.GetAttribute("value") != AreaCode && checkbox.Selected)
|
||||
{
|
||||
SafeClick(checkbox);
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
// 대상 체크박스 선택
|
||||
if (!targetCheckbox.Selected)
|
||||
{
|
||||
SafeClick(targetCheckbox);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{AreaCode} 도서관으로 변경됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{AreaCode} 도서관이 이미 선택되어 있음");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void SafeClick(IWebElement element)
|
||||
{
|
||||
// 안정적인 클릭을 위한 여러 방법 시도
|
||||
try
|
||||
{
|
||||
// 1. JavaScript로 클릭 시도
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click();", element);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. 요소가 보이도록 스크롤 후 클릭
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
|
||||
Thread.Sleep(500);
|
||||
element.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3. Actions 클래스 사용
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
var actions = new OpenQA.Selenium.Interactions.Actions(driver);
|
||||
actions.MoveToElement(element).Click().Perform();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 4. 마지막 방법: JavaScript로 직접 체크 상태 변경
|
||||
var driver = ((IWrapsDriver)element).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].checked = !arguments[0].checked;", element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색어 입력
|
||||
try
|
||||
{
|
||||
var searchInput = wait.Until(d => d.FindElement(By.Id("search_text")));
|
||||
searchInput.Clear();
|
||||
searchInput.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색어입력실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭
|
||||
try
|
||||
{
|
||||
var searchButton = wait.Until(d => d.FindElement(By.Id("do-search")));
|
||||
searchButton.Click();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼클릭실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 1. search-info div에서 직접 추출 시도
|
||||
try
|
||||
{
|
||||
var searchInfoElement = driver.FindElement(By.CssSelector("div.search-info"));
|
||||
if (searchInfoElement != null)
|
||||
{
|
||||
var searchInfoText = searchInfoElement.Text;
|
||||
|
||||
// "총 N건이 검색되었습니다" 패턴 찾기
|
||||
var match = Regex.Match(searchInfoText, @"총\s*(\d+)\s*건이\s*검색되었습니다", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
// <b> 태그에서 직접 숫자 추출 시도
|
||||
try
|
||||
{
|
||||
var boldElements = searchInfoElement.FindElements(By.TagName("b"));
|
||||
foreach (var boldElement in boldElements)
|
||||
{
|
||||
var boldText = boldElement.Text.Trim();
|
||||
if (int.TryParse(boldText, out int boldCount))
|
||||
{
|
||||
if (boldCount == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({boldCount}권)";
|
||||
return boldCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"search-info 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
// 2. 페이지 소스에서 정규식으로 추출 시도
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("0건이 검색되었습니다") ||
|
||||
pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"총\s*<b>(\d+)</b>\s*건이\s*검색되었습니다",
|
||||
@"총\s*(\d+)\s*건이\s*검색되었습니다",
|
||||
@"총\s*<b>\s*(\d+)\s*</b>\s*건",
|
||||
@"총\s*(\d+)\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var pageSource = d.PageSource;
|
||||
// search-info div나 검색 결과 관련 요소가 나타나면 로드 완료
|
||||
return pageSource.Contains("search-info") ||
|
||||
pageSource.Contains("검색되었습니다") ||
|
||||
pageSource.Contains("검색결과") ||
|
||||
pageSource.Contains("총") ||
|
||||
pageSource.Contains("건이");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(3000);
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
413
unimarc/unimarc/SearchModel/JunnamEduJiheaNuriSearcher.cs
Normal file
413
unimarc/unimarc/SearchModel/JunnamEduJiheaNuriSearcher.cs
Normal file
@@ -0,0 +1,413 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
|
||||
public class JunnamEduJiheaNuriSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://jnelib.jne.go.kr/book/search_book/search.es?mid=d20101000000";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
public JunnamEduJiheaNuriSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"전남교육청행정자료실({areaName})";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
if (_driver != null)
|
||||
{
|
||||
_driver.Quit();
|
||||
_driver.Dispose();
|
||||
_driver = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
if (_driver == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SeleniumHelper.IsReady == false) await SeleniumHelper.Download();
|
||||
_driver = await SeleniumHelper.CreateDriver(ShowBrowser: showdriver);
|
||||
Console.WriteLine("JunnamEduJiheaNuriSearcher Driver 초기화 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"JunnamEduJiheaNuriSearcher Driver 초기화 실패: {ex.Message}");
|
||||
throw new InvalidOperationException($"JunnamEduJiheaNuriSearcher Driver 초기화에 실패했습니다: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual protected bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.AreaCode.isEmpty()) return true;
|
||||
|
||||
|
||||
|
||||
// Areacode가 "ALL"인 경우
|
||||
if (AreaCode == "ALL")
|
||||
{
|
||||
var allCheckbox = wait.Until(d => d.FindElement(By.Id("all_srch")));
|
||||
if (!allCheckbox.Selected)
|
||||
{
|
||||
SafeClick(allCheckbox);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("전체 선택으로 변경됨");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("전체 선택이 이미 활성화되어 있음");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 특정 지역 선택인 경우
|
||||
var targetSelector = $"libInfo_{AreaCode}";
|
||||
var targetCheckbox = wait.Until(d => d.FindElement(By.Id(targetSelector)));
|
||||
|
||||
if (targetCheckbox == null)
|
||||
{
|
||||
Console.WriteLine($"도서관 체크박스를 찾을 수 없습니다: {targetSelector}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 전체 선택이 되어 있으면 해제
|
||||
var allCheckbox2 = wait.Until(d => d.FindElement(By.Id("all_srch")));
|
||||
if (allCheckbox2.Selected)
|
||||
{
|
||||
SafeClick(allCheckbox2);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("전체 선택 해제됨");
|
||||
}
|
||||
|
||||
// 대상 지역 선택
|
||||
if (!targetCheckbox.Selected)
|
||||
{
|
||||
SafeClick(targetCheckbox);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{AreaCode} 지역으로 변경됨");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 선택 실패: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void SafeClick(IWebElement searchBox)
|
||||
{
|
||||
// 안정적인 클릭을 위한 여러 방법 시도
|
||||
try
|
||||
{
|
||||
// 1. JavaScript로 클릭 시도
|
||||
var driver = ((IWrapsDriver)searchBox).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click();", searchBox);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. 요소가 보이도록 스크롤 후 클릭
|
||||
var driver = ((IWrapsDriver)searchBox).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", searchBox);
|
||||
Thread.Sleep(500);
|
||||
searchBox.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// 3. Actions 클래스 사용
|
||||
var driver = ((IWrapsDriver)searchBox).WrappedDriver;
|
||||
var actions = new OpenQA.Selenium.Interactions.Actions(driver);
|
||||
actions.MoveToElement(searchBox).Click().Perform();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 4. 마지막 방법: JavaScript로 직접 체크 해제
|
||||
var driver = ((IWrapsDriver)searchBox).WrappedDriver;
|
||||
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].checked = false;", searchBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 드라이버가 없으면 자동으로 시작
|
||||
if (_driver == null)
|
||||
{
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
|
||||
// 도서관 선택
|
||||
if (SelectLibrary(wait) == false)
|
||||
{
|
||||
result.ErrorMessage = "도서관선택실패";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 방법을 서명으로 변경
|
||||
try
|
||||
{
|
||||
var searchKeyWordSelect = wait.Until(d => d.FindElement(By.Id("searchKeyWord")));
|
||||
var selectElement = new SelectElement(searchKeyWordSelect);
|
||||
selectElement.SelectByValue("1"); // 1 = 서명
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색방법선택실패({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색어 입력
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
searchBox = wait.Until(d => d.FindElement(By.Id("searchWordText")));
|
||||
searchBox.Clear();
|
||||
searchBox.SendKeys(searchTerm);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색창없음({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭
|
||||
IWebElement searchButton = null;
|
||||
try
|
||||
{
|
||||
searchButton = _driver.FindElement(By.CssSelector("button[type='submit']"));
|
||||
if (searchButton != null)
|
||||
searchButton.Click();
|
||||
else
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼없음";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorMessage = $"검색버튼없음({ex.Message})";
|
||||
result.BookCount = -1;
|
||||
result.IsSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = ermsg;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 먼저 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
var noResultDiv = driver.FindElement(By.CssSelector(".SearchResult .resultBook"));
|
||||
var noResultText = noResultDiv.Text;
|
||||
if (noResultText.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 없는 경우 div가 없을 수도 있음
|
||||
}
|
||||
|
||||
// 검색결과가 있는 경우 p.page_info에서 전체 건수 추출
|
||||
try
|
||||
{
|
||||
var pageInfo = driver.FindElement(By.CssSelector("p.page_info"));
|
||||
var pageInfoText = pageInfo.Text; // 예: "전체 7건, 현재 페이지 1/1"
|
||||
|
||||
var match = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체\s*(\d+)건");
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int vqty))
|
||||
{
|
||||
errmessage = $"검색성공({vqty}건)";
|
||||
return vqty;
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = $"수량값오류({match.Groups[1].Value})";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = "수량항목없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// page_info가 없는 경우 검색결과가 없는 것으로 판단
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
// 페이지 로딩 상태 확인
|
||||
wait.Until(d =>
|
||||
{
|
||||
var readyState = ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState");
|
||||
return readyState.Equals("complete");
|
||||
});
|
||||
|
||||
// 검색 결과 페이지가 로드될 때까지 대기
|
||||
wait.Until(d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
var noResultDiv = d.FindElement(By.CssSelector(".SearchResult .resultBook"));
|
||||
if (noResultDiv.Text.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
return true; // 검색결과 없음 페이지 로드 완료
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
// 검색결과가 있는 경우 page_info 확인
|
||||
try
|
||||
{
|
||||
var pageInfo = d.FindElement(By.CssSelector("p.page_info"));
|
||||
var pageInfoText = pageInfo.Text;
|
||||
// "전체 N건" 형식이 나타나면 로드 완료
|
||||
return pageInfoText.Contains("전체") && pageInfoText.Contains("건");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 모든 감지 방법이 실패하면 최소한의 대기 시간 적용
|
||||
await Task.Delay(2000);
|
||||
throw new Exception($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,10 @@ namespace BokBonCheck
|
||||
|
||||
public class JunnamEduSearcher : ILibrarySearcher
|
||||
{
|
||||
public string Areacode { get; set; } = string.Empty;
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://jnelib.jne.go.kr/book/search_book/search.es?mid=d50101000000";
|
||||
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
@@ -30,7 +30,7 @@ namespace BokBonCheck
|
||||
public JunnamEduSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.Areacode = areaCode;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"전남교육청({areaName})";
|
||||
}
|
||||
|
||||
@@ -71,28 +71,28 @@ namespace BokBonCheck
|
||||
try
|
||||
{
|
||||
// Areacode가 "ALL"인 경우
|
||||
if (Areacode == "ALL")
|
||||
if (AreaCode == "ALL")
|
||||
{
|
||||
var allCheckbox = wait.Until(d => d.FindElement(By.CssSelector("#all_srch")));
|
||||
|
||||
var allCheckbox1 = wait.Until(d => d.FindElement(By.CssSelector("#all_srch")));
|
||||
|
||||
// 이미 전체가 선택되어 있으면 변경하지 않음
|
||||
if (allCheckbox.Selected)
|
||||
if (allCheckbox1.Selected)
|
||||
{
|
||||
Console.WriteLine("전체 선택이 이미 활성화되어 있음");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 전체 선택이 안되어 있으면 활성화
|
||||
SafeClick(allCheckbox);
|
||||
SafeClick(allCheckbox1);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine("전체 선택으로 변경됨");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 특정 지역 선택인 경우
|
||||
var targetSelector = $"#libInfo_{Areacode}";
|
||||
var targetSelector = $"#libInfo_{AreaCode}";
|
||||
var targetCheckbox = wait.Until(d => d.FindElement(By.CssSelector(targetSelector)));
|
||||
|
||||
|
||||
if (targetCheckbox == null)
|
||||
{
|
||||
Console.WriteLine($"도서관 체크박스를 찾을 수 없습니다: {targetSelector}");
|
||||
@@ -107,7 +107,7 @@ namespace BokBonCheck
|
||||
// 이미 원하는 지역이 선택되어 있고, 전체 선택이 해제되어 있으면 변경하지 않음
|
||||
if (isTargetSelected && !isAllSelected)
|
||||
{
|
||||
Console.WriteLine($"{Areacode} 지역이 이미 선택되어 있음");
|
||||
Console.WriteLine($"{AreaCode} 지역이 이미 선택되어 있음");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -124,9 +124,9 @@ namespace BokBonCheck
|
||||
{
|
||||
SafeClick(targetCheckbox);
|
||||
Thread.Sleep(300);
|
||||
Console.WriteLine($"{Areacode} 지역으로 변경됨");
|
||||
Console.WriteLine($"{AreaCode} 지역으로 변경됨");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -191,7 +191,9 @@ namespace BokBonCheck
|
||||
await StartDriver();
|
||||
}
|
||||
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
var cururl = _driver.Url;
|
||||
if (cururl.Equals(SiteUrl) == false)
|
||||
_driver.Navigate().GoToUrl(SiteUrl);
|
||||
|
||||
// 페이지 로딩 대기
|
||||
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(15));
|
||||
@@ -247,7 +249,7 @@ namespace BokBonCheck
|
||||
try
|
||||
{
|
||||
searchButton = _driver.FindElement(By.CssSelector("button[type='submit']"));
|
||||
if(searchButton != null)
|
||||
if (searchButton != null)
|
||||
searchButton.Click();
|
||||
else
|
||||
{
|
||||
@@ -321,7 +323,7 @@ namespace BokBonCheck
|
||||
{
|
||||
var pageInfo = driver.FindElement(By.CssSelector("p.page_info"));
|
||||
var pageInfoText = pageInfo.Text; // 예: "전체 7건, 현재 페이지 1/1"
|
||||
|
||||
|
||||
var match = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체\s*(\d+)건");
|
||||
if (match.Success)
|
||||
{
|
||||
|
||||
@@ -13,73 +13,23 @@ using OpenQA.Selenium.Chromium;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class KwangjuCityLibrarySearcher_choisangjun : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_choisangjun(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "MF";
|
||||
SiteName = "광주시교육청통합도서관(분관최상준도서관)";
|
||||
}
|
||||
}
|
||||
public class KwangjuCityLibrarySearcher_dagachi : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_dagachi(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "ME";
|
||||
SiteName = "광주시교육청통합도서관(송정다가치문화도서관)";
|
||||
}
|
||||
}
|
||||
public class KwangjuCityLibrarySearcher_central : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_central(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "MD";
|
||||
SiteName = "광주시교육청통합도서관(중앙도서관)";
|
||||
}
|
||||
}
|
||||
public class KwangjuCityLibrarySearcher_Student : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_Student(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "MC";
|
||||
SiteName = "광주시교육청통합도서관(학생교육문화회관)";
|
||||
}
|
||||
}
|
||||
public class KwangjuCityLibrarySearcher_Kumho : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_Kumho(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "MB";
|
||||
SiteName = "광주시교육청통합도서관(금호평생교육관)";
|
||||
}
|
||||
}
|
||||
public class KwangjuCityLibrarySearcher_Indi : KwangjuCityLibrarySearcher
|
||||
{
|
||||
public KwangjuCityLibrarySearcher_Indi(int no) : base(no)
|
||||
{
|
||||
SelectorValue = "MA";
|
||||
SiteName = "광주시교육청통합도서관(학생독립운동기념회관)";
|
||||
}
|
||||
}
|
||||
public abstract class KwangjuCityLibrarySearcher : ILibrarySearcher
|
||||
public class KwangjuCityEduLibrarySearcher : ILibrarySearcher
|
||||
{
|
||||
public int No { get; set; }
|
||||
|
||||
protected string AreaCode = "";
|
||||
public string SiteName { get; protected set; } = "광주시교육청통합도서관";
|
||||
public string SiteUrl => "https://lib.gen.go.kr/main/site/search/bookSearch.do#simple";
|
||||
|
||||
protected string SelectorValue = "";
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
private const int SW_MINIMIZE = 6;
|
||||
|
||||
public KwangjuCityLibrarySearcher(int no)
|
||||
public KwangjuCityEduLibrarySearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"광주시교육청통합도서관({areaName})";
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showBrowser = false)
|
||||
@@ -119,7 +69,7 @@ namespace BokBonCheck
|
||||
var select = new OpenQA.Selenium.Support.UI.SelectElement(selectElement);
|
||||
|
||||
// value가 "MA"인 옵션 선택
|
||||
select.SelectByValue(SelectorValue);
|
||||
select.SelectByValue(AreaCode);
|
||||
}
|
||||
catch
|
||||
{
|
||||
188
unimarc/unimarc/SearchModel/MokpoLibSearcher.cs
Normal file
188
unimarc/unimarc/SearchModel/MokpoLibSearcher.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Text;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class MokpoLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://mokpolib.or.kr/dls_lt/index.php";
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public MokpoLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"목포시립({areaName})";
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = HttpUtility.UrlEncode(searchTerm, Encoding.UTF8);
|
||||
|
||||
// 검색 URL 구성
|
||||
var searchUrl = $"{SiteUrl}?mod=wdDataSearch&act=searchResultList&manageSearch=&detailSearch=";
|
||||
|
||||
// 도서관 코드가 있으면 추가
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
searchUrl += $"&manageCode%5B{AreaCode}%5D={AreaCode}";
|
||||
}
|
||||
|
||||
// 검색 방식을 제목으로 설정하고 검색어 추가
|
||||
searchUrl += $"&searchItem%5B%5D=title&searchWord%5B%5D={encodedSearchTerm}";
|
||||
|
||||
Console.WriteLine($"목포시립도서관 검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행
|
||||
var response = await _httpClient.GetAsync(searchUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = $"검색 오류: {ex.Message}";
|
||||
result.BookCount = 0;
|
||||
Console.WriteLine($"목포시립도서관 검색 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// HTML에서 "총 <strong class="cyan">N권(개)</strong>" 패턴 찾기
|
||||
var patterns = new[]
|
||||
{
|
||||
@"총\s*<strong[^>]*class=""cyan""[^>]*>(\d+)권\(개\)</strong>",
|
||||
@"총\s*<strong[^>]*>(\d+)권\(개\)</strong>",
|
||||
@"총\s*(\d+)권\(개\)",
|
||||
@"총\s*<strong[^>]*class=""cyan""[^>]*>(\d+)</strong>",
|
||||
@"총\s*<strong[^>]*>(\d+)</strong>"
|
||||
};
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다") ||
|
||||
htmlContent.Contains("총 0권(개)"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 더 넓은 범위로 숫자 찾기 시도
|
||||
var generalPatterns = new[]
|
||||
{
|
||||
@"총\s*.*?(\d+)\s*권",
|
||||
@"총\s*.*?(\d+)\s*개",
|
||||
@"총\s*.*?(\d+)",
|
||||
@"<strong[^>]*class=""cyan""[^>]*>(\d+)</strong>"
|
||||
};
|
||||
|
||||
foreach (var pattern in generalPatterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public Task WaitForPageChange(OpenQA.Selenium.Support.UI.WebDriverWait wait)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,198 +17,14 @@ using System.Runtime.CompilerServices;
|
||||
namespace BokBonCheck
|
||||
{
|
||||
|
||||
|
||||
public class NamguLibrarySearcher_Munhwa : NamguLibrarySearcher
|
||||
{
|
||||
public NamguLibrarySearcher_Munhwa(int no) : base(no)
|
||||
{
|
||||
SiteName = "남구통합도서관(문화정보도서관)"; // 문화관 검색기
|
||||
}
|
||||
|
||||
protected override bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
selector = "#libMA";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class NamguLibrarySearcher_Purungil : NamguLibrarySearcher
|
||||
{
|
||||
public NamguLibrarySearcher_Purungil(int no) : base(no)
|
||||
{
|
||||
SiteName = "남구통합도서관(푸른길도서관)";
|
||||
}
|
||||
|
||||
protected override bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
selector = "#libMB";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class NamguLibrarySearcher_Children : NamguLibrarySearcher
|
||||
{
|
||||
public NamguLibrarySearcher_Children(int no) : base(no)
|
||||
{
|
||||
SiteName = "남구통합도서관(청소년도서관)";
|
||||
}
|
||||
|
||||
protected override bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
|
||||
}
|
||||
|
||||
selector = "#libMC";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
//searchBox.Click(); // 체크박스 선택
|
||||
SafeClick(searchBox);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class NamguLibrarySearcher_Hyocheon : NamguLibrarySearcher
|
||||
{
|
||||
public NamguLibrarySearcher_Hyocheon(int no) : base(no)
|
||||
{
|
||||
SiteName = "남구통합도서관(효천어울림도서관)";
|
||||
}
|
||||
|
||||
|
||||
protected override bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
|
||||
selector = "#libSW";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class NamguLibrarySearcher_Smart : NamguLibrarySearcher
|
||||
{
|
||||
public NamguLibrarySearcher_Smart(int no) : base(no)
|
||||
{
|
||||
SiteName = "남구통합도서관(스마트도서관)";
|
||||
}
|
||||
|
||||
protected override bool SelectLibrary(WebDriverWait wait)
|
||||
{
|
||||
IWebElement searchBox = null;
|
||||
try
|
||||
{
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
|
||||
selector = "#libSQ";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class NamguLibrarySearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode = "";
|
||||
public string SiteName { get; protected set; } = "남구통합도서관(전체)";
|
||||
public string SiteUrl => "https://lib.namgu.gwangju.kr/main/bookSearch";
|
||||
|
||||
public bool HttpApiMode { get; set; } = false;
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
@@ -219,9 +35,11 @@ namespace BokBonCheck
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
private const int SW_MINIMIZE = 6;
|
||||
|
||||
public NamguLibrarySearcher(int no)
|
||||
public NamguLibrarySearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"남구통합도서관({areaName})";
|
||||
}
|
||||
|
||||
|
||||
@@ -264,15 +82,24 @@ namespace BokBonCheck
|
||||
var selector = "#clickAll";
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == true)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
|
||||
selector = AreaCode;
|
||||
searchBox = wait.Until(d => d.FindElement(By.CssSelector(selector)));
|
||||
if (searchBox == null) return false;
|
||||
if (searchBox.Selected == false)
|
||||
{
|
||||
SafeClick(searchBox);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
229
unimarc/unimarc/SearchModel/SuncheonLibSearcher.cs
Normal file
229
unimarc/unimarc/SearchModel/SuncheonLibSearcher.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Text;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class SuncheonLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://library.suncheon.go.kr/lib/book/search/searchIndex.do";
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private static readonly HttpClient _httpClient = new HttpClient()
|
||||
{
|
||||
DefaultRequestHeaders =
|
||||
{
|
||||
{ "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" }
|
||||
}
|
||||
};
|
||||
|
||||
public SuncheonLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"순천시립({areaName})";
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = HttpUtility.UrlEncode(searchTerm, Encoding.UTF8);
|
||||
|
||||
// 검색 URL 구성
|
||||
var searchUrl = $"{SiteUrl}?menuCd=L001001001&alpha=&vcindex=¤tPageNo=1&nPageSize=10&searchType=title&search={encodedSearchTerm}&mediaCode=";
|
||||
|
||||
// 도서관 코드가 있으면 추가
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
if (AreaCode == "mini")
|
||||
{
|
||||
// 작은도서관의 경우 모든 코드를 포함
|
||||
searchUrl += "&manageCd=AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BF,BG,BH,BI,BJ,BM,BQ,BS,BW,CA,CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK,CL,CM,CN,CO,CP,CQ,DA,DB,DC,DD,DE,DF,DG,DH,DI,DJ,DK,DL,DS,GD";
|
||||
}
|
||||
else
|
||||
{
|
||||
searchUrl += $"&manageCd={AreaCode}";
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"순천시립도서관 검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행 (추가 헤더 포함)
|
||||
using (var request = new HttpRequestMessage(HttpMethod.Get, searchUrl))
|
||||
{
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
|
||||
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3");
|
||||
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
throw new HttpRequestException($"HTTP {(int)response.StatusCode} {response.StatusCode}: {errorContent}");
|
||||
}
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = $"검색 오류: {ex.Message}";
|
||||
result.BookCount = 0;
|
||||
Console.WriteLine($"순천시립도서관 검색 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// HTML에서 "총 <strong class="cred">N</strong>건" 패턴 찾기
|
||||
var patterns = new[]
|
||||
{
|
||||
@"총\s*<strong[^>]*class=""cred""[^>]*>(\d+)</strong>\s*건",
|
||||
@"총\s*<strong[^>]*>(\d+)</strong>\s*건",
|
||||
@"총\s*(\d+)\s*건",
|
||||
@"<strong[^>]*class=""cred""[^>]*>(\d+)</strong>"
|
||||
};
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다") ||
|
||||
htmlContent.Contains("총 0건"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// resultCon 영역에서 더 자세히 검색
|
||||
var resultConPattern = @"<div[^>]*class=""resultCon[^""]*""[^>]*>.*?총\s*<strong[^>]*>(\d+)</strong>\s*건.*?</div>";
|
||||
var resultConMatch = Regex.Match(htmlContent, resultConPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
if (resultConMatch.Success)
|
||||
{
|
||||
if (int.TryParse(resultConMatch.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
// 더 넓은 범위로 숫자 찾기 시도
|
||||
var generalPatterns = new[]
|
||||
{
|
||||
@"검색한\s*결과\s*총\s*<strong[^>]*>(\d+)</strong>",
|
||||
@"검색결과를\s*찾았습니다[^>]*>(\d+)</strong>",
|
||||
@"<strong[^>]*class=""cred""[^>]*>(\d+)</strong>"
|
||||
};
|
||||
|
||||
foreach (var pattern in generalPatterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public Task WaitForPageChange(OpenQA.Selenium.Support.UI.WebDriverWait wait)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
167
unimarc/unimarc/SearchModel/WandoLibSearcher.cs
Normal file
167
unimarc/unimarc/SearchModel/WandoLibSearcher.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
using System.Text.RegularExpressions;
|
||||
using WebDriverManager;
|
||||
using WebDriverManager.DriverConfigs.Impl;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using UniMarc.마크;
|
||||
using OpenQA.Selenium.Chromium;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AR;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
public class WandoLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://wandolib.kr/dls_le/index.php";
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
public int No { get; set; }
|
||||
|
||||
private ChromiumDriver _driver;
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public WandoLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"완도군립({areaName})";
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = System.Web.HttpUtility.UrlEncode(searchTerm, System.Text.Encoding.UTF8);
|
||||
|
||||
// 검색 URL 구성
|
||||
var searchUrl = $"{SiteUrl}?mod=wdDataSearch&act=searchIList&item=title&word={encodedSearchTerm}";
|
||||
|
||||
// 도서관 코드가 있으면 추가
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
searchUrl += $"&manageCode%5B{AreaCode}%5D={AreaCode}";
|
||||
}
|
||||
|
||||
Console.WriteLine($"완도군립도서관 검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행
|
||||
var response = await _httpClient.GetAsync(searchUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = ex.Message;
|
||||
result.BookCount = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
try
|
||||
{
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (htmlContent.Contains("0권(개)") || htmlContent.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@"총\s*<strong[^>]*class=""cyan""[^>]*>\s*(\d+)\s*권\(개\)",
|
||||
@"총\s*(\d+)\s*권\(개\)",
|
||||
@"<strong[^>]*class=""cyan""[^>]*>\s*(\d+)\s*권",
|
||||
@"(\d+)\s*권\(개\)"
|
||||
};
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드 (HTTP 방식에서는 불필요)
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
// HTTP 방식에서는 즉시 응답이 오므로 대기 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
unimarc/unimarc/SearchModel/YeosuLibSearcher.cs
Normal file
162
unimarc/unimarc/SearchModel/YeosuLibSearcher.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Text;
|
||||
using OpenQA.Selenium.Support.UI;
|
||||
|
||||
namespace BokBonCheck
|
||||
{
|
||||
|
||||
public class YeosuLibSearcher : ILibrarySearcher
|
||||
{
|
||||
protected string AreaCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; protected set; }
|
||||
public string SiteUrl => "https://yslib.yeosu.go.kr/dls_kapi/index.php";
|
||||
|
||||
public int No { get; set; }
|
||||
public bool HttpApiMode { get; set; } = true;
|
||||
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public YeosuLibSearcher(int no, string areaCode, string areaName)
|
||||
{
|
||||
this.No = no;
|
||||
this.AreaCode = areaCode;
|
||||
this.SiteName = $"여수시립({areaName})";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task StartDriver(bool showdriver = false)
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 드라이버 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void StopDriver()
|
||||
{
|
||||
// HTTP 클라이언트 사용으로 별도 정리 불필요
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<BookSearchResult> SearchAsync(string searchTerm)
|
||||
{
|
||||
var result = new BookSearchResult
|
||||
{
|
||||
SiteName = SiteName,
|
||||
SearchTerm = searchTerm,
|
||||
SearchTime = DateTime.Now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// 검색어 URL 인코딩
|
||||
var encodedSearchTerm = HttpUtility.UrlEncode(searchTerm, Encoding.UTF8);
|
||||
|
||||
// 검색 URL 구성
|
||||
var searchUrl = $"{SiteUrl}?act=searchResultList&mod=wdDataSearch";
|
||||
|
||||
// 지역코드가 있으면 추가 (전체인 경우 facetManageCode 생략)
|
||||
if (!string.IsNullOrEmpty(AreaCode))
|
||||
{
|
||||
searchUrl += $"&facetManageCode={AreaCode}";
|
||||
}
|
||||
|
||||
searchUrl += $"&searchWord={encodedSearchTerm}&author=&keyword=&publisher=&pubYearS=&pubYearE=&dataSort=rk+desc";
|
||||
|
||||
Console.WriteLine($"여수시립도서관 검색 URL: {searchUrl}");
|
||||
|
||||
// HTTP GET 요청 실행
|
||||
var response = await _httpClient.GetAsync(searchUrl);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = $"검색성공({resultCount}권)";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = $"검색 오류: {ex.Message}";
|
||||
result.BookCount = 0;
|
||||
Console.WriteLine($"여수시립도서관 검색 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// HTML에서 "총 N권(개)" 패턴 찾기
|
||||
var pattern = @"총\s*<strong[^>]*class=""cyan""[^>]*>(\d+)권\(개\)</strong>";
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = $"수량값오류({match.Groups[1].Value})";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 패턴을 찾지 못한 경우 다른 패턴으로 시도
|
||||
var alternatePattern = @"총\s*<strong[^>]*>(\d+)권\(개\)</strong>";
|
||||
var alternateMatch = Regex.Match(htmlContent, alternatePattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (alternateMatch.Success)
|
||||
{
|
||||
if (int.TryParse(alternateMatch.Groups[1].Value, out int count))
|
||||
{
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,22 @@
|
||||
namespace UniMarc.Properties {
|
||||
|
||||
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace UniMarc.Properties {
|
||||
|
||||
|
||||
public class UserSetting : AR.Setting
|
||||
{
|
||||
public string LastSearchTarget { get; set; }
|
||||
public string LastSearchTargetDLS { get; set; }
|
||||
public override void AfterLoad()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void AfterSave()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
// 이 클래스를 사용하여 설정 클래스에 대한 특정 이벤트를 처리할 수 있습니다.
|
||||
// SettingChanging 이벤트는 설정 값이 변경되기 전에 발생합니다.
|
||||
// PropertyChanged 이벤트는 설정 값이 변경된 후에 발생합니다.
|
||||
|
||||
@@ -225,13 +225,27 @@
|
||||
<DependentUpon>Reference.svcmap</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="PUB.cs" />
|
||||
<Compile Include="SearchModel\AnsanLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\BookSearchService.cs" />
|
||||
<Compile Include="SearchModel\BukguLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\BukguPublicLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\BukguSlibSearcher.cs" />
|
||||
<Compile Include="SearchModel\DLSSearcher.cs" />
|
||||
<Compile Include="SearchModel\DownloadProgressForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SearchModel\GoheungLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\GwangjuCityLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\GwangsanLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\IksanLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\ILibrarySearcher.cs" />
|
||||
<Compile Include="SearchModel\KwangjuCityLibrarySearcher.cs" />
|
||||
<Compile Include="SearchModel\JeonbukEduLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\MokpoLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\SuncheonLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\WandoLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\YeosuLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\JunnamEduJiheaNuriSearcher.cs" />
|
||||
<Compile Include="SearchModel\KwangjuCityEduLibrarySearcher.cs" />
|
||||
<Compile Include="SearchModel\JunnamEduSearcher.cs" />
|
||||
<Compile Include="SearchModel\NamguLibrarySearcher.cs" />
|
||||
<Compile Include="SearchModel\SeleniumHelper.cs" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<PublishUrlHistory>E:\UniMarcApplicationUpdateFiles\|ftp://ftpgloria%401.215.250.130/|ftp://ftpgloria%401.215.250.130:50005/|sftp://ftpgloria%401.215.250.130/|ftp://ftpgloria%401.215.250.130/unimarc/</PublishUrlHistory>
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace UniMarc.마크
|
||||
this.dataGridView1.Name = "dataGridView1";
|
||||
this.dataGridView1.ReadOnly = true;
|
||||
this.dataGridView1.RowTemplate.Height = 23;
|
||||
this.dataGridView1.Size = new System.Drawing.Size(436, 186);
|
||||
this.dataGridView1.Size = new System.Drawing.Size(464, 583);
|
||||
this.dataGridView1.TabIndex = 1;
|
||||
this.dataGridView1.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellDoubleClick);
|
||||
this.dataGridView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView1_KeyDown);
|
||||
@@ -96,7 +96,7 @@ namespace UniMarc.마크
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(436, 32);
|
||||
this.panel1.Size = new System.Drawing.Size(464, 32);
|
||||
this.panel1.TabIndex = 2;
|
||||
//
|
||||
// btn_Close
|
||||
@@ -144,14 +144,14 @@ namespace UniMarc.마크
|
||||
this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel2.Location = new System.Drawing.Point(0, 32);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Size = new System.Drawing.Size(436, 186);
|
||||
this.panel2.Size = new System.Drawing.Size(464, 583);
|
||||
this.panel2.TabIndex = 3;
|
||||
//
|
||||
// Check_Copy_Sub_List
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(436, 218);
|
||||
this.ClientSize = new System.Drawing.Size(464, 615);
|
||||
this.Controls.Add(this.panel2);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.Name = "Check_Copy_Sub_List";
|
||||
|
||||
@@ -133,7 +133,6 @@ namespace UniMarc.마크
|
||||
{
|
||||
var cc2 = cc as Check_copyWD;
|
||||
cc2.btn_SearchList.Text = list_name;
|
||||
cc2.SearchCount.Value = cc2.dv1.Rows.Count - 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace UniMarc.마크
|
||||
this.dataGridView1.Name = "dataGridView1";
|
||||
this.dataGridView1.ReadOnly = true;
|
||||
this.dataGridView1.RowTemplate.Height = 23;
|
||||
this.dataGridView1.Size = new System.Drawing.Size(514, 261);
|
||||
this.dataGridView1.Size = new System.Drawing.Size(514, 606);
|
||||
this.dataGridView1.TabIndex = 0;
|
||||
this.dataGridView1.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellDoubleClick);
|
||||
this.dataGridView1.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dataGridView1_RowPostPaint);
|
||||
@@ -119,7 +119,7 @@ namespace UniMarc.마크
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(514, 261);
|
||||
this.ClientSize = new System.Drawing.Size(514, 606);
|
||||
this.Controls.Add(this.dataGridView1);
|
||||
this.Name = "Check_Copy_Sub_Search";
|
||||
this.Text = "도서관 검색";
|
||||
|
||||
51
unimarc/unimarc/마크/Check_copyWD.Designer.cs
generated
51
unimarc/unimarc/마크/Check_copyWD.Designer.cs
generated
@@ -42,9 +42,7 @@
|
||||
this.btn_SearchList = new System.Windows.Forms.Button();
|
||||
this.btn_Start = new System.Windows.Forms.Button();
|
||||
this.btn_Stop = new System.Windows.Forms.Button();
|
||||
this.SearchCount = new System.Windows.Forms.NumericUpDown();
|
||||
this.btn_Close = new System.Windows.Forms.Button();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tb_SearchTarget = new System.Windows.Forms.ComboBox();
|
||||
this.btSearchLibrary = new System.Windows.Forms.Label();
|
||||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
@@ -61,16 +59,15 @@
|
||||
this.panel6 = new System.Windows.Forms.Panel();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.lblStatus = new System.Windows.Forms.ToolStripLabel();
|
||||
this.lbSite = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.panel4 = new System.Windows.Forms.Panel();
|
||||
this.chk_RemoveBrit = new System.Windows.Forms.CheckBox();
|
||||
this.btn_ResultEmpty = new System.Windows.Forms.Button();
|
||||
this.btn_GridReset = new System.Windows.Forms.Button();
|
||||
this.btn_OpenMemo = new System.Windows.Forms.Button();
|
||||
this.chk_spChar = new System.Windows.Forms.CheckBox();
|
||||
this.lbSite = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SearchCount)).BeginInit();
|
||||
this.panel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dv1)).BeginInit();
|
||||
this.panel3.SuspendLayout();
|
||||
@@ -228,19 +225,6 @@
|
||||
this.btn_Stop.UseVisualStyleBackColor = true;
|
||||
this.btn_Stop.Click += new System.EventHandler(this.btn_Stop_Click);
|
||||
//
|
||||
// SearchCount
|
||||
//
|
||||
this.SearchCount.Location = new System.Drawing.Point(491, 6);
|
||||
this.SearchCount.Maximum = new decimal(new int[] {
|
||||
10000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.SearchCount.Name = "SearchCount";
|
||||
this.SearchCount.Size = new System.Drawing.Size(54, 21);
|
||||
this.SearchCount.TabIndex = 2;
|
||||
this.SearchCount.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// btn_Close
|
||||
//
|
||||
this.btn_Close.Location = new System.Drawing.Point(548, 4);
|
||||
@@ -251,23 +235,15 @@
|
||||
this.btn_Close.UseVisualStyleBackColor = true;
|
||||
this.btn_Close.Click += new System.EventHandler(this.btn_Close_Click);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(444, 10);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(45, 12);
|
||||
this.label2.TabIndex = 0;
|
||||
this.label2.Text = "검색 수";
|
||||
//
|
||||
// tb_SearchTarget
|
||||
//
|
||||
this.tb_SearchTarget.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
|
||||
this.tb_SearchTarget.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
|
||||
this.tb_SearchTarget.Enabled = false;
|
||||
this.tb_SearchTarget.ImeMode = System.Windows.Forms.ImeMode.Hangul;
|
||||
this.tb_SearchTarget.Location = new System.Drawing.Point(66, 6);
|
||||
this.tb_SearchTarget.Name = "tb_SearchTarget";
|
||||
this.tb_SearchTarget.Size = new System.Drawing.Size(243, 20);
|
||||
this.tb_SearchTarget.Size = new System.Drawing.Size(390, 20);
|
||||
this.tb_SearchTarget.TabIndex = 1;
|
||||
this.tb_SearchTarget.SelectedIndexChanged += new System.EventHandler(this.tb_SearchTarget_SelectedIndexChanged);
|
||||
this.tb_SearchTarget.KeyDown += new System.Windows.Forms.KeyEventHandler(this.tb_SearchTarget_KeyDown);
|
||||
@@ -288,11 +264,9 @@
|
||||
this.panel2.Controls.Add(this.btn_SiteDenote);
|
||||
this.panel2.Controls.Add(this.lbl_PW);
|
||||
this.panel2.Controls.Add(this.lbl_ID);
|
||||
this.panel2.Controls.Add(this.SearchCount);
|
||||
this.panel2.Controls.Add(this.tb_SearchTarget);
|
||||
this.panel2.Controls.Add(this.btSearchLibrary);
|
||||
this.panel2.Controls.Add(this.btn_Close);
|
||||
this.panel2.Controls.Add(this.label2);
|
||||
this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.panel2.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel2.Name = "panel2";
|
||||
@@ -301,7 +275,7 @@
|
||||
//
|
||||
// btn_SiteDenote
|
||||
//
|
||||
this.btn_SiteDenote.Location = new System.Drawing.Point(317, 5);
|
||||
this.btn_SiteDenote.Location = new System.Drawing.Point(462, 5);
|
||||
this.btn_SiteDenote.Name = "btn_SiteDenote";
|
||||
this.btn_SiteDenote.Size = new System.Drawing.Size(77, 23);
|
||||
this.btn_SiteDenote.TabIndex = 4;
|
||||
@@ -432,6 +406,12 @@
|
||||
this.lblStatus.Size = new System.Drawing.Size(27, 20);
|
||||
this.lblStatus.Text = "WD";
|
||||
//
|
||||
// lbSite
|
||||
//
|
||||
this.lbSite.Name = "lbSite";
|
||||
this.lbSite.Size = new System.Drawing.Size(55, 17);
|
||||
this.lbSite.Text = "-- Site --";
|
||||
//
|
||||
// panel4
|
||||
//
|
||||
this.panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
@@ -497,12 +477,6 @@
|
||||
this.chk_spChar.Text = "특수문자 제거";
|
||||
this.chk_spChar.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// lbSite
|
||||
//
|
||||
this.lbSite.Name = "lbSite";
|
||||
this.lbSite.Size = new System.Drawing.Size(55, 17);
|
||||
this.lbSite.Text = "-- Site --";
|
||||
//
|
||||
// Check_copyWD
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
@@ -510,14 +484,13 @@
|
||||
this.ClientSize = new System.Drawing.Size(637, 738);
|
||||
this.Controls.Add(this.panel3);
|
||||
this.Name = "Check_copyWD";
|
||||
this.Text = "복본조사(WebDriver)";
|
||||
this.Text = "복본조사(New)";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Check_copy_FormClosing);
|
||||
this.Load += new System.EventHandler(this.Check_copy_Load);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SearchCount)).EndInit();
|
||||
this.panel2.ResumeLayout(false);
|
||||
this.panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dv1)).EndInit();
|
||||
@@ -536,7 +509,6 @@
|
||||
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.Label btSearchLibrary;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Panel panel2;
|
||||
private System.Windows.Forms.Button btn_Close;
|
||||
private System.Windows.Forms.Button btn_Stop;
|
||||
@@ -550,7 +522,6 @@
|
||||
private System.Windows.Forms.Panel panel4;
|
||||
private System.Windows.Forms.CheckBox chk_spChar;
|
||||
private System.Windows.Forms.CheckBox chk_RemoveBrit;
|
||||
public System.Windows.Forms.NumericUpDown SearchCount;
|
||||
private System.Windows.Forms.RadioButton rb_isNumber;
|
||||
private System.Windows.Forms.RadioButton rb_isHave;
|
||||
private System.Windows.Forms.Button btn_GridReset;
|
||||
|
||||
@@ -10,6 +10,7 @@ using BokBonCheck;
|
||||
using AR;
|
||||
using UniMarc.SearchModel;
|
||||
using System.Linq;
|
||||
using UniMarc;
|
||||
|
||||
namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
@@ -22,6 +23,15 @@ namespace WindowsFormsApp1.Mac
|
||||
public string SearcherNo;
|
||||
private bool isStop = false;
|
||||
Main main;
|
||||
|
||||
bool GetDemoRunAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DateTime.Now <= new DateTime(2025, 09, 30));
|
||||
|
||||
}
|
||||
}
|
||||
public Check_copyWD(Main _main)
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -32,56 +42,307 @@ namespace WindowsFormsApp1.Mac
|
||||
//도서검색(크롤링)
|
||||
_searchService = new BookSearchService();
|
||||
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher_Munhwa(idx++));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher_Children(idx++));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher_Smart(idx++));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher_Purungil(idx++));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher_Hyocheon(idx++));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher(idx++, "#libMA", "문화정보도서관"));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher(idx++, "#libMC", "청소년도서관"));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher(idx++, "#libSQ", "스마트도서관"));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher(idx++, "#libMB", "푸른길도서관"));
|
||||
_searchService.AddSearcher(new NamguLibrarySearcher(idx++, "#libSW", "효천어울림도서관"));
|
||||
|
||||
//광주시청도서광
|
||||
idx = 30;
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_central(idx++));
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_choisangjun(idx++));
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_dagachi(idx++));
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_Indi(idx++));
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_Student(idx++));
|
||||
_searchService.AddSearcher(new KwangjuCityLibrarySearcher_Kumho(idx++));
|
||||
|
||||
//전남교육청통합도서관
|
||||
idx = 50;
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "ALL", "전체"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146010", "목포"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146007", "나주"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146006", "남평"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146025", "광양"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146008", "담양"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146005", "구례"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146012", "보성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146013", "벌교"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146023", "화순"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146019", "장흥"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146022", "해남"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146017", "영암"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146011", "무안"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146021", "함평"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146016", "영광"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146018", "장성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146020", "진도"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146003", "곡성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146059", "학생교육문화회관"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146042", "광양평생"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146002", "고흥평생"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00346002", "교육연수원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00324008", "교육연구정보원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00346030", "전라남도국제교육원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146180", "순천만생태문화교육원"));
|
||||
if (GetDemoRunAuth == true)
|
||||
{
|
||||
|
||||
|
||||
|
||||
//광주시교육청통합도서관
|
||||
idx = 50;
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "MD", "중앙도서관"));
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "MF", "분관최상준도서관"));
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "ME", "송정다가치문화도서관"));
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "MA", "학생독립운동기념회관"));
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "MC", "학생교육문화회관"));
|
||||
_searchService.AddSearcher(new KwangjuCityEduLibrarySearcher(idx++, "MB", "금호평생교육관"));
|
||||
|
||||
//전남교육청통합도서관
|
||||
idx = 100;
|
||||
//_searchService.AddSearcher(new JunnamEduSearcher(idx++, "ALL", "전체"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146010", "목포"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146007", "나주"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146006", "남평"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146025", "광양"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146008", "담양"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146005", "구례"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146012", "보성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146013", "벌교"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146023", "화순"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146019", "장흥"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146022", "해남"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146017", "영암"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146011", "무안"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146021", "함평"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146016", "영광"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146018", "장성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146020", "진도"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146003", "곡성"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146059", "학생교육문화회관"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146042", "광양평생"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146002", "고흥평생"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00346002", "교육연수원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00324008", "교육연구정보원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00346030", "전라남도국제교육원"));
|
||||
_searchService.AddSearcher(new JunnamEduSearcher(idx++, "00146180", "순천만생태문화교육원"));
|
||||
|
||||
//전남교육청행정자료실
|
||||
idx = 150;
|
||||
_searchService.AddSearcher(new JunnamEduJiheaNuriSearcher(idx++, "00324010", "지혜누리"));
|
||||
|
||||
//여수시립
|
||||
idx = 200;
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MG", "여수이순신도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MA", "여수시립쌍봉도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MB", "여수시립현암도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MC", "여수시립환경도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MD", "여수시립돌산도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "ME", "여수시립소라도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "MF", "여수시립율촌도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PA", "거문도은빛바다도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PB", "치매안심센터작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PC", "청솔글누리작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PD", "동부도시보건작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PE", "화양열린작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PF", "여문늘벗작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "PH", "국동작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SA", "아주타운아파트작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SB", "책이랑나랑작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SC", "현천작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SE", "꿈꾸는영어전문작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SF", "학마을작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SG", "웅천지웰작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SH", "한려작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SJ", "주은금고작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SK", "광림작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SM", "민들레작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SO", "원앙작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SP", "푸른정원작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SR", "로얄골드빌작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SS", "꿈을키우는작은도서관"));
|
||||
//_searchService.AddSearcher(new YeosuLibSearcher(idx++, "ST", "KLAS MANAGEMENT"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SY", "신기부영작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "SZ", "국동365열린도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "TA", "지웰2차 작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "TB", "이편한 작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "TC", "채움늘 작은도서관"));
|
||||
_searchService.AddSearcher(new YeosuLibSearcher(idx++, "TD", "웅천글꽃 작은도서관"));
|
||||
|
||||
//고흥군립
|
||||
idx = 300;
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MA", "고흥군립중앙도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MB", "고흥군립남부도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MC", "고흥군립북부도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MD", "과역작은도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "ME", "나로한빛 작은도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MF", "도화푸른꿈 작은도서관"));
|
||||
_searchService.AddSearcher(new GoheungLibSearcher(idx++, "MG", "포두작은도서관"));
|
||||
|
||||
//광주북구 통합도서관
|
||||
idx = 400;
|
||||
_searchService.AddSearcher(new BukguLibSearcher(idx++, "101", "스마트도서관1호점"));
|
||||
_searchService.AddSearcher(new BukguLibSearcher(idx++, "102", "스마트도서관2호점"));
|
||||
_searchService.AddSearcher(new BukguLibSearcher(idx++, "105", "스마트도서관3호점"));
|
||||
|
||||
//광주북구 작은도서관
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729038", "꿈나무작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129094", "동림동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729046", "두암1동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129069", "두암2동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129068", "두암3동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129056", "매곡동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129074", "문흥2동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129054", "삼각동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729068", "시화문화마을작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129057", "신안동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129220", "양산동주민작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129085", "오치1동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129070", "오치2동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129055", "용봉작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129064", "운암1동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129071", "운암2동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129058", "운암3동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729175", "임동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729085", "중앙동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129075", "중흥1동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729155", "징검다리작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "129065", "풍향동작은도서관"));
|
||||
_searchService.AddSearcher(new BukguSlibSearcher(idx++, "729154", "햇살마루작은도서관"));
|
||||
|
||||
//광주북구 공공도서관
|
||||
_searchService.AddSearcher(new BukguPublicLibSearcher(idx++, "124010", "일곡도서관"));
|
||||
_searchService.AddSearcher(new BukguPublicLibSearcher(idx++, "129131", "운암도서관"));
|
||||
_searchService.AddSearcher(new BukguPublicLibSearcher(idx++, "129225", "양산도서관"));
|
||||
_searchService.AddSearcher(new BukguPublicLibSearcher(idx++, "129226", "중흥도서관"));
|
||||
_searchService.AddSearcher(new BukguPublicLibSearcher(idx++, "129227", "신용도서관"));
|
||||
|
||||
//전북교육청도서관
|
||||
idx = 700;
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MV", "고창도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MB", "군산학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MC", "군산학생교육문화관 대야분관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MH", "김제학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MJ", "김제학생교육문화관 금산분관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MF", "남원학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MG", "남원학생교육문화관운봉분관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MR", "무주도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MK", "부안학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MU", "순창도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MP", "완주도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MD", "익산학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_ME", "익산학생교육문화관 함열분관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MT", "임실도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MS", "장수도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MA", "전주학생교육문화관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MQ", "진안도서관"));
|
||||
_searchService.AddSearcher(new JeonbukEduLibSearcher(idx++, "lib_MN", "정읍학생복지회관"));
|
||||
|
||||
//광주광산구 통합도서관
|
||||
idx = 800;
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "JM", "장덕도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "MB", "이야기꽃도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "MA", "첨단도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "BR", "신가도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "WN", "운남어린이도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "MC", "스마트도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CA", "첨단빛누리작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CB", "사랑나눔작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CC", "혜윰마루작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CD", "책놀터작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CE", "우산동작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CF", "더불어락작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CG", "임곡꿈쟁이작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CH", "유노윤호HUG작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CI", "늘품작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CJ", "왁자지껄수다놀이터작은도서관"));
|
||||
_searchService.AddSearcher(new GwangsanLibSearcher(idx++, "CK", "송정다누리작은도서관"));
|
||||
|
||||
//목포시립도서관
|
||||
idx = 900;
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MA", "목포시립도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MX", "목포어울림도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MJ", "목포어린이도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MQ", "목포영어도서관"));
|
||||
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "ME", "꿈나무작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MB", "꿈돌이작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MS", "노을작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MW", "늘푸른작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MH", "무지개작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MF", "반딧불작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MP", "삼학작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MV", "샛별작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MO", "소나무작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MN", "숲속작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MK", "연꽃작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MD", "옹달샘작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MC", "은하수작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MM", "청개구리작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MI", "초롱초롱작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "ML", "푸른솔작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MU", "푸른숲작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MR", "행복마을작은도서관"));
|
||||
_searchService.AddSearcher(new MokpoLibSearcher(idx++, "MT", "호돌이작은도서관"));
|
||||
|
||||
//순천시립도서관
|
||||
idx = 1000;
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MA", "삼산도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MB", "그림책도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "BR", "연향도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MH", "기적의도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MC", "조례호수도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MJ", "신대도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MK", "어울림도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MD", "해룡농어촌도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "MG", "풍덕글마루도서관"));
|
||||
_searchService.AddSearcher(new SuncheonLibSearcher(idx++, "mini", "작은도서관"));
|
||||
|
||||
//광주시립도서관
|
||||
idx = 1100;
|
||||
_searchService.AddSearcher(new GwangjuCityLibSearcher(idx++, "124003", "무등도서관"));
|
||||
_searchService.AddSearcher(new GwangjuCityLibSearcher(idx++, "124004", "사직도서관"));
|
||||
_searchService.AddSearcher(new GwangjuCityLibSearcher(idx++, "124008", "산수도서관"));
|
||||
_searchService.AddSearcher(new GwangjuCityLibSearcher(idx++, "129228", "디지털정보도서관"));
|
||||
|
||||
// 완도군립도서관
|
||||
idx = 1200;
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "MA", "완도군립도서관"));
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "MB", "노화공공도서관"));
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "MC", "금일공공도서관"));
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "MD", "보길윤선도작은도서관"));
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "ME", "군외동백숲작은도서관"));
|
||||
_searchService.AddSearcher(new WandoLibSearcher(idx++, "MF", "도담도담작은도서관"));
|
||||
|
||||
// 익산시통합도서관
|
||||
idx = 1300;
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "MO", "모현도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "BR", "영등도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "MA", "마동도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "BU", "부송도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "MC", "유천도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "HW", "황등도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "MB", "금마도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SX", "모인여행숲도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SW", "수도산그림책숲도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "UQ", "스마트도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SI", "글마루작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SD", "깊은샘작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SE", "꿈꾸는뜰작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SO", "꿈드림작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SK", "낭산작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SB", "동산작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SJ", "모현뜰작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SH", "배산작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SC", "봄나루작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SF", "부송작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SA", "삼성동어린이도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SQ", "어양작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SP", "어울림작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SG", "예솔작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SL", "왕궁작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SN", "울림작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SM", "행복세상작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SR", "그루터기작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SS", "늘봄작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SU", "망성아담작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SV", "함라등대작은도서관"));
|
||||
_searchService.AddSearcher(new IksanLibSearcher(idx++, "SY", "무학정원작은도서관"));
|
||||
|
||||
// 안산시중앙도서관
|
||||
//idx = 1400;
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MA", "중앙도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MD", "감골도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MB", "관산도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "ME", "단원어린이도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "ND", "대부도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "NF", "미디어도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MH", "반월도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MX", "본오도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "ML", "부곡도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "NK", "상록수도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MF", "상록어린이도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "NC", "선부도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MC", "성포도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MS", "수암도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "MR", "원고잔도서관"));
|
||||
//_searchService.AddSearcher(new AnsanLibSearcher(idx++, "NJ", "월피예술도서관"));
|
||||
|
||||
}
|
||||
|
||||
this.tb_SearchTarget.Items.Clear();
|
||||
// this.tb_SearchTarget.Items.Add("-- 검색대상을 선택하세요 --");
|
||||
foreach (var item in _searchService.GetAvailableSites().OrderBy(t=>t))
|
||||
// this.tb_SearchTarget.Items.Add("-- 검색대상을 선택하세요 --");
|
||||
foreach (var item in _searchService.GetAvailableSites().OrderBy(t => t))
|
||||
tb_SearchTarget.Items.Add(item);
|
||||
|
||||
if (PUB.setting.LastSearchTarget.isEmpty() == false)
|
||||
tb_SearchTarget.Text = PUB.setting.LastSearchTarget;
|
||||
|
||||
this.Text = $"복본조사(New:{_searchService.GetAvailableSites().Count})";
|
||||
}
|
||||
|
||||
private void dataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
|
||||
@@ -97,6 +358,7 @@ namespace WindowsFormsApp1.Mac
|
||||
|
||||
//크롤링
|
||||
InitializeChromeDriver();
|
||||
tb_SearchTarget.Enabled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,10 +482,9 @@ namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
Skill_Grid sg = new Skill_Grid();
|
||||
sg.Excel_to_DataGridView(sender, e);
|
||||
|
||||
SearchCount.Value = dv1.Rows.Count;
|
||||
}
|
||||
|
||||
|
||||
async private void btn_Start_Click(object sender, EventArgs e)
|
||||
{
|
||||
var searcher = this.GetSearcher();
|
||||
@@ -233,14 +494,9 @@ namespace WindowsFormsApp1.Mac
|
||||
return;
|
||||
}
|
||||
|
||||
SearchCount.Value = dv1.Rows.Count; //250619
|
||||
RowCount = 0; //250619
|
||||
|
||||
dv1.CurrentCell = dv1.Rows[0].Cells[0];
|
||||
|
||||
int SCount = Convert.ToInt32(SearchCount.Value);
|
||||
|
||||
if (DateTime.Now > new DateTime(2025, 09, 30))
|
||||
if (GetDemoRunAuth == false)
|
||||
{
|
||||
UTIL.MsgE("테스트 기간이 종료되었습니다\n개발자 문의 하세요");
|
||||
return;
|
||||
@@ -254,10 +510,12 @@ namespace WindowsFormsApp1.Mac
|
||||
|
||||
try
|
||||
{
|
||||
PUB.setting.LastSearchTarget = this.tb_SearchTarget.Text.Trim();
|
||||
PUB.setting.Save();
|
||||
|
||||
this._isSearching = true;
|
||||
btn_Start.Enabled = false;
|
||||
btn_Stop.Enabled = false;
|
||||
btn_Stop.Enabled = true;
|
||||
await searcher.StartDriver(this.chkShowBrowser.Checked);
|
||||
byte searchopt = 0; //전체검색
|
||||
if (radTargetEmpty.Checked) searchopt = 1;
|
||||
@@ -278,7 +536,7 @@ namespace WindowsFormsApp1.Mac
|
||||
if (this._isSearching == false)
|
||||
{
|
||||
drow.Cells["dvc_remark"].Value = "Cancel";
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
dv1.CurrentCell = drow.Cells[0];
|
||||
@@ -340,7 +598,7 @@ namespace WindowsFormsApp1.Mac
|
||||
}
|
||||
}
|
||||
|
||||
if (retry == false && chkRetryErrData.Checked)
|
||||
if (_isSearching == true && retry == false && chkRetryErrData.Checked)
|
||||
{
|
||||
retry = true;
|
||||
radTargetErr.Checked = true;
|
||||
@@ -371,11 +629,8 @@ namespace WindowsFormsApp1.Mac
|
||||
btn_Start.Enabled = true;
|
||||
this._isSearching = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int RowCount = 0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -521,7 +776,7 @@ namespace WindowsFormsApp1.Mac
|
||||
dv1.Rows[a].DefaultCellStyle.ForeColor = Color.Black;
|
||||
dv1.Rows[a].DefaultCellStyle.BackColor = Color.White;
|
||||
dv1.Rows[a].Cells["Count"].Value = "";
|
||||
RowCount = 0;
|
||||
dv1.Rows[a].Cells["dvc_remark"].Value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +795,7 @@ namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
if (this.tb_SearchTarget.SelectedIndex < 0) return null;
|
||||
return this._searchService.Get(tb_SearchTarget.Text);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void btn_SiteDenote_Click(object sender, EventArgs e)
|
||||
@@ -567,10 +822,12 @@ namespace WindowsFormsApp1.Mac
|
||||
var searcher = this._searchService.Get(this.tb_SearchTarget.Text);
|
||||
if (searcher == null)
|
||||
{
|
||||
chkShowBrowser.Enabled = true;
|
||||
lbSite.Text = "-- site --";
|
||||
return;
|
||||
}
|
||||
this.lbSite.Text = searcher.SiteUrl;
|
||||
chkShowBrowser.Enabled = !searcher.HttpApiMode;
|
||||
this.lbSite.Text = searcher.SiteUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using UniMarc;
|
||||
using UniMarc.SearchModel;
|
||||
|
||||
namespace WindowsFormsApp1.Mac
|
||||
@@ -179,6 +180,8 @@ namespace WindowsFormsApp1.Mac
|
||||
|
||||
btn_Search.Enabled = true;
|
||||
|
||||
PUB.setting.LastSearchTargetDLS = tb_SearchClient.Text.Trim();
|
||||
PUB.setting.Save();
|
||||
|
||||
//로그인
|
||||
_searcher = new DLSSearcher(50);
|
||||
|
||||
Reference in New Issue
Block a user