Files
Unimarc/unimarc/unimarc/SearchModel/GwangsanLibSearcher.cs
Arin(asus) 946957bab2 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>
2025-08-14 01:21:33 +09:00

181 lines
6.4 KiB
C#

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();
}
}
}