검색결과 없음 HTML 추출 개선 및 도서관별 지연시간 저장 기능 구현
- 모든 도서관 검색기에서 검색결과 없음시 구체적인 HTML 조각 추출 - BookSearchResult에 Resulthtml 속성 추가하여 매칭된 HTML 컨텍스트 저장 - Helper_LibraryDelaySettings.cs 추가로 도서관별 검색 지연시간 XML 저장 - Check_copyWD.cs에 dvc_resulthtml 컬럼 표시 및 지연시간 저장 UI 구현 - 15개 SearchModel 파일에서 htmlContent 1000자 자르기를 의미있는 메시지로 교체 - HTTP 검색기들에 한글 인코딩 문제 해결을 위한 헤더 개선 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
- **데이터베이스**: MySQL
|
||||
- **주요기능**: 마크 작성, 복본조사, DLS 연동, 도서 정보 관리
|
||||
|
||||
## 데이터베이스 정보
|
||||
- Server=1.215.250.130;Port=3306;Database=unimarc;uid=root;pwd=Admin21234;
|
||||
|
||||
## 코딩 컨벤션
|
||||
- 파일명: PascalCase (예: DLS_Copy.cs)
|
||||
- 클래스명: PascalCase
|
||||
|
||||
@@ -9,6 +9,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Factory_Client", "Factory_C
|
||||
EndProject
|
||||
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "UniMarcSetup", "UniMarcSetup\UniMarcSetup.vdproj", "{B0A88F76-DC68-44F9-90B4-CD94625CC1F4}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "솔루션 항목", "솔루션 항목", "{2A3A057F-5D22-31FD-628C-DF5EF75AEF1E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
CLAUDE.md = CLAUDE.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
170
unimarc/unimarc/Helper_LibraryDelaySettings.cs
Normal file
170
unimarc/unimarc/Helper_LibraryDelaySettings.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Text;
|
||||
|
||||
namespace UniMarc
|
||||
{
|
||||
/// <summary>
|
||||
/// 도서관별 지연시간 설정을 관리하는 클래스
|
||||
/// </summary>
|
||||
public class Helper_LibraryDelaySettings
|
||||
{
|
||||
private static readonly string SettingsFileName = "LibraryDelaySettings.xml";
|
||||
private static readonly string SettingsFilePath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"UniMarc",
|
||||
SettingsFileName
|
||||
);
|
||||
|
||||
private Dictionary<string, int> _libraryDelaySettings;
|
||||
|
||||
public Helper_LibraryDelaySettings()
|
||||
{
|
||||
_libraryDelaySettings = new Dictionary<string, int>();
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 도서관별 지연시간 설정을 로드
|
||||
/// </summary>
|
||||
private void LoadSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(SettingsFilePath))
|
||||
{
|
||||
var xmlDoc = new XmlDocument();
|
||||
xmlDoc.Load(SettingsFilePath);
|
||||
|
||||
var libraryNodes = xmlDoc.SelectNodes("//LibraryDelaySettings/Library");
|
||||
if (libraryNodes != null)
|
||||
{
|
||||
foreach (XmlNode node in libraryNodes)
|
||||
{
|
||||
var name = node.Attributes?["Name"]?.Value;
|
||||
var delayStr = node.Attributes?["Delay"]?.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(name) && int.TryParse(delayStr, out int delay))
|
||||
{
|
||||
_libraryDelaySettings[name] = delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 지연시간 설정 로드 오류: {ex.Message}");
|
||||
_libraryDelaySettings = new Dictionary<string, int>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 도서관별 지연시간 설정을 저장
|
||||
/// </summary>
|
||||
private void SaveSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 디렉토리 생성
|
||||
var directory = Path.GetDirectoryName(SettingsFilePath);
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// XML 파일로 저장
|
||||
var xmlDoc = new XmlDocument();
|
||||
var declaration = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
xmlDoc.AppendChild(declaration);
|
||||
|
||||
var root = xmlDoc.CreateElement("LibraryDelaySettings");
|
||||
xmlDoc.AppendChild(root);
|
||||
|
||||
foreach (var kvp in _libraryDelaySettings)
|
||||
{
|
||||
var libraryElement = xmlDoc.CreateElement("Library");
|
||||
libraryElement.SetAttribute("Name", kvp.Key);
|
||||
libraryElement.SetAttribute("Delay", kvp.Value.ToString());
|
||||
root.AppendChild(libraryElement);
|
||||
}
|
||||
|
||||
xmlDoc.Save(SettingsFilePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 지연시간 설정 저장 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 도서관의 지연시간 설정을 가져옴
|
||||
/// </summary>
|
||||
/// <param name="libraryName">도서관 이름</param>
|
||||
/// <returns>지연시간(초), 설정이 없으면 0</returns>
|
||||
public int GetDelay(string libraryName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(libraryName))
|
||||
return 0;
|
||||
|
||||
return _libraryDelaySettings.TryGetValue(libraryName, out int delay) ? delay : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 도서관의 지연시간 설정을 저장
|
||||
/// </summary>
|
||||
/// <param name="libraryName">도서관 이름</param>
|
||||
/// <param name="delaySeconds">지연시간(초)</param>
|
||||
public void SetDelay(string libraryName, int delaySeconds)
|
||||
{
|
||||
if (string.IsNullOrEmpty(libraryName))
|
||||
return;
|
||||
|
||||
if (delaySeconds < 0)
|
||||
delaySeconds = 0;
|
||||
|
||||
_libraryDelaySettings[libraryName] = delaySeconds;
|
||||
SaveSettings();
|
||||
|
||||
Console.WriteLine($"도서관 지연시간 설정 저장: {libraryName} = {delaySeconds}초");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 도서관 지연시간 설정을 가져옴
|
||||
/// </summary>
|
||||
/// <returns>도서관명-지연시간 딕셔너리</returns>
|
||||
public Dictionary<string, int> GetAllSettings()
|
||||
{
|
||||
return new Dictionary<string, int>(_libraryDelaySettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 도서관의 지연시간 설정을 제거
|
||||
/// </summary>
|
||||
/// <param name="libraryName">도서관 이름</param>
|
||||
public void RemoveDelay(string libraryName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(libraryName))
|
||||
return;
|
||||
|
||||
if (_libraryDelaySettings.ContainsKey(libraryName))
|
||||
{
|
||||
_libraryDelaySettings.Remove(libraryName);
|
||||
SaveSettings();
|
||||
Console.WriteLine($"도서관 지연시간 설정 제거: {libraryName}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 지연시간 설정을 초기화
|
||||
/// </summary>
|
||||
public void ClearAllSettings()
|
||||
{
|
||||
_libraryDelaySettings.Clear();
|
||||
SaveSettings();
|
||||
Console.WriteLine("모든 도서관 지연시간 설정 초기화");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,9 @@ namespace WindowsFormsApp1
|
||||
Application.Run(new Main());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void DB_InitSetting()
|
||||
{
|
||||
UniMarc.Properties.Settings.Default.IP = ConvertIP(UniMarc.Properties.Settings.Default.IP);
|
||||
UniMarc.Properties.Settings.Default.IP = ConvertIP(UniMarc.Properties.Settings.Default.IP);
|
||||
UniMarc.Properties.Settings.Default.Port = Convert2to10(UniMarc.Properties.Settings.Default.Port);
|
||||
UniMarc.Properties.Settings.Default.Uid = ConvertAscii(UniMarc.Properties.Settings.Default.Uid);
|
||||
UniMarc.Properties.Settings.Default.pwd = ConvertAscii(UniMarc.Properties.Settings.Default.pwd);
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
|
||||
// 기본값으로 할 수 있습니다.
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2025.09.03.2030")]
|
||||
[assembly: AssemblyFileVersion("2025.09.03.2030")]
|
||||
[assembly: AssemblyVersion("2025.09.16.0000")]
|
||||
[assembly: AssemblyFileVersion("2025.09.16.0000")]
|
||||
|
||||
@@ -397,8 +397,10 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
// SearchAsync에서 PageSource 가져오기
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -423,128 +425,40 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
|
||||
if (driver.Url.EndsWith("DetailSearchResult") == false)
|
||||
{
|
||||
errmessage = "결과페이지가아님";
|
||||
return -1;
|
||||
}
|
||||
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
|
||||
if (noResultElements.Count > 0)
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다",
|
||||
@"총 0 건",
|
||||
@"총 0건"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
|
||||
RetryPoint:
|
||||
bool retry = false;
|
||||
// 2. 안산시 도서관 특화: span.count.gothic em 요소에서 직접 추출
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
var countElement = driver.FindElement(By.CssSelector("span.count.gothic em"));
|
||||
if (countElement != null)
|
||||
{
|
||||
// Text 대신 InnerHtml이나 GetAttribute 사용해보기
|
||||
var countText = countElement.Text.Trim();
|
||||
var innerHTML = countElement.GetAttribute("innerHTML");
|
||||
var outerHTML = countElement.GetAttribute("outerHTML");
|
||||
|
||||
Console.WriteLine($"count 요소 .Text: '{countText}'");
|
||||
Console.WriteLine($"count 요소 innerHTML: '{innerHTML}'");
|
||||
Console.WriteLine($"count 요소 outerHTML: '{outerHTML}'");
|
||||
|
||||
// innerHTML이나 outerHTML에서 텍스트 추출 시도
|
||||
string textToUse = !string.IsNullOrEmpty(countText) ? countText : innerHTML;
|
||||
if (string.IsNullOrEmpty(textToUse))
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
textToUse = outerHTML;
|
||||
}
|
||||
|
||||
Console.WriteLine($"추출할 텍스트: '{textToUse}'");
|
||||
|
||||
// "총 0 건 " 형태에서 숫자 추출
|
||||
var match = Regex.Match(textToUse, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
Console.WriteLine("검색 결과: 0건");
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"검색 결과: {count}건");
|
||||
return count;
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"정규식 매칭 실패: '{textToUse}'");
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
Console.WriteLine($"span.count.gothic em 요소 추출 실패: {ex1.Message}");
|
||||
}
|
||||
|
||||
// 3. span.count 전체에서 추출 시도
|
||||
try
|
||||
{
|
||||
var countSpan = driver.FindElement(By.CssSelector("span.count"));
|
||||
if (countSpan != null)
|
||||
{
|
||||
var fullText = countSpan.Text.Trim();
|
||||
Console.WriteLine($"count span 전체 텍스트: '{fullText}'");
|
||||
|
||||
var match = Regex.Match(fullText, @"총\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 (Exception ex2)
|
||||
{
|
||||
Console.WriteLine($"span.count 요소 추출 실패: {ex2.Message}");
|
||||
}
|
||||
|
||||
// 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[]
|
||||
@@ -560,11 +474,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -576,28 +493,81 @@ namespace BokBonCheck
|
||||
}
|
||||
}
|
||||
|
||||
if (retry == false)
|
||||
{
|
||||
Console.WriteLine( "결과를 찾을 수 없어 재시도");
|
||||
retry = true;
|
||||
Task.Delay(1000);
|
||||
goto RetryPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace BokBonCheck
|
||||
public DateTime SearchTime { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
public bool IsSuccess { get; set; }
|
||||
|
||||
public string Resulthtml { get; set; }
|
||||
}
|
||||
|
||||
public class BookSearchService
|
||||
|
||||
@@ -244,8 +244,9 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -270,73 +271,39 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. totalCount 요소에서 직접 추출 시도
|
||||
try
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
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 { }
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다",
|
||||
@"전체 0 건"
|
||||
};
|
||||
|
||||
// 전체 텍스트에서 정규식으로 추출
|
||||
var totalCountText = totalCountElement.Text;
|
||||
var match = Regex.Match(totalCountText, @"전체\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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[]
|
||||
@@ -350,11 +317,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -367,16 +337,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -112,19 +113,21 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 검색 결과가 없는 경우 확인
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다") ||
|
||||
htmlContent.Contains("자룼가 없습니다") ||
|
||||
htmlContent.Contains("<strong>0</strong> Results:"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -147,8 +150,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"조선이공대학교도서관 검색 결과: {count}건");
|
||||
return count;
|
||||
@@ -173,22 +179,27 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"조선이공대학교도서관 검색 결과: {count}건");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine("조선이공대학교도서관 검색결과 패턴을 찾을 수 없음");
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "결과 분석 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -197,5 +208,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -112,9 +113,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -125,6 +127,7 @@ namespace BokBonCheck
|
||||
htmlContent.Contains("총 <strong>0</strong>건"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -147,8 +150,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"조선대학교중앙도서관 검색 결과: {count}건");
|
||||
return count;
|
||||
@@ -173,22 +179,28 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"조선대학교중앙도서관 검색 결과: {count}건");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine("조선대학교중앙도서관 검색결과 패턴을 찾을 수 없음");
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "결과 분석 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -197,5 +209,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,10 @@ namespace BokBonCheck
|
||||
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
// SearchAsync에서 PageSource 가져오기
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -173,60 +176,54 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
var noResultElement = driver.FindElement(By.XPath("//*[contains(text(), '검색된 도서가 없습니다') or contains(text(), '검색결과가 없습니다')]"));
|
||||
if (noResultElement != null)
|
||||
@"검색된 도서가 없습니다",
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var resultElement = driver.FindElement(By.CssSelector(".subTapContWrap.on p"));
|
||||
if (resultElement != null)
|
||||
{
|
||||
var resultText = resultElement.Text;
|
||||
var match = Regex.Match(resultText, @"총\s*(\d+)건", RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
// 검색결과 없음 메시지를 포함한 HTML 조각 추출
|
||||
var index = htmlContent.IndexOf(pattern);
|
||||
if (index >= 0)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
var startIndex = Math.Max(0, index - 100);
|
||||
var endIndex = Math.Min(htmlContent.Length, index + pattern.Length + 100);
|
||||
resulthtml = htmlContent.Substring(startIndex, endIndex - startIndex);
|
||||
|
||||
// 상위 태그 찾기 시도
|
||||
try
|
||||
{
|
||||
if (count == 0)
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 실패시 기본 추출 결과 사용
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = pattern;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"결과 요소 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
var pageSource = driver.PageSource;
|
||||
|
||||
if (pageSource.Contains("검색된 도서가 없습니다") ||
|
||||
pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
var htmlPatterns = new[]
|
||||
{
|
||||
@@ -237,11 +234,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -254,16 +254,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "ExtractBookCount 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -218,8 +218,9 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -244,67 +245,21 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = 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 건"))
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다") ||
|
||||
htmlContent.Contains("전체 0 건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = "검색결과가 없습니다";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -319,11 +274,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -335,49 +293,81 @@ namespace BokBonCheck
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = "결과수량을찾을수없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -155,8 +155,9 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -181,87 +182,38 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
var noResultElement = driver.FindElement(By.XPath("//p[contains(text(), '조회된 도서가 없습니다')]"));
|
||||
if (noResultElement != null)
|
||||
@"조회된 도서가 없습니다",
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
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);
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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[]
|
||||
@@ -274,11 +226,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -291,16 +246,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -81,10 +81,11 @@ namespace BokBonCheck
|
||||
// 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("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
request.Headers.Add("Accept-Language", "ko-KR,ko;q=0.9,en;q=0.1");
|
||||
request.Headers.Add("Accept-Charset", "UTF-8,*;q=0.1");
|
||||
// Accept-Encoding 제거 - 압축으로 인한 인코딩 문제 방지
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -96,10 +97,50 @@ namespace BokBonCheck
|
||||
throw new HttpRequestException($"HTTP {(int)response.StatusCode} {response.StatusCode}: {errorContent}");
|
||||
}
|
||||
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
// 인코딩 문제 해결: 서버 응답의 Content-Type 확인 후 적절한 인코딩 사용
|
||||
string htmlContent;
|
||||
var contentType = response.Content.Headers.ContentType?.ToString() ?? "";
|
||||
Console.WriteLine($"광주동구 Content-Type: {contentType}");
|
||||
|
||||
if (contentType.Contains("charset="))
|
||||
{
|
||||
// 서버에서 지정한 charset 사용
|
||||
htmlContent = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
// charset이 명시되지 않은 경우 수동 처리
|
||||
var responseBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
// UTF-8 먼저 시도
|
||||
htmlContent = Encoding.UTF8.GetString(responseBytes);
|
||||
|
||||
// 한글이 없거나 깨진 경우 EUC-KR 시도
|
||||
if (!ContainsKorean(htmlContent) || htmlContent.Contains("<22>"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
var euckrEncoding = Encoding.GetEncoding("EUC-KR");
|
||||
var euckrContent = euckrEncoding.GetString(responseBytes);
|
||||
if (ContainsKorean(euckrContent))
|
||||
{
|
||||
htmlContent = euckrContent;
|
||||
Console.WriteLine("광주동구: EUC-KR 인코딩 사용");
|
||||
}
|
||||
}
|
||||
catch (Exception encEx)
|
||||
{
|
||||
Console.WriteLine($"광주동구 EUC-KR 변환 오류: {encEx.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
|
||||
// ResultHtml에 분석용 HTML 저장 (디버깅용으로 일부만)
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -126,10 +167,11 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage,out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
|
||||
resulthtml=string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 검색 결과가 없는 경우 확인
|
||||
@@ -141,18 +183,23 @@ namespace BokBonCheck
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 2. 검색 결과 수량 추출: <p class="totalCount">전체 <strong>2</strong> 건</p>
|
||||
// 2. 검색 결과 수량 추출 - 더 포괄적인 패턴 사용
|
||||
var patterns = new[]
|
||||
{
|
||||
@"<p[^>]*class=""totalCount""[^>]*>전체\s*<strong>\s*(\d+)\s*</strong>\s*건</p>",
|
||||
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건",
|
||||
@"<strong>\s*(\d+)\s*</strong>\s*건",
|
||||
@"총\s*(\d+)\s*건"
|
||||
// 기본 패턴들
|
||||
@"전체\s*(?:\*\*)?(\d+)(?:\*\*)?\s*건", // 전체 **N** 건 또는 전체 N 건
|
||||
@"<h[1-6][^>]*>.*?전체\s*(?:\*\*)?(\d+)(?:\*\*)?\s*건.*?</h[1-6]>", // h태그 안의 전체 N 건
|
||||
@"<p[^>]*class=""totalCount""[^>]*>전체\s*<strong>\s*(\d+)\s*</strong>\s*건</p>", // 원래 패턴
|
||||
@"전체\s*<strong>\s*(\d+)\s*</strong>\s*건", // strong 태그
|
||||
@"<strong>\s*(\d+)\s*</strong>\s*건", // strong만
|
||||
@"총\s*(\d+)\s*건", // 총 N 건
|
||||
@"검색결과\s*:\s*(\d+)\s*건", // 검색결과: N 건
|
||||
@"(\d+)\s*건의\s*검색결과", // N 건의 검색결과
|
||||
};
|
||||
|
||||
foreach (var pattern in patterns)
|
||||
{
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
@@ -160,25 +207,31 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value; // 매칭된 부분만 저장
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"광주동구 검색 결과: {count}건");
|
||||
Console.WriteLine($"광주동구 검색 결과: {count}건 (패턴: {pattern})");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 더 자세한 패턴으로 시도 (줄바꿈 포함)
|
||||
// 3. 멀티라인 패턴으로 재시도
|
||||
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*건"
|
||||
@"전체\s*(?:\*\*)?[\r\n\s]*(\d+)[\r\n\s]*(?:\*\*)?\s*건",
|
||||
@"전체\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);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
@@ -186,15 +239,24 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value; // 매칭된 부분만 저장
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"광주동구 검색 결과: {count}건");
|
||||
Console.WriteLine($"광주동구 검색 결과: {count}건 (멀티라인 패턴)");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4. 패턴을 찾지 못한 경우 - 디버깅을 위한 HTML 내용 일부 출력
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine($"광주동구 HTML 샘플: {resulthtml}");
|
||||
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine("광주동구 검색결과 패턴을 찾을 수 없음");
|
||||
return -1;
|
||||
@@ -202,6 +264,8 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음"; // 오류 시 HTML 일부 저장
|
||||
Console.WriteLine($"광주동구 결과 분석 오류: {ex.Message}");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -210,5 +274,83 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 문자열에 한글이 포함되어 있는지 확인
|
||||
/// </summary>
|
||||
private bool ContainsKorean(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return false;
|
||||
|
||||
foreach (char c in text)
|
||||
{
|
||||
if (c >= 0xAC00 && c <= 0xD7A3) // 한글 유니코드 범위
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,7 +337,8 @@ namespace BokBonCheck
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출 (페이징 포함)
|
||||
var (resultCount, ermsg) = await ExtractBookCountWithPaging(_driver, searchTerm);
|
||||
var (resultCount, ermsg, resultHtml) = await ExtractBookCountWithPaging(_driver, searchTerm);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -362,13 +363,15 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<(int count, string message)> ExtractBookCountWithPaging(IWebDriver driver, string searchTerm)
|
||||
private async Task<(int count, string message, string resultHtml)> ExtractBookCountWithPaging(IWebDriver driver, string searchTerm)
|
||||
{
|
||||
string errmessage = string.Empty;
|
||||
int totalCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var htmlContent = driver.PageSource;
|
||||
string resultHtml = string.Empty;
|
||||
// 첫 번째 페이지에서 테이블 row 수 확인
|
||||
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
|
||||
|
||||
@@ -381,7 +384,28 @@ namespace BokBonCheck
|
||||
if (firstPageRows.Count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return (0, errmessage);
|
||||
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
resultHtml = ExtractResultContext(htmlContent, match);
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
}
|
||||
}
|
||||
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
|
||||
totalCount += firstPageRows.Count;
|
||||
@@ -390,7 +414,28 @@ namespace BokBonCheck
|
||||
catch
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return (0, errmessage);
|
||||
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
resultHtml = ExtractResultContext(htmlContent, match);
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
}
|
||||
}
|
||||
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
|
||||
// 페이징이 있는지 확인하고 각 페이지 방문
|
||||
@@ -436,18 +481,42 @@ namespace BokBonCheck
|
||||
if (totalCount == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return (0, errmessage);
|
||||
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다",
|
||||
@"전체\s*0\s*건"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
resultHtml = ExtractResultContext(htmlContent, match);
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
}
|
||||
}
|
||||
resultHtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return (0, errmessage, resultHtml);
|
||||
}
|
||||
|
||||
resultHtml = $"검색성공 - 총 {totalCount}건";
|
||||
errmessage = $"검색성공({totalCount}권)";
|
||||
Console.WriteLine($"전체 검색 결과: {totalCount}건");
|
||||
return (totalCount, errmessage);
|
||||
return (totalCount, errmessage, resultHtml);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
return (-1, errmessage);
|
||||
string resultHtml = "오류 발생";
|
||||
return (-1, errmessage, resultHtml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,5 +561,67 @@ namespace BokBonCheck
|
||||
Console.WriteLine($"페이지 변경 감지 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, System.Text.RegularExpressions.Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = System.Text.RegularExpressions.Regex.Matches(searchText, tagPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = System.Text.RegularExpressions.Regex.Match(tagMatch.Value, @"<(\w+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = System.Text.RegularExpressions.Regex.Match(searchText, closeTagPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -112,9 +113,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -124,6 +126,7 @@ namespace BokBonCheck
|
||||
htmlContent.Contains("자료가 없습니다"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -146,8 +149,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
@@ -171,20 +177,25 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -193,5 +204,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,8 +107,9 @@ namespace BokBonCheck
|
||||
// JavaScript 렌더링 대기
|
||||
await Task.Delay(3000);
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -133,71 +134,21 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// JavaScript 실행 후 실제 렌더링된 DOM에서 결과 추출
|
||||
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
|
||||
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
|
||||
if (noResultElements.Count > 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
// 2. total_area에서 결과 수량 추출 (JavaScript 렌더링 후)
|
||||
try
|
||||
{
|
||||
var totalAreaElement = wait.Until(d => d.FindElement(By.CssSelector("div.total_area p.total span")));
|
||||
if (totalAreaElement != null)
|
||||
{
|
||||
var countText = totalAreaElement.Text.Trim();
|
||||
Console.WriteLine($"total_area 텍스트: '{countText}'");
|
||||
|
||||
// "총 3건" 형태에서 숫자 추출
|
||||
var match = Regex.Match(countText, @"총\s*(\d+)\s*건", RegexOptions.IgnoreCase);
|
||||
if (match.Success && int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
Console.WriteLine("검색 결과: 0건");
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"검색 결과: {count}건");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
Console.WriteLine($"total_area 요소 추출 실패: {ex1.Message}");
|
||||
}
|
||||
|
||||
// 3. 페이지 소스에서 렌더링된 결과 추출
|
||||
var pageSource = driver.PageSource;
|
||||
Console.WriteLine("페이지 소스에서 결과 추출 시도");
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다") ||
|
||||
pageSource.Contains("자료가 없습니다") ||
|
||||
pageSource.Contains("총 0건"))
|
||||
if (htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다") ||
|
||||
htmlContent.Contains("자료가 없습니다") ||
|
||||
htmlContent.Contains("총 0건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -212,11 +163,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -229,16 +183,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 완전한 페이지 로딩 대기 메서드
|
||||
private async Task WaitForCompletePageLoad(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -110,9 +111,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
// 실제 HTML 구조에 맞는 패턴으로 수정
|
||||
@@ -139,6 +141,7 @@ namespace BokBonCheck
|
||||
if (pattern.Contains(@"\s*0\s*"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -148,17 +151,21 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 디버깅을 위해 HTML 내용 일부 출력
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine($"HTML 내용 일부: {htmlContent.Substring(0, Math.Min(1000, htmlContent.Length))}");
|
||||
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
@@ -166,6 +173,7 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -177,5 +185,66 @@ namespace BokBonCheck
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,8 +227,9 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -253,71 +254,20 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = 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("검색된 자료가 없습니다"))
|
||||
if (htmlContent.Contains("0건이 검색되었습니다") ||
|
||||
htmlContent.Contains("검색결과가 없습니다") ||
|
||||
htmlContent.Contains("검색된 자료가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -332,11 +282,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -349,16 +302,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -260,7 +260,8 @@ namespace BokBonCheck
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -285,11 +286,13 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
var htmlContent = driver.PageSource;
|
||||
// 먼저 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
@@ -298,6 +301,7 @@ namespace BokBonCheck
|
||||
if (noResultText.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = noResultText;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -318,17 +322,36 @@ namespace BokBonCheck
|
||||
if (int.TryParse(match.Groups[1].Value, out int vqty))
|
||||
{
|
||||
errmessage = $"검색성공({vqty}건)";
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
return vqty;
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = $"수량값오류({match.Groups[1].Value})";
|
||||
resulthtml = match.Value;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = "수량항목없음";
|
||||
// 매칭된 부분이 없는 경우, 기본적으로 pageInfoText 부분 추출 시도
|
||||
try
|
||||
{
|
||||
var dummyMatch = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체.*");
|
||||
if (dummyMatch.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -336,6 +359,7 @@ namespace BokBonCheck
|
||||
{
|
||||
// page_info가 없는 경우 검색결과가 없는 것으로 판단
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = "검색결과 없음: " + ex.Message;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -343,11 +367,72 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "ExtractBookCount 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
|
||||
@@ -272,7 +272,8 @@ namespace BokBonCheck
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -297,11 +298,13 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
var htmlContent = driver.PageSource;
|
||||
// 먼저 검색결과가 없는 경우 확인
|
||||
try
|
||||
{
|
||||
@@ -310,6 +313,7 @@ namespace BokBonCheck
|
||||
if (noResultText.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = noResultText;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -330,17 +334,36 @@ namespace BokBonCheck
|
||||
if (int.TryParse(match.Groups[1].Value, out int vqty))
|
||||
{
|
||||
errmessage = $"검색성공({vqty}건)";
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
return vqty;
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = $"수량값오류({match.Groups[1].Value})";
|
||||
resulthtml = match.Value;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = "수량항목없음";
|
||||
// 매칭된 부분이 없는 경우, 기본적으로 pageInfoText 부분 추출 시도
|
||||
try
|
||||
{
|
||||
var dummyMatch = System.Text.RegularExpressions.Regex.Match(pageInfoText, @"전체.*");
|
||||
if (dummyMatch.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -348,6 +371,27 @@ namespace BokBonCheck
|
||||
{
|
||||
// page_info가 없는 경우 검색결과가 없는 것으로 판단
|
||||
errmessage = "검색결과없음";
|
||||
// "검색결과가 없습니다"와 같은 메시지를 찾아 context 추출 시도
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -355,11 +399,72 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "ExtractBookCount 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -100,7 +100,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -128,9 +129,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -141,6 +143,7 @@ namespace BokBonCheck
|
||||
htmlContent.Contains("총 0 건이 검색되었습니다"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -163,8 +166,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"KCM자료검색시스템 검색 결과: {count}건");
|
||||
return count;
|
||||
@@ -189,15 +195,19 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"KCM자료검색시스템 검색 결과: {count}건");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
Console.WriteLine("KCM자료검색시스템 검색결과 패턴을 찾을 수 없음");
|
||||
return -1;
|
||||
@@ -205,6 +215,7 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -213,5 +224,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,10 +193,21 @@ namespace BokBonCheck
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(30)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver);
|
||||
var resultCount = ExtractBookCount(_driver, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
result.IsSuccess = false;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.BookCount = resultCount;
|
||||
result.IsSuccess = true;
|
||||
result.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -211,10 +222,14 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver)
|
||||
private int ExtractBookCount(IWebDriver driver, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
var htmlContent = driver.PageSource;
|
||||
|
||||
// div.search-result 내부의 span에서 '전체 N' 텍스트 추출
|
||||
var resultDiv = driver.FindElement(By.CssSelector("div.ndls_result"));
|
||||
var span = resultDiv.FindElement(By.XPath(".//span[contains(text(),'전체')]"));
|
||||
@@ -222,13 +237,106 @@ namespace BokBonCheck
|
||||
var match = System.Text.RegularExpressions.Regex.Match(text, @"전체\s*(\d+)");
|
||||
if (match.Success)
|
||||
{
|
||||
return int.Parse(match.Groups[1].Value);
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = text;
|
||||
return 0;
|
||||
}
|
||||
errorMessage = $"검색성공({count}건)";
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
errorMessage = "수량항목없음";
|
||||
// 매칭된 부분이 없는 경우, 기본적으로 text 부분 추출 시도
|
||||
try
|
||||
{
|
||||
var dummyMatch = System.Text.RegularExpressions.Regex.Match(text, @"전체.*");
|
||||
if (dummyMatch.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
return 0;
|
||||
errorMessage = ex.Message;
|
||||
resulthtml = "오류발생";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -92,7 +92,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -120,9 +121,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -146,8 +148,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
@@ -161,6 +166,7 @@ namespace BokBonCheck
|
||||
htmlContent.Contains("총 0권(개)"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -183,20 +189,25 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -205,5 +216,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,9 +196,9 @@ namespace BokBonCheck
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var htmlContent = _driver.PageSource;
|
||||
var resultCount = ExtractBookCount(htmlContent, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -223,71 +223,56 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 검색결과 페이지 대기
|
||||
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
|
||||
|
||||
// 1. 검색결과가 없는 경우 확인
|
||||
try
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
var noResultPatterns = new[]
|
||||
{
|
||||
var noResultElements = driver.FindElements(By.XPath("//*[contains(text(), '검색결과가 없습니다') or contains(text(), '검색된 자료가 없습니다')]"));
|
||||
if (noResultElements.Count > 0)
|
||||
@"검색결과가 없습니다",
|
||||
@"검색된 자료가 없습니다",
|
||||
@"자료가 없습니다",
|
||||
@"전체 <strong>0</strong> 건"
|
||||
};
|
||||
|
||||
foreach (var pattern in noResultPatterns)
|
||||
{
|
||||
if (htmlContent.Contains(pattern))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
// 검색결과 없음 메시지를 포함한 HTML 조각 추출
|
||||
var index = htmlContent.IndexOf(pattern);
|
||||
if (index >= 0)
|
||||
{
|
||||
var startIndex = Math.Max(0, index - 100);
|
||||
var endIndex = Math.Min(htmlContent.Length, index + pattern.Length + 100);
|
||||
resulthtml = htmlContent.Substring(startIndex, endIndex - startIndex);
|
||||
|
||||
// 상위 태그 찾기 시도
|
||||
try
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(htmlContent, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 실패시 기본 추출 결과 사용
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = pattern;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 검색결과가 있는 경우로 진행
|
||||
}
|
||||
|
||||
// 2. totalCount에서 결과 수량 추출
|
||||
try
|
||||
{
|
||||
var totalCountElement = wait.Until(d => d.FindElement(By.CssSelector("p.totalCount strong")));
|
||||
if (totalCountElement != null)
|
||||
{
|
||||
var countText = totalCountElement.Text.Trim();
|
||||
Console.WriteLine($"totalCount 텍스트: '{countText}'");
|
||||
|
||||
if (int.TryParse(countText, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
Console.WriteLine("검색 결과: 0건");
|
||||
return 0;
|
||||
}
|
||||
errmessage = $"검색성공({count}권)";
|
||||
Console.WriteLine($"검색 결과: {count}건");
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
Console.WriteLine($"totalCount 요소 추출 실패: {ex1.Message}");
|
||||
}
|
||||
|
||||
// 3. 페이지 소스에서 결과 추출
|
||||
var pageSource = driver.PageSource;
|
||||
Console.WriteLine("페이지 소스에서 결과 추출 시도");
|
||||
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (pageSource.Contains("검색결과가 없습니다") ||
|
||||
pageSource.Contains("검색된 자료가 없습니다") ||
|
||||
pageSource.Contains("자료가 없습니다") ||
|
||||
pageSource.Contains("전체 <strong>0</strong> 건"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTML에서 다양한 패턴 찾기
|
||||
var htmlPatterns = new[]
|
||||
@@ -299,11 +284,14 @@ namespace BokBonCheck
|
||||
|
||||
foreach (var pattern in htmlPatterns)
|
||||
{
|
||||
var match = Regex.Match(pageSource, pattern, RegexOptions.IgnoreCase);
|
||||
var match = Regex.Match(htmlContent, pattern, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
// 매칭된 부분과 상위 태그 추출하여 resulthtml에 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
@@ -316,16 +304,80 @@ namespace BokBonCheck
|
||||
}
|
||||
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
resulthtml = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "ExtractBookCount 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 완전한 페이지 로딩 대기 메서드
|
||||
private async Task WaitForCompletePageLoad(WebDriverWait wait)
|
||||
{
|
||||
|
||||
@@ -269,7 +269,8 @@ namespace BokBonCheck
|
||||
await WaitForPageChange(new WebDriverWait(_driver, TimeSpan.FromSeconds(15)));
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg);
|
||||
var resultCount = ExtractBookCount(_driver, searchTerm, out string ermsg, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
if (resultCount == -1)
|
||||
{
|
||||
result.BookCount = 0;
|
||||
@@ -294,11 +295,14 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage)
|
||||
private int ExtractBookCount(IWebDriver driver, string searchTerm, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
var htmlContent = driver.PageSource;
|
||||
|
||||
// div.search-result 내부의 span에서 '전체 N' 텍스트 추출
|
||||
var resultDiv = driver.FindElement(By.CssSelector("div.search-result"));
|
||||
|
||||
@@ -306,6 +310,7 @@ namespace BokBonCheck
|
||||
if (bodytext.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = bodytext;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -315,6 +320,7 @@ namespace BokBonCheck
|
||||
if (searchTerm.Contains(searchtitle) == false)
|
||||
{
|
||||
errmessage = $"검색어불일치({searchtitle}/{searchTerm})";
|
||||
resulthtml = searchtitle;
|
||||
return -1;
|
||||
}
|
||||
var span = resultDiv.FindElement(By.XPath(".//span[contains(text(),'전체')]"));
|
||||
@@ -325,10 +331,13 @@ namespace BokBonCheck
|
||||
if (int.TryParse(match.Groups[1].Value, out int vqty) == false)
|
||||
{
|
||||
errmessage = $"수량값오류({match.Groups[1].Value})";
|
||||
resulthtml = match.Value;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage = $"검색성공({vqty}건)";
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
searchTerm = string.Empty;
|
||||
return vqty;
|
||||
}
|
||||
@@ -336,6 +345,23 @@ namespace BokBonCheck
|
||||
else
|
||||
{
|
||||
errmessage = "수량항목없음";
|
||||
// 매칭된 부분이 없는 경우, 기본적으로 text 부분 추출 시도
|
||||
try
|
||||
{
|
||||
var dummyMatch = System.Text.RegularExpressions.Regex.Match(text, @"전체.*");
|
||||
if (dummyMatch.Success)
|
||||
{
|
||||
resulthtml = ExtractResultContext(htmlContent, dummyMatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
resulthtml = htmlContent.Length > 500 ? htmlContent.Substring(0, 500) : htmlContent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -343,11 +369,72 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "ExtractBookCount 오류: " + ex.Message;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 페이지 변경을 감지하는 메서드
|
||||
public async Task WaitForPageChange(WebDriverWait wait)
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -97,7 +97,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -125,9 +126,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -150,8 +152,11 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
@@ -165,6 +170,7 @@ namespace BokBonCheck
|
||||
htmlContent.Contains("총 0건"))
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,8 +184,10 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = resultConMatch.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, resultConMatch);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
@@ -203,20 +211,25 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -225,5 +238,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -96,7 +96,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -122,15 +123,17 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errmessage, out string resulthtml)
|
||||
{
|
||||
errmessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
try
|
||||
{
|
||||
// 검색 결과가 없다는 메시지 확인
|
||||
if (htmlContent.Contains("0권(개)") || htmlContent.Contains("검색결과가 없습니다"))
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = "검색결과없음";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -153,14 +156,19 @@ namespace BokBonCheck
|
||||
if (count == 0)
|
||||
{
|
||||
errmessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errmessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errmessage = "결과수량을찾을수없음";
|
||||
return -1;
|
||||
|
||||
@@ -168,6 +176,7 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errmessage = ex.Message;
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -178,5 +187,67 @@ namespace BokBonCheck
|
||||
// HTTP 방식에서는 즉시 응답이 오므로 대기 불필요
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace BokBonCheck
|
||||
// 브라우저와 유사한 헤더 추가
|
||||
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("Accept-Encoding", "gzip, deflate, br");
|
||||
request.Headers.Add("Connection", "keep-alive");
|
||||
request.Headers.Add("Upgrade-Insecure-Requests", "1");
|
||||
|
||||
@@ -92,7 +92,8 @@ namespace BokBonCheck
|
||||
var htmlContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// 검색 결과 수 추출
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage);
|
||||
var resultCount = ExtractBookCount(htmlContent, out string errorMessage, out string resultHtml);
|
||||
result.Resulthtml = resultHtml;
|
||||
|
||||
if (resultCount == -1)
|
||||
{
|
||||
@@ -120,9 +121,10 @@ namespace BokBonCheck
|
||||
return result;
|
||||
}
|
||||
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage)
|
||||
private int ExtractBookCount(string htmlContent, out string errorMessage, out string resulthtml)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
resulthtml = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -134,12 +136,21 @@ namespace BokBonCheck
|
||||
{
|
||||
if (int.TryParse(match.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = match.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, match);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = $"수량값오류({match.Groups[1].Value})";
|
||||
resulthtml = match.Value;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -153,11 +164,21 @@ namespace BokBonCheck
|
||||
{
|
||||
if (int.TryParse(alternateMatch.Groups[1].Value, out int count))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
errorMessage = "검색결과없음";
|
||||
resulthtml = alternateMatch.Value;
|
||||
return 0;
|
||||
}
|
||||
// 매칭된 부분과 그 상위 태그를 찾아서 저장
|
||||
resulthtml = ExtractResultContext(htmlContent, alternateMatch);
|
||||
errorMessage = $"검색성공({count}권)";
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 패턴을 찾지 못한 경우
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
errorMessage = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
@@ -165,6 +186,7 @@ namespace BokBonCheck
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"결과 분석 오류: {ex.Message}";
|
||||
resulthtml = "검색결과 패턴을 찾을 수 없음";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -173,5 +195,67 @@ namespace BokBonCheck
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 매칭된 결과와 그 상위 태그를 추출
|
||||
/// </summary>
|
||||
private string ExtractResultContext(string htmlContent, Match match)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matchIndex = match.Index;
|
||||
var matchLength = match.Length;
|
||||
|
||||
// 매칭된 위치 앞쪽에서 상위 태그 시작 찾기
|
||||
var startSearchIndex = Math.Max(0, matchIndex - 200); // 매칭 위치 200자 전부터 검색
|
||||
var searchText = htmlContent.Substring(startSearchIndex, matchIndex - startSearchIndex + matchLength + Math.Min(200, htmlContent.Length - matchIndex - matchLength));
|
||||
|
||||
// 상위 태그 패턴들 (div, p, h1-h6, span 등)
|
||||
var tagPatterns = new[] { @"<(div|p|h[1-6]|span|section|article)[^>]*>", @"<[^>]+>" };
|
||||
|
||||
string resultContext = match.Value; // 기본값은 매칭된 부분만
|
||||
|
||||
foreach (var tagPattern in tagPatterns)
|
||||
{
|
||||
// 매칭된 부분 앞에서 가장 가까운 태그 시작 찾기
|
||||
var tagMatches = Regex.Matches(searchText, tagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
for (int i = tagMatches.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var tagMatch = tagMatches[i];
|
||||
if (tagMatch.Index < (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 태그 이름 추출
|
||||
var tagName = Regex.Match(tagMatch.Value, @"<(\w+)", RegexOptions.IgnoreCase).Groups[1].Value;
|
||||
|
||||
// 닫는 태그 찾기
|
||||
var closeTagPattern = $@"</{tagName}[^>]*>";
|
||||
var closeMatch = Regex.Match(searchText, closeTagPattern, RegexOptions.IgnoreCase);
|
||||
|
||||
if (closeMatch.Success && closeMatch.Index > (matchIndex - startSearchIndex))
|
||||
{
|
||||
// 상위 태그와 그 내용을 포함하여 반환
|
||||
var startIdx = tagMatch.Index;
|
||||
var endIdx = closeMatch.Index + closeMatch.Length;
|
||||
resultContext = searchText.Substring(startIdx, Math.Min(endIdx - startIdx, 500)); // 최대 500자
|
||||
return resultContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 상위 태그를 찾지 못한 경우, 매칭 전후 50자씩 포함
|
||||
var contextStart = Math.Max(0, matchIndex - 50);
|
||||
var contextEnd = Math.Min(htmlContent.Length, matchIndex + matchLength + 50);
|
||||
resultContext = htmlContent.Substring(contextStart, contextEnd - contextStart);
|
||||
|
||||
return resultContext;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"ExtractResultContext 오류: {ex.Message}");
|
||||
return match.Value; // 오류 시 매칭된 부분만 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace WindowsFormsApp1
|
||||
else
|
||||
dataGridView.Sort(dataGridView.Columns[col], System.ComponentModel.ListSortDirection.Ascending);
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// * Row헤더에 체크박스를 넣는 기능*
|
||||
@@ -99,7 +99,7 @@ namespace WindowsFormsApp1
|
||||
}
|
||||
private void datagridview_checkBox_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach(DataGridViewRow r in ((DataGridView)sender).Rows)
|
||||
foreach (DataGridViewRow r in ((DataGridView)sender).Rows)
|
||||
{
|
||||
r.Cells["colCheck"].Value = ((CheckBox)sender).Checked;
|
||||
}
|
||||
@@ -119,16 +119,23 @@ namespace WindowsFormsApp1
|
||||
char[] columnSplitter = { '\t' };
|
||||
|
||||
//get the text from clipboard
|
||||
IDataObject dataInClipboard = Clipboard.GetDataObject();
|
||||
|
||||
string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);
|
||||
if (Clipboard.ContainsText() == false) return;
|
||||
|
||||
string stringInClipboard = null;
|
||||
|
||||
if (e.Alt)
|
||||
stringInClipboard = Clipboard.GetText(TextDataFormat.UnicodeText);
|
||||
else
|
||||
stringInClipboard = Clipboard.GetText();// (string)objdata;
|
||||
|
||||
//split it into lines
|
||||
//20230209 \r텝 기능과 \n 줄넘김 기능을 같이 공백 제거 처리해버려 공백칸을 활용해야 함에도 제거하는 현상 발생.
|
||||
//텝 공백 문자열 동시에 사용하여 분류
|
||||
// stringInClipboard= stringInClipboard.Replace("\r", "");
|
||||
if (stringInClipboard == null) return;
|
||||
List<string>rowsInClipboard = stringInClipboard.Split(rowSpliteter, StringSplitOptions.None).ToList();
|
||||
rowsInClipboard.RemoveAt(rowsInClipboard.Count-1);
|
||||
List<string> rowsInClipboard = stringInClipboard.Split(rowSpliteter, StringSplitOptions.None).ToList();
|
||||
rowsInClipboard.RemoveAt(rowsInClipboard.Count - 1);
|
||||
//get the row and column of selected cell in dataGridView1
|
||||
int r = ((DataGridView)sender).SelectedCells[0].RowIndex;
|
||||
int c = ((DataGridView)sender).SelectedCells[0].ColumnIndex;
|
||||
@@ -209,7 +216,7 @@ namespace WindowsFormsApp1
|
||||
private Rectangle dragBoxFromMouseDown;
|
||||
private int rowIndexFromMouseDown;
|
||||
private int rowIndexOfItemUnderMouseToDrop;
|
||||
|
||||
|
||||
public void MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
DataGridView dataGridView = sender as DataGridView;
|
||||
@@ -292,7 +299,8 @@ namespace WindowsFormsApp1
|
||||
string[] db_data = db_res1.Split('|');
|
||||
string[] db_pur = db_res2.Split('|');
|
||||
|
||||
if (db_res1.Length < 3) {
|
||||
if (db_res1.Length < 3)
|
||||
{
|
||||
MessageBox.Show("DB호출 에러!", "Error");
|
||||
return "False";
|
||||
}
|
||||
@@ -300,20 +308,26 @@ namespace WindowsFormsApp1
|
||||
string fax = string.Empty;
|
||||
string emchk = string.Empty;
|
||||
|
||||
if (db_pur.Length > 3) {
|
||||
for(int a= 0; a < db_pur.Length; a++)
|
||||
if (db_pur.Length > 3)
|
||||
{
|
||||
for (int a = 0; a < db_pur.Length; a++)
|
||||
{
|
||||
if (a % 3 == 0) { // 전화번호
|
||||
if (db_pur[a] != "") {
|
||||
if (a % 3 == 0)
|
||||
{ // 전화번호
|
||||
if (db_pur[a] != "")
|
||||
{
|
||||
tel = db_pur[a];
|
||||
}
|
||||
}
|
||||
if (a % 3 == 1) { // 팩스
|
||||
if (db_pur[a] != "") {
|
||||
if (a % 3 == 1)
|
||||
{ // 팩스
|
||||
if (db_pur[a] != "")
|
||||
{
|
||||
fax = db_pur[a];
|
||||
}
|
||||
}
|
||||
if (a % 3 == 2) { // 팩스 이메일 체크
|
||||
if (a % 3 == 2)
|
||||
{ // 팩스 이메일 체크
|
||||
emchk = db_pur[a];
|
||||
}
|
||||
}
|
||||
@@ -401,7 +415,7 @@ namespace WindowsFormsApp1
|
||||
#region 주문일자 / 보낸곳 (4행)
|
||||
rng = ws.Range["A4", "C4"];
|
||||
rng.MergeCells = true;
|
||||
rng.Value2 = "주문일자 : "+DateTime.Now.ToString("yyyy-MM-dd H:m:ss");
|
||||
rng.Value2 = "주문일자 : " + DateTime.Now.ToString("yyyy-MM-dd H:m:ss");
|
||||
rng.HorizontalAlignment = Excel.XlHAlign.xlHAlignLeft;
|
||||
rng.Font.Bold = true;
|
||||
|
||||
@@ -495,7 +509,7 @@ namespace WindowsFormsApp1
|
||||
|
||||
#region 추신
|
||||
endcount++;
|
||||
string 발송처 = "D"+endcount.ToString();
|
||||
string 발송처 = "D" + endcount.ToString();
|
||||
|
||||
rng = ws.Range["A" + endcount, "C" + endcount];
|
||||
rng.MergeCells = true;
|
||||
@@ -551,7 +565,7 @@ namespace WindowsFormsApp1
|
||||
rng2.Font.Bold = true;
|
||||
|
||||
////////
|
||||
rng = ws.Range[발송처, "D"+endcount];
|
||||
rng = ws.Range[발송처, "D" + endcount];
|
||||
rng.MergeCells = true;
|
||||
rng.Value2 = "발 송 처";
|
||||
rng.Font.Bold = true;
|
||||
@@ -580,10 +594,10 @@ namespace WindowsFormsApp1
|
||||
|
||||
application.Interactive = true;
|
||||
application.Quit();
|
||||
|
||||
|
||||
return FileName;
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.ToString());
|
||||
return "False";
|
||||
@@ -630,9 +644,9 @@ namespace WindowsFormsApp1
|
||||
private string Excel_Sub(string[] data)
|
||||
{
|
||||
string[] length = {
|
||||
"1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "10",
|
||||
"11", "12", "13", "14", "15",
|
||||
"1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "10",
|
||||
"11", "12", "13", "14", "15",
|
||||
"16", "17", "18", "19", "20",
|
||||
"21", "22", "23", "24", "25", "26"
|
||||
};
|
||||
@@ -646,8 +660,8 @@ namespace WindowsFormsApp1
|
||||
|
||||
string count = data.Length.ToString();
|
||||
string res = string.Empty;
|
||||
|
||||
for(int a = 0; a < length.Length; a++)
|
||||
|
||||
for (int a = 0; a < length.Length; a++)
|
||||
{
|
||||
if (length[a] == count)
|
||||
{
|
||||
@@ -658,7 +672,7 @@ namespace WindowsFormsApp1
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
public class Helper_Print
|
||||
public class Helper_Print
|
||||
{
|
||||
/// <summary>
|
||||
/// 행의 갯수
|
||||
@@ -788,7 +802,7 @@ namespace WindowsFormsApp1
|
||||
/// <param name="file_name"></param>
|
||||
/// <param name="fax_param">[0] 발신번호 / [1] 수신번호
|
||||
/// / [2] 수신자 회사명 / [3 ]수신자명 </param>
|
||||
public string Send_BaroFax(string file_name, string[] fax_param )
|
||||
public string Send_BaroFax(string file_name, string[] fax_param)
|
||||
{
|
||||
BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();
|
||||
|
||||
@@ -824,7 +838,7 @@ namespace WindowsFormsApp1
|
||||
BaroService_FAXSoapClient fAXSoapClient = new BaroService_FAXSoapClient();
|
||||
|
||||
// 수신자회사명, 수신번호, 전송일시, 전송결과, 전송페이지수, 성공페이지수, 전송파일명
|
||||
string[] MsgBox_Array = {
|
||||
string[] MsgBox_Array = {
|
||||
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiveCorp,
|
||||
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).ReceiverNum,
|
||||
fAXSoapClient.GetFaxMessage(CERTKEY, CorpNum, sendkey).SendDT,
|
||||
@@ -1190,9 +1204,9 @@ namespace WindowsFormsApp1
|
||||
public bool IsConnected { get; set; }
|
||||
|
||||
private string ipAddr = string.Empty;
|
||||
private string Port = string.Empty;
|
||||
private string Port = string.Empty;
|
||||
private string userId = string.Empty;
|
||||
private string Pwd = string.Empty;
|
||||
private string Pwd = string.Empty;
|
||||
|
||||
public FTP() { }
|
||||
|
||||
@@ -1219,7 +1233,7 @@ namespace WindowsFormsApp1
|
||||
using (ftpRequest.GetResponse()) { }
|
||||
this.IsConnected = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.LastException = ex;
|
||||
System.Reflection.MemberInfo info = System.Reflection.MethodInfo.GetCurrentMethod();
|
||||
@@ -1288,7 +1302,7 @@ namespace WindowsFormsApp1
|
||||
buff = null;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.ToString());
|
||||
this.LastException = ex;
|
||||
@@ -1392,14 +1406,14 @@ namespace WindowsFormsApp1
|
||||
|
||||
if (reader != null) reader.Close();
|
||||
|
||||
foreach(string file in result.ToString().Split('\n'))
|
||||
foreach (string file in result.ToString().Split('\n'))
|
||||
{
|
||||
resultList.Add(file);
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.LastException = ex;
|
||||
|
||||
@@ -1420,12 +1434,12 @@ namespace WindowsFormsApp1
|
||||
|
||||
try
|
||||
{
|
||||
foreach(string tmpFolder in arrDir)
|
||||
foreach (string tmpFolder in arrDir)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tmpFolder == string.Empty) continue;
|
||||
|
||||
|
||||
currentDir += @"/" + tmpFolder;
|
||||
|
||||
string url = string.Format(@"FTP://{0}:{1}/{2}", this.ipAddr, this.Port, currentDir);
|
||||
@@ -1453,9 +1467,11 @@ namespace WindowsFormsApp1
|
||||
private void checkDir(string localFullPathFile)
|
||||
{
|
||||
FileInfo finfo = new FileInfo(localFullPathFile);
|
||||
if (!finfo.Exists) {
|
||||
if (!finfo.Exists)
|
||||
{
|
||||
DirectoryInfo dInfo = new DirectoryInfo(finfo.DirectoryName);
|
||||
if (!dInfo.Exists) {
|
||||
if (!dInfo.Exists)
|
||||
{
|
||||
dInfo.Create();
|
||||
}
|
||||
}
|
||||
@@ -1552,30 +1568,35 @@ namespace WindowsFormsApp1
|
||||
int tDown = 0;
|
||||
for (int a = 0; a < array_text.Count; a++)
|
||||
{
|
||||
// if (array_text[a] == "") continue;
|
||||
// if (array_text[a] == "") continue;
|
||||
|
||||
num.Add(array_text[a].Substring(0, 3));
|
||||
|
||||
if (array_text[a][5] == '▼') {
|
||||
if (array_text[a][5] == '▼')
|
||||
{
|
||||
array_text[a] = array_text[a].Remove(0, 3);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
array_text[a] = array_text[a].Remove(0, 5);
|
||||
}
|
||||
|
||||
가변길이 += array_text[a] + "\n";
|
||||
int textLength = 0;
|
||||
if (EncodingType == "UTF-8") {
|
||||
if (EncodingType == "UTF-8")
|
||||
{
|
||||
textLength = Encoding.UTF8.GetBytes(array_text[a]).Length
|
||||
- WordCheck(array_text[a], "▲")
|
||||
- WordCheck(array_text[a], "▼");
|
||||
}
|
||||
else if (EncodingType == "UniCode") {
|
||||
else if (EncodingType == "UniCode")
|
||||
{
|
||||
textLength = Encoding.Unicode.GetBytes(array_text[a]).Length
|
||||
- WordCheck(array_text[a], "▲")
|
||||
- WordCheck(array_text[a], "▼");
|
||||
}
|
||||
else { // ANSI
|
||||
else
|
||||
{ // ANSI
|
||||
textLength = Encoding.Default.GetBytes(array_text[a]).Length
|
||||
- WordCheck(array_text[a], "▲")
|
||||
- WordCheck(array_text[a], "▼");
|
||||
@@ -1587,12 +1608,13 @@ namespace WindowsFormsApp1
|
||||
|
||||
for (int a = 0; a < array_text.Count; a++)
|
||||
{
|
||||
if (a == 0) { //total.Add("0");
|
||||
if (a == 0)
|
||||
{ //total.Add("0");
|
||||
tTotal.Add(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// total.Add(total[a - 1] + count[a - 1]);
|
||||
// total.Add(total[a - 1] + count[a - 1]);
|
||||
tTotal.Add(tTotal[a - 1] + tCount[a - 1]);
|
||||
}
|
||||
//else if (a == 1)
|
||||
@@ -1609,7 +1631,7 @@ namespace WindowsFormsApp1
|
||||
// else c = Convert.ToInt32(Encoding.Default.GetBytes(array_text[a - 2]).Length.ToString()) - WordCheck(array_text[a - 2], "▲") - WordCheck(array_text[a - 2], "▼");
|
||||
// int res = b + c;
|
||||
// total.Add(res.ToString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
string[] str_num = num.ToArray();
|
||||
@@ -1626,7 +1648,7 @@ namespace WindowsFormsApp1
|
||||
// else if (total[a].Length == 2) { total[a] = total[a].Insert(0, "000"); }
|
||||
// else if (total[a].Length == 1) { total[a] = total[a].Insert(0, "0000"); }
|
||||
// 디렉토리 += str_num[a] + count[a] + total[a] + "\n";
|
||||
디렉토리 += str_num[a] + tCount[a].ToString().PadLeft(4, '0') + tTotal[a].ToString().PadLeft(5, '0');
|
||||
디렉토리 += str_num[a] + tCount[a].ToString().PadLeft(4, '0') + tTotal[a].ToString().PadLeft(5, '0');
|
||||
}
|
||||
|
||||
string[] 리더부 = { "00000","n", "a", "m", " ",
|
||||
@@ -1642,11 +1664,11 @@ namespace WindowsFormsApp1
|
||||
|
||||
string dp = 가변길이 + 디렉토리;
|
||||
int recode = 0;
|
||||
if (EncodingType == "UTF-8") recode = Encoding.UTF8.GetBytes(dp).Length- WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
|
||||
if (EncodingType == "UTF-8") recode = Encoding.UTF8.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
|
||||
else if (EncodingType == "UniCode") recode = Encoding.Unicode.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
|
||||
else recode = Encoding.Default.GetBytes(dp).Length- WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
|
||||
|
||||
|
||||
else recode = Encoding.Default.GetBytes(dp).Length - WordCheck(dp, "▲") - WordCheck(dp, "▼") - WordCheck(dp, "↔");
|
||||
|
||||
|
||||
리더부[0] = insert_Zero(recode + 24, 5);
|
||||
|
||||
int data_addr = 24 + Encoding.Default.GetBytes(디렉토리).Length - WordCheck(디렉토리, "▲");
|
||||
@@ -1693,7 +1715,7 @@ namespace WindowsFormsApp1
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 추가하고 싶은 태그를 뷰형태의 마크에 추가하는 함수.
|
||||
@@ -1706,7 +1728,7 @@ namespace WindowsFormsApp1
|
||||
if (Tag.Length < 3) return "";
|
||||
|
||||
int TargetTagNum = Convert.ToInt32(Tag.Substring(0, 3));
|
||||
|
||||
|
||||
string[] SplitView = TypeView.Split('\n');
|
||||
List<string> View = new List<string>(SplitView);
|
||||
|
||||
@@ -1731,9 +1753,9 @@ namespace WindowsFormsApp1
|
||||
/// <param name="pAddTag">추가할 태그 (태그명\t지시기호\t태그내용)</param>
|
||||
/// <param name="pTargetData">뷰형태의 마크</param>
|
||||
/// <returns></returns>
|
||||
public string AddTagInMarc(int pTargetTagNum,string pAddTag, string pTargetData)//TagTarget Num 을 찾아서 있을경우는 해당 Tag 데이터를 전송, 없을경우는 신규로 해야함.
|
||||
public string AddTagInMarc(int pTargetTagNum, string pAddTag, string pTargetData)//TagTarget Num 을 찾아서 있을경우는 해당 Tag 데이터를 전송, 없을경우는 신규로 해야함.
|
||||
{
|
||||
|
||||
|
||||
if (pAddTag.Length < 3) return "";
|
||||
string tRet = pTargetData;
|
||||
// ex ) 020 : ~~~ 에 XXXX 내용줄 뒤에 추가
|
||||
@@ -1827,7 +1849,7 @@ namespace WindowsFormsApp1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{// 기존 태그 변경
|
||||
int endIdx = SplitView[a].IndexOf("▼", startIdx + 1);
|
||||
@@ -1906,7 +1928,7 @@ namespace WindowsFormsApp1
|
||||
/// <param name="marc">마크 데이터</param>
|
||||
/// <param name="search">추출할 함수(배열)</param>
|
||||
/// <returns></returns>
|
||||
public string[] Take_Tag(string marc, string[] search,bool pSearchTag = false)
|
||||
public string[] Take_Tag(string marc, string[] search, bool pSearchTag = false)
|
||||
{
|
||||
string[] ary = marc.Split('');
|
||||
string[] tag = res_dir(ary[0].Substring(24));
|
||||
@@ -1958,7 +1980,7 @@ namespace WindowsFormsApp1
|
||||
//memo = result[b];
|
||||
start += 2;
|
||||
int end = -1;
|
||||
if (tmp.Length > 1) end=tmp.IndexOf("", start);
|
||||
if (tmp.Length > 1) end = tmp.IndexOf("", start);
|
||||
if (memo == result[b])
|
||||
break;
|
||||
|
||||
@@ -2188,7 +2210,8 @@ namespace WindowsFormsApp1
|
||||
/// <param name="e">EventArgs</param>
|
||||
public void Int_Comma(object sender, EventArgs e)
|
||||
{
|
||||
if (((TextBox)sender).Text != "") {
|
||||
if (((TextBox)sender).Text != "")
|
||||
{
|
||||
string text;
|
||||
text = ((TextBox)sender).Text.Replace(",", "");
|
||||
((TextBox)sender).Text = String.Format("{0:#,###}", Convert.ToInt32(text));
|
||||
@@ -2204,7 +2227,7 @@ namespace WindowsFormsApp1
|
||||
public bool isContainHangul(string value)
|
||||
{
|
||||
char[] charArr = value.ToCharArray();
|
||||
foreach(char c in charArr)
|
||||
foreach (char c in charArr)
|
||||
{
|
||||
if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
|
||||
return true;
|
||||
@@ -2221,7 +2244,7 @@ namespace WindowsFormsApp1
|
||||
public bool CheckString(string value, string chkString)
|
||||
{
|
||||
int index = value.IndexOf(chkString);
|
||||
if (index < 0)
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -2264,10 +2287,10 @@ namespace WindowsFormsApp1
|
||||
public class API
|
||||
{
|
||||
|
||||
public string CheckString(string pText,string pStr)
|
||||
public string CheckString(string pText, string pStr)
|
||||
{
|
||||
string tRet = pText;
|
||||
Regex reg = new Regex(@"([\"+pStr+"]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
|
||||
Regex reg = new Regex(@"([\" + pStr + "]+)" + @"[가-힣]+");//+ @"([\>]+)");//new Regex(@"([\<]+)"+ @"[ㄱ-ㅎ가-힣]+"+@"([\>]+)");
|
||||
MatchCollection tMatch = reg.Matches(tRet);
|
||||
for (int i = 0; i < tMatch.Count; i++)
|
||||
{
|
||||
@@ -2326,8 +2349,9 @@ namespace WindowsFormsApp1
|
||||
xml = CheckString(xml, "〈");
|
||||
doc.LoadXml(xml);
|
||||
}
|
||||
catch (Exception ex){
|
||||
return "";
|
||||
catch (Exception ex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
var json = JsonConvert.SerializeXmlNode(doc);
|
||||
|
||||
@@ -2520,19 +2544,23 @@ namespace WindowsFormsApp1
|
||||
{
|
||||
if (length == 1)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
tmp_data.Add(docs[Param[b]]["#text"]);
|
||||
}
|
||||
catch (KeyNotFoundException e) {
|
||||
catch (KeyNotFoundException e)
|
||||
{
|
||||
tmp_data.Add("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
tmp_data.Add(docs[a][Param[b]]["#text"]);
|
||||
}
|
||||
catch (KeyNotFoundException e) {
|
||||
catch (KeyNotFoundException e)
|
||||
{
|
||||
tmp_data.Add("");
|
||||
}
|
||||
}
|
||||
@@ -2649,8 +2677,8 @@ namespace WindowsFormsApp1
|
||||
return dialogResult;
|
||||
}
|
||||
}
|
||||
public class PrintLine
|
||||
{
|
||||
public class PrintLine
|
||||
{
|
||||
string num { get; set; }
|
||||
string count { get; set; }
|
||||
string list_name { get; set; }
|
||||
@@ -2963,7 +2991,7 @@ namespace WindowsFormsApp1
|
||||
{
|
||||
string version = "0";
|
||||
var fn = Application.StartupPath + "\\update.inf";
|
||||
if(System.IO.File.Exists(fn))
|
||||
if (System.IO.File.Exists(fn))
|
||||
{
|
||||
StreamReader sr = new StreamReader(fn);
|
||||
while (!sr.EndOfStream)
|
||||
@@ -2976,7 +3004,7 @@ namespace WindowsFormsApp1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Reference.svcmap</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Helper_LibraryDelaySettings.cs" />
|
||||
<Compile Include="PUB.cs" />
|
||||
<Compile Include="SearchModel\AnsanLibSearcher.cs" />
|
||||
<Compile Include="SearchModel\BookSearchService.cs" />
|
||||
|
||||
179
unimarc/unimarc/마크/Check_copyWD.Designer.cs
generated
179
unimarc/unimarc/마크/Check_copyWD.Designer.cs
generated
@@ -28,7 +28,8 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.chkShowBrowser = new System.Windows.Forms.CheckBox();
|
||||
this.chkRetryErrData = new System.Windows.Forms.CheckBox();
|
||||
@@ -50,10 +51,9 @@
|
||||
this.lbl_PW = new System.Windows.Forms.Label();
|
||||
this.lbl_ID = new System.Windows.Forms.Label();
|
||||
this.dv1 = new System.Windows.Forms.DataGridView();
|
||||
this.book_name = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.book_comp = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.Count = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.dvc_remark = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.일반문자로붙여넣기ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.btn_ApplyFilter = new System.Windows.Forms.Button();
|
||||
this.panel3 = new System.Windows.Forms.Panel();
|
||||
this.panel6 = new System.Windows.Forms.Panel();
|
||||
@@ -66,19 +66,30 @@
|
||||
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.book_name = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.book_comp = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.Count = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.dvc_remark = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.dvc_resulthtml = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.nudAddDelay = new System.Windows.Forms.NumericUpDown();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.panel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dv1)).BeginInit();
|
||||
this.contextMenuStrip1.SuspendLayout();
|
||||
this.panel3.SuspendLayout();
|
||||
this.panel6.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.panel4.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudAddDelay)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.panel1.Controls.Add(this.label1);
|
||||
this.panel1.Controls.Add(this.nudAddDelay);
|
||||
this.panel1.Controls.Add(this.chkShowBrowser);
|
||||
this.panel1.Controls.Add(this.chkRetryErrData);
|
||||
this.panel1.Controls.Add(this.groupBox1);
|
||||
@@ -90,7 +101,7 @@
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 34);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(637, 106);
|
||||
this.panel1.Size = new System.Drawing.Size(719, 106);
|
||||
this.panel1.TabIndex = 0;
|
||||
//
|
||||
// chkShowBrowser
|
||||
@@ -98,7 +109,7 @@
|
||||
this.chkShowBrowser.AutoSize = true;
|
||||
this.chkShowBrowser.Checked = true;
|
||||
this.chkShowBrowser.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.chkShowBrowser.Location = new System.Drawing.Point(515, 81);
|
||||
this.chkShowBrowser.Location = new System.Drawing.Point(618, 50);
|
||||
this.chkShowBrowser.Name = "chkShowBrowser";
|
||||
this.chkShowBrowser.Size = new System.Drawing.Size(96, 16);
|
||||
this.chkShowBrowser.TabIndex = 8;
|
||||
@@ -125,7 +136,7 @@
|
||||
this.groupBox1.Controls.Add(this.radTargetAll);
|
||||
this.groupBox1.Location = new System.Drawing.Point(318, 34);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(304, 39);
|
||||
this.groupBox1.Size = new System.Drawing.Size(294, 39);
|
||||
this.groupBox1.TabIndex = 6;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "검색대상";
|
||||
@@ -133,7 +144,7 @@
|
||||
// radTargetErr
|
||||
//
|
||||
this.radTargetErr.AutoSize = true;
|
||||
this.radTargetErr.Location = new System.Drawing.Point(197, 16);
|
||||
this.radTargetErr.Location = new System.Drawing.Point(239, 16);
|
||||
this.radTargetErr.Name = "radTargetErr";
|
||||
this.radTargetErr.Size = new System.Drawing.Size(47, 16);
|
||||
this.radTargetErr.TabIndex = 9;
|
||||
@@ -143,7 +154,7 @@
|
||||
// radTargetEmpty
|
||||
//
|
||||
this.radTargetEmpty.AutoSize = true;
|
||||
this.radTargetEmpty.Location = new System.Drawing.Point(144, 16);
|
||||
this.radTargetEmpty.Location = new System.Drawing.Point(172, 16);
|
||||
this.radTargetEmpty.Name = "radTargetEmpty";
|
||||
this.radTargetEmpty.Size = new System.Drawing.Size(47, 16);
|
||||
this.radTargetEmpty.TabIndex = 8;
|
||||
@@ -153,7 +164,7 @@
|
||||
// radTargetErrEmpty
|
||||
//
|
||||
this.radTargetErrEmpty.AutoSize = true;
|
||||
this.radTargetErrEmpty.Location = new System.Drawing.Point(61, 17);
|
||||
this.radTargetErrEmpty.Location = new System.Drawing.Point(75, 16);
|
||||
this.radTargetErrEmpty.Name = "radTargetErrEmpty";
|
||||
this.radTargetErrEmpty.Size = new System.Drawing.Size(77, 16);
|
||||
this.radTargetErrEmpty.TabIndex = 7;
|
||||
@@ -209,7 +220,7 @@
|
||||
//
|
||||
this.btn_Start.Location = new System.Drawing.Point(470, 4);
|
||||
this.btn_Start.Name = "btn_Start";
|
||||
this.btn_Start.Size = new System.Drawing.Size(75, 24);
|
||||
this.btn_Start.Size = new System.Drawing.Size(153, 24);
|
||||
this.btn_Start.TabIndex = 2;
|
||||
this.btn_Start.Text = "검색시작";
|
||||
this.btn_Start.UseVisualStyleBackColor = true;
|
||||
@@ -217,7 +228,7 @@
|
||||
//
|
||||
// btn_Stop
|
||||
//
|
||||
this.btn_Stop.Location = new System.Drawing.Point(548, 4);
|
||||
this.btn_Stop.Location = new System.Drawing.Point(631, 4);
|
||||
this.btn_Stop.Name = "btn_Stop";
|
||||
this.btn_Stop.Size = new System.Drawing.Size(75, 24);
|
||||
this.btn_Stop.TabIndex = 2;
|
||||
@@ -227,7 +238,7 @@
|
||||
//
|
||||
// btn_Close
|
||||
//
|
||||
this.btn_Close.Location = new System.Drawing.Point(548, 4);
|
||||
this.btn_Close.Location = new System.Drawing.Point(631, 4);
|
||||
this.btn_Close.Name = "btn_Close";
|
||||
this.btn_Close.Size = new System.Drawing.Size(75, 24);
|
||||
this.btn_Close.TabIndex = 2;
|
||||
@@ -270,14 +281,14 @@
|
||||
this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.panel2.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel2.Name = "panel2";
|
||||
this.panel2.Size = new System.Drawing.Size(637, 34);
|
||||
this.panel2.Size = new System.Drawing.Size(719, 34);
|
||||
this.panel2.TabIndex = 0;
|
||||
//
|
||||
// btn_SiteDenote
|
||||
//
|
||||
this.btn_SiteDenote.Location = new System.Drawing.Point(462, 5);
|
||||
this.btn_SiteDenote.Location = new System.Drawing.Point(470, 5);
|
||||
this.btn_SiteDenote.Name = "btn_SiteDenote";
|
||||
this.btn_SiteDenote.Size = new System.Drawing.Size(77, 23);
|
||||
this.btn_SiteDenote.Size = new System.Drawing.Size(155, 23);
|
||||
this.btn_SiteDenote.TabIndex = 4;
|
||||
this.btn_SiteDenote.Text = "사이트 표출";
|
||||
this.btn_SiteDenote.UseVisualStyleBackColor = true;
|
||||
@@ -307,55 +318,52 @@
|
||||
this.dv1.BackgroundColor = System.Drawing.SystemColors.Control;
|
||||
this.dv1.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.dv1.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
|
||||
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
|
||||
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Control;
|
||||
dataGridViewCellStyle2.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.WindowText;
|
||||
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.dv1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle2;
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
|
||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
|
||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
|
||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
|
||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.dv1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
|
||||
this.dv1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dv1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.book_name,
|
||||
this.book_comp,
|
||||
this.Count,
|
||||
this.dvc_remark});
|
||||
this.dvc_remark,
|
||||
this.dvc_resulthtml});
|
||||
this.dv1.ContextMenuStrip = this.contextMenuStrip1;
|
||||
this.dv1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dv1.Location = new System.Drawing.Point(0, 0);
|
||||
this.dv1.Name = "dv1";
|
||||
this.dv1.RowTemplate.Height = 23;
|
||||
this.dv1.Size = new System.Drawing.Size(637, 542);
|
||||
this.dv1.Size = new System.Drawing.Size(719, 542);
|
||||
this.dv1.TabIndex = 1;
|
||||
this.dv1.RowPostPaint += new System.Windows.Forms.DataGridViewRowPostPaintEventHandler(this.dataGridView1_RowPostPaint);
|
||||
this.dv1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView1_KeyDown);
|
||||
//
|
||||
// book_name
|
||||
// contextMenuStrip1
|
||||
//
|
||||
this.book_name.HeaderText = "도서명(총서명)";
|
||||
this.book_name.Name = "book_name";
|
||||
this.book_name.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.book_name.Width = 300;
|
||||
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem,
|
||||
this.일반문자로붙여넣기ToolStripMenuItem});
|
||||
this.contextMenuStrip1.Name = "contextMenuStrip1";
|
||||
this.contextMenuStrip1.Size = new System.Drawing.Size(215, 48);
|
||||
//
|
||||
// book_comp
|
||||
// 유니코드문자로붙여넝ㅎ기ToolStripMenuItem
|
||||
//
|
||||
this.book_comp.HeaderText = "출판사";
|
||||
this.book_comp.Name = "book_comp";
|
||||
this.book_comp.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.book_comp.Width = 120;
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem.Name = "유니코드문자로붙여넝ㅎ기ToolStripMenuItem";
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem.Size = new System.Drawing.Size(214, 22);
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem.Text = "유니코드 문자로 붙여넣기";
|
||||
this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem.Click += new System.EventHandler(this.유니코드문자로붙여넝ㅎ기ToolStripMenuItem_Click);
|
||||
//
|
||||
// Count
|
||||
// 일반문자로붙여넣기ToolStripMenuItem
|
||||
//
|
||||
this.Count.HeaderText = "검색 수";
|
||||
this.Count.Name = "Count";
|
||||
this.Count.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.Count.Width = 50;
|
||||
//
|
||||
// dvc_remark
|
||||
//
|
||||
this.dvc_remark.HeaderText = "비고";
|
||||
this.dvc_remark.Name = "dvc_remark";
|
||||
this.dvc_remark.Width = 110;
|
||||
this.일반문자로붙여넣기ToolStripMenuItem.Name = "일반문자로붙여넣기ToolStripMenuItem";
|
||||
this.일반문자로붙여넣기ToolStripMenuItem.Size = new System.Drawing.Size(214, 22);
|
||||
this.일반문자로붙여넣기ToolStripMenuItem.Text = "일반 문자로 붙여넣기";
|
||||
this.일반문자로붙여넣기ToolStripMenuItem.Click += new System.EventHandler(this.일반문자로붙여넣기ToolStripMenuItem_Click);
|
||||
//
|
||||
// btn_ApplyFilter
|
||||
//
|
||||
@@ -376,7 +384,7 @@
|
||||
this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel3.Location = new System.Drawing.Point(0, 0);
|
||||
this.panel3.Name = "panel3";
|
||||
this.panel3.Size = new System.Drawing.Size(637, 738);
|
||||
this.panel3.Size = new System.Drawing.Size(719, 738);
|
||||
this.panel3.TabIndex = 3;
|
||||
//
|
||||
// panel6
|
||||
@@ -386,7 +394,7 @@
|
||||
this.panel6.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.panel6.Location = new System.Drawing.Point(0, 174);
|
||||
this.panel6.Name = "panel6";
|
||||
this.panel6.Size = new System.Drawing.Size(637, 564);
|
||||
this.panel6.Size = new System.Drawing.Size(719, 564);
|
||||
this.panel6.TabIndex = 3;
|
||||
//
|
||||
// statusStrip1
|
||||
@@ -396,7 +404,7 @@
|
||||
this.lbSite});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 542);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(637, 22);
|
||||
this.statusStrip1.Size = new System.Drawing.Size(719, 22);
|
||||
this.statusStrip1.TabIndex = 2;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
@@ -424,7 +432,7 @@
|
||||
this.panel4.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.panel4.Location = new System.Drawing.Point(0, 140);
|
||||
this.panel4.Name = "panel4";
|
||||
this.panel4.Size = new System.Drawing.Size(637, 34);
|
||||
this.panel4.Size = new System.Drawing.Size(719, 34);
|
||||
this.panel4.TabIndex = 2;
|
||||
//
|
||||
// chk_RemoveBrit
|
||||
@@ -477,11 +485,60 @@
|
||||
this.chk_spChar.Text = "특수문자 제거";
|
||||
this.chk_spChar.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// book_name
|
||||
//
|
||||
this.book_name.HeaderText = "도서명(총서명)";
|
||||
this.book_name.Name = "book_name";
|
||||
this.book_name.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.book_name.Width = 300;
|
||||
//
|
||||
// book_comp
|
||||
//
|
||||
this.book_comp.HeaderText = "출판사";
|
||||
this.book_comp.Name = "book_comp";
|
||||
this.book_comp.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.book_comp.Width = 120;
|
||||
//
|
||||
// Count
|
||||
//
|
||||
this.Count.HeaderText = "검색 수";
|
||||
this.Count.Name = "Count";
|
||||
this.Count.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
|
||||
this.Count.Width = 50;
|
||||
//
|
||||
// dvc_remark
|
||||
//
|
||||
this.dvc_remark.HeaderText = "비고";
|
||||
this.dvc_remark.Name = "dvc_remark";
|
||||
this.dvc_remark.Width = 110;
|
||||
//
|
||||
// dvc_resulthtml
|
||||
//
|
||||
this.dvc_resulthtml.HeaderText = "결과";
|
||||
this.dvc_resulthtml.Name = "dvc_resulthtml";
|
||||
//
|
||||
// nudAddDelay
|
||||
//
|
||||
this.nudAddDelay.Location = new System.Drawing.Point(618, 79);
|
||||
this.nudAddDelay.Name = "nudAddDelay";
|
||||
this.nudAddDelay.Size = new System.Drawing.Size(56, 21);
|
||||
this.nudAddDelay.TabIndex = 9;
|
||||
this.nudAddDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(559, 83);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(53, 12);
|
||||
this.label1.TabIndex = 10;
|
||||
this.label1.Text = "추가지연";
|
||||
//
|
||||
// Check_copyWD
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(637, 738);
|
||||
this.ClientSize = new System.Drawing.Size(719, 738);
|
||||
this.Controls.Add(this.panel3);
|
||||
this.Name = "Check_copyWD";
|
||||
this.Text = "복본조사(New)";
|
||||
@@ -494,6 +551,7 @@
|
||||
this.panel2.ResumeLayout(false);
|
||||
this.panel2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dv1)).EndInit();
|
||||
this.contextMenuStrip1.ResumeLayout(false);
|
||||
this.panel3.ResumeLayout(false);
|
||||
this.panel6.ResumeLayout(false);
|
||||
this.panel6.PerformLayout();
|
||||
@@ -501,6 +559,7 @@
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.panel4.ResumeLayout(false);
|
||||
this.panel4.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudAddDelay)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@@ -536,13 +595,19 @@
|
||||
private System.Windows.Forms.RadioButton radTargetErr;
|
||||
private System.Windows.Forms.RadioButton radTargetEmpty;
|
||||
private System.Windows.Forms.RadioButton radTargetErrEmpty;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn book_name;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn book_comp;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn Count;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn dvc_remark;
|
||||
public System.Windows.Forms.CheckBox chkRetryErrData;
|
||||
public System.Windows.Forms.GroupBox groupBox1;
|
||||
public System.Windows.Forms.CheckBox chkShowBrowser;
|
||||
private System.Windows.Forms.ToolStripStatusLabel lbSite;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem 유니코드문자로붙여넝ㅎ기ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem 일반문자로붙여넣기ToolStripMenuItem;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn book_name;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn book_comp;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn Count;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn dvc_remark;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn dvc_resulthtml;
|
||||
private System.Windows.Forms.NumericUpDown nudAddDelay;
|
||||
private System.Windows.Forms.Label label1;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using UniMarc.SearchModel;
|
||||
using System.Linq;
|
||||
using UniMarc;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
@@ -39,6 +40,9 @@ namespace WindowsFormsApp1.Mac
|
||||
main = _main;
|
||||
db.DBcon();
|
||||
|
||||
// 도서관별 지연시간 설정 초기화
|
||||
_delaySettings = new Helper_LibraryDelaySettings();
|
||||
|
||||
var idx = 1;
|
||||
//도서검색(크롤링)
|
||||
_searchService = new BookSearchService();
|
||||
@@ -450,6 +454,7 @@ namespace WindowsFormsApp1.Mac
|
||||
|
||||
private readonly BookSearchService _searchService;
|
||||
private bool _isSearching = false;
|
||||
private readonly Helper_LibraryDelaySettings _delaySettings;
|
||||
|
||||
private async void InitializeChromeDriver()
|
||||
{
|
||||
@@ -612,7 +617,10 @@ namespace WindowsFormsApp1.Mac
|
||||
int cnt_ok = 0;
|
||||
int cnt_ng = 0;
|
||||
int cnt_er = 0;
|
||||
int addDelay = (int)nudAddDelay.Value * 1000; //추가 지연시간 : 1개의 레코드 처리 후 추가 지연한다.
|
||||
|
||||
// 현재 지연시간을 도서관별로 저장
|
||||
SaveLibraryDelaySettings(searcher.SiteName, (int)nudAddDelay.Value);
|
||||
|
||||
RetrySearch:
|
||||
foreach (DataGridViewRow drow in this.dv1.Rows)
|
||||
@@ -620,6 +628,10 @@ namespace WindowsFormsApp1.Mac
|
||||
if (this._isSearching == false)
|
||||
{
|
||||
drow.Cells["dvc_remark"].Value = "Cancel";
|
||||
if (dv1.Columns.Contains("dvc_resulthtml"))
|
||||
{
|
||||
drow.Cells["dvc_resulthtml"].Value = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -630,6 +642,10 @@ namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
cnt_skip += 1;
|
||||
drow.Cells["dvc_remark"].Value = "No Title";
|
||||
if (dv1.Columns.Contains("dvc_resulthtml"))
|
||||
{
|
||||
drow.Cells["dvc_resulthtml"].Value = "";
|
||||
}
|
||||
drow.DefaultCellStyle.BackColor = Color.HotPink;
|
||||
drow.DefaultCellStyle.ForeColor = Color.Blue;
|
||||
continue;
|
||||
@@ -660,6 +676,13 @@ namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
drow.Cells["dvc_remark"].Value = rlt.ErrorMessage;
|
||||
drow.Cells["Count"].Value = $"{rlt.BookCount}";
|
||||
|
||||
// ResultHtml을 dvc_resulthtml 컬럼에 저장
|
||||
if (dv1.Columns.Contains("dvc_resulthtml"))
|
||||
{
|
||||
drow.Cells["dvc_resulthtml"].Value = rlt.Resulthtml ?? "";
|
||||
}
|
||||
|
||||
if (rlt.BookCount == 0)
|
||||
{
|
||||
cnt_ng += 1;
|
||||
@@ -677,9 +700,18 @@ namespace WindowsFormsApp1.Mac
|
||||
{
|
||||
cnt_er += 1;
|
||||
drow.Cells["dvc_remark"].Value = $"Error|{rlt.ErrorMessage}";
|
||||
|
||||
// 오류시에도 ResultHtml이 있으면 저장 (디버깅용)
|
||||
if (dv1.Columns.Contains("dvc_resulthtml"))
|
||||
{
|
||||
drow.Cells["dvc_resulthtml"].Value = rlt.Resulthtml ?? "";
|
||||
}
|
||||
|
||||
drow.DefaultCellStyle.BackColor = Color.HotPink;
|
||||
drow.DefaultCellStyle.ForeColor = Color.Blue;
|
||||
}
|
||||
if(addDelay > 0)
|
||||
await Task.Delay(addDelay);
|
||||
}
|
||||
|
||||
if (_isSearching == true && retry == false && chkRetryErrData.Checked)
|
||||
@@ -861,6 +893,12 @@ namespace WindowsFormsApp1.Mac
|
||||
dv1.Rows[a].DefaultCellStyle.BackColor = Color.White;
|
||||
dv1.Rows[a].Cells["Count"].Value = "";
|
||||
dv1.Rows[a].Cells["dvc_remark"].Value = "";
|
||||
|
||||
// dvc_resulthtml 컬럼도 초기화
|
||||
if (dv1.Columns.Contains("dvc_resulthtml"))
|
||||
{
|
||||
dv1.Rows[a].Cells["dvc_resulthtml"].Value = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,6 +950,67 @@ namespace WindowsFormsApp1.Mac
|
||||
}
|
||||
chkShowBrowser.Enabled = !searcher.HttpApiMode;
|
||||
this.lbSite.Text = $"[{searcher.AreaCode}] {searcher.SiteUrl}";
|
||||
|
||||
// 저장된 지연시간 불러오기
|
||||
LoadLibraryDelaySettings(searcher.SiteName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 선택된 도서관의 저장된 지연시간을 불러와서 UI에 설정
|
||||
/// </summary>
|
||||
/// <param name="libraryName">도서관 이름</param>
|
||||
private void LoadLibraryDelaySettings(string libraryName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var savedDelay = _delaySettings.GetDelay(libraryName);
|
||||
if (savedDelay > 0)
|
||||
{
|
||||
nudAddDelay.Value = savedDelay;
|
||||
Console.WriteLine($"도서관 지연시간 불러옴: {libraryName} = {savedDelay}초");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 저장된 설정이 없으면 기본값 유지
|
||||
Console.WriteLine($"도서관 지연시간 설정 없음, 기본값 사용: {libraryName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 지연시간 불러오기 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 검색 시작시 현재 지연시간을 저장
|
||||
/// </summary>
|
||||
/// <param name="libraryName">도서관 이름</param>
|
||||
/// <param name="delaySeconds">지연시간(초)</param>
|
||||
private void SaveLibraryDelaySettings(string libraryName, int delaySeconds)
|
||||
{
|
||||
try
|
||||
{
|
||||
_delaySettings.SetDelay(libraryName, delaySeconds);
|
||||
Console.WriteLine($"도서관 지연시간 저장됨: {libraryName} = {delaySeconds}초");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"도서관 지연시간 저장 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void 유니코드문자로붙여넝ㅎ기ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Skill_Grid sg = new Skill_Grid();
|
||||
var newkey = new KeyEventArgs(Keys.Control | Keys.V | Keys.Alt );
|
||||
sg.Excel_to_DataGridView(this.dv1, newkey);
|
||||
}
|
||||
|
||||
private void 일반문자로붙여넣기ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Skill_Grid sg = new Skill_Grid();
|
||||
var newkey = new KeyEventArgs(Keys.Control | Keys.V);
|
||||
sg.Excel_to_DataGridView(this.dv1, newkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +129,11 @@
|
||||
<metadata name="dvc_remark.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
<metadata name="dvc_resulthtml.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>134, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
|
||||
Reference in New Issue
Block a user