11. 2 웹 검색 엔진 관리자 응용 만들기
이번에는 관리자 응용을 만듭시다. 관리자 응용은 Windows Form 형태의 응용 프로그램으로 WSEManager 이름으로 만듭시다.
관리자 응용에서 제공할 기능은 다음과 같습니다.
검색 서비스가 잘 동작하는지 확인할 수 있다.
웹 로봇을 설정할 수 있다.
수집 결과에 관한 상태 모니터링을 할 수 있다.
사이트로 탐색할 수 있다.
관리자 응용은 프로핑 단계에서 작성한 WSEManager 응용 프로그램 프로토 타이핑과 기본적인 구조는 유사합니다. 여기에서는 프로토 타이핑에서 구현하지 않았던 세부 기능을 구현할 것입니다.
11.2.1 폼 디자인
관리자 응용은 MainForm과 EHBrowser를 만들어서 사용할게요.
MainForm은 관리자가 검색 서비스 동작 확인 및 웹 로봇 설정, 현재 수집 결과 모니터링을 수행하는 폼이고 수집 결과 페이지 주소로 바로가기를 했을 때 EHBrowser를 통해 사이트 정보를 보여주게 합시다.
[그림 11.5] MainForm의 컨트롤 배치
번호 |
컨트롤 이름 |
컨트롤 유형 |
설명 |
1 |
btn_start |
Button |
웹 로봇 수집 가동 |
2 |
btn_stop |
Button |
웹 로봇 수집 멈춤 |
3 |
tc_main |
TabControl |
탭 컨트롤 |
4 |
tp_search |
TabPage |
검색 페이지 |
5 |
tp_set_robot |
TabPage |
웹 로봇 설정 페이지 |
6 |
tp_monitoring |
TabPage |
모니터링 페이지 |
7 |
lb_query |
Label |
단순 정보 표시 |
8 |
tbox_query |
TextBox |
검색 질의 입력 창 |
9 |
btn_search |
Button |
검색 요청 버튼 |
10 |
ruc_result |
RUListControl |
검색 결과 컬렉션 |
[표 11.4] WSE Manager 메인 폼과 검색 탭 페이지의 자식 컨트롤
[그림 11.6] MainForm의 웹 로봇 설정 탭의 컨트롤 배치
번호 |
컨트롤 이름 |
컨트롤 유형 |
설명 |
1 |
lb_period |
Label |
단순 정보 표시 |
2 |
nud_period |
NumericUpDown |
수집 주기 선택 |
3 |
btn_set_period |
Button |
수집 주기 설정 |
4 |
lb_seed_site |
Label |
단순 정보 표시 |
5 |
tbox_seed_site |
TextBox |
Seed 사이트 입력 창 |
6 |
btn_add_seed |
Button |
Seed 사이트 추가 |
7 |
btn_refresh_candi |
Button |
수집 대상 목록 고침 |
8 |
btn_refresh_purl |
Button |
수집 완료 목록 고침 |
9 |
lv_candidate |
ListView |
수집 대상 리스트 뷰 |
10 |
ch_addr |
ColumnHeader |
컬럼 헤더 |
11 |
ch_depth |
ColumnHeader |
컬럼 헤더 |
12 |
lv_posted |
ListView |
수집 완료 리스트 뷰 |
13 |
ch_posted_addr |
ColumnHeader |
컬럼 헤더 |
14 |
ch_origin_addr |
ColumnHeader |
컬럼 헤더 |
15 |
ch_posted_depth |
ColumnHeader |
컬럼 헤더 |
[표 11.5] WSE Manager 설정 탭 페이지의 자식 컨트롤
[그림 11.7] MainForm의 모니터링 탭의 컨트롤 배치
번호 |
컨트롤 이름 |
컨트롤 유형 |
설명 |
1 |
lb_posted_page |
Label |
단순 정보 표시 |
2 |
lbox_posted_page |
ListBox |
수집 완료 목록 |
3 |
btn_refresh_moph |
Button |
형태소 목록 고침 |
4 |
lbox_morpheme |
ListBox |
형태소 목록 |
5 |
lb_page_info |
Label |
단순 정보 표시 |
6 |
ruc_selected |
RankedUrlControl |
사이트 상세 정보 |
7 |
lb_morpheme_info |
Label |
단순 정보 표시 |
8 |
lview_morpheme |
ListView |
형태소 상세 정보 |
9 |
ch_posted_url |
ColumnHeader |
컴럼 헤더 |
10 |
ch_refcnt |
ColumnHeader |
컬럼 헤더 |
11 |
ch_totalcnt |
ColumnHeader |
컬럼 헤더 |
[표 11.6] WSE Manager 모니터링 탭 페이지의 자식 컨트롤
Windows Form 추가 메뉴를 통해 EHBrowser 폼을 추가합시다.
EHBrowser 폼에는 자식 컨트롤로 페이지 제목과 주소 및 페이지 내용을 보여주는 자식 컨트롤을 배치합니다.
[그림 11.8] EHBrowser폼 자식 컨트롤 배치
번호 |
컨트롤 이름 |
컨트롤 유형 |
설명 |
1 |
lb_title_info |
Label |
정보 표시 |
2 |
lb_title |
Label |
타이틀 |
3 |
lb_addr_info |
Label |
정보 표시 |
4 |
lb_addr |
Label |
사이트 주소 |
5 |
wb |
WebBrowser |
페이지 정보 표시 |
[표 11.7] RankedUrlControl의 자식 컨트롤
11.2.2 구현
WSE Manager 응용은 검색 서비스와 웹 로봇 서비스를 이용합니다. 두 가지 서비스 모두 .NET 리모팅 서비스를 사용하므로 System.Runtime.Remoting 어셈블리를 참조 추가합니다.
그리고 검색 서비스에서 제공하는 MashalByReference 개체를 참조하기 위해 서버와 클라이언트 모두 참조해야 하는 GenericSearchLib 어셈블리를 추가합니다.
웹 로봇 서비스에서 제공하는 개체를 참조하기 위해 GenericWebRobotLib 어셈블리를 참조 추가합니다.
그리고 RankedUrlControlLib 어셈블리와 DBMForAllLib, DBMForSearchLib, WSECore 어셈블리도 참조 추가합니다.
MainForm의 Load 이벤트 핸들러를 추가하세요.
private void MainForm_Load(object sender, EventArgs e)
이벤트 핸들러에서는 .NET 리모팅 서비스를 사용하기 위해 HttpChannel 개체를 생성하여 등록합니다.
HttpChannel hc = new HttpChannel();
ChannelServices.RegisterChannel(hc, false);
웹 로봇의 활성화 상태에 따라 웹 로봇 수집 시작과 멈춤 버튼의 활성화 속성을 설정합니다. 웹 로봇의 MashalByReference 개체를 참조하기 위한 속성은 별도로 만들어서 사용합시다.
bool enable = WebRobot.GetEnabled();
SetStartStopButton(enable);
웹 로봇 서비스의 GenericWebRobot 개체와 검색 서비스의 GenericSearch 개체를 참조하기 위한 속성을 제공합니다.
GenericWebRobot WebRobot
{
get
{
GenericWebRobot robot = Activator.GetObject(
typeof(GenericWebRobot),
"http://[웹 로봇 서비스 서버의 IP 주소]:10400/WebRobotSVC")
as GenericWebRobot;
return robot;
}
}
GenericSearch Searcher
{
get
{
GenericSearch searcher = Activator.GetObject(
typeof(GenericSearch),
"http://[검색 서비스 서버의 IP 주소]:10200/EHSearchSVC") as GenericSearch;
return searcher;
}
}
웹 로봇 수집 멈춤과 시작 버튼 활성화를 설정하는 메서드를 작성하세요.
private void SetStartStopButton(bool enable)
{
btn_start.Enabled = !enable;
btn_stop.Enabled = enable;
}
검색 버튼 클릭 이벤트 핸들러를 추가하세요.
private void btn_search_Click(object sender, EventArgs e)
검색 결과를 보여주는 ruc_result의 Clear 메서드를 호출하여 결과를 초기화합니다.
ruc_result.Clear();
쿼리 입력 창의 Text 속성을 입력 인자로 Searcher의 Request 메서드를 호출하여 결과 목록을 얻어와서 ruc_result에 추가합니다.
string query = tbox_query.Text;
ArrayList list = Searcher.Request(query);
foreach (RankedUrl rurl in list)
{
ruc_result.AddRankedUrl(rurl);
}
검색 결과를 보여주는 ruc_reuslt 컨트롤의 RUClick 이벤트 핸들러를 추가합시다.
private void ruc_result_RUClick(object sender, RUrlClickEventArgs e)
이벤트 핸들러에서는 이벤트 처리 인자의 RankedUrl 개체를 입력 인자로 EHBrowser 폼을 생성하여 활성화합니다. EHBrowser 부분은 EH 응용 만들기에서 작성한 것과 일치합니다.
if (e.RUrl != null)
{
RankedUrl rurl = e.RUrl;
EHBrowser eb = new EHBrowser(rurl);
eb.Show();
}
웹 로봇 수집 시작 버튼과 멈춤 버튼 클릭 이벤트 핸들러를 추가하여 웹 로봇의 수집 여부를 설정합니다.
private void btn_start_Click(object sender, EventArgs e)
{
WebRobot.SetEnabled(true);
SetStartStopButton(true);
}
private void btn_stop_Click(object sender, EventArgs e)
{
WebRobot.SetEnabled(false);
SetStartStopButton(false);
}
수집 주기 설정 버튼 클릭 이벤트 핸들러와 Seed 사이트 추가 버튼 클릭 이벤트 핸들러를 추가하여 웹 로봇의 설정 주기 및 Seed 사이트 추가 메서드를 호출합니다.
private void btn_set_period_Click(object sender, EventArgs e)
{
WebRobot.SetPeriod((int)nud_period.Value);
}
private void btn_add_seed_Click(object sender, EventArgs e)
{
WebRobot.SetSeedSite(tbox_seed_site.Text);
}
수집 대상 목록 새로고침 버튼 클릭 이벤트 핸들러를 추가하세요.
private void btn_refresh_candi_Click(object sender, EventArgs e)
수집 대상 목록 ListView의 항목을 지워줍니다.
lv_candidate.Items.Clear();
EHDbmForAll 정적 클래스를 이용하여 수집 대상 목록을 얻어옵니다.
List<Candidate> list = EHDbmForAll.GetCandidates();
얻어온 목록으로 ListViewItem 개체를 생성하여 수집 대상 목록 ListView에 추가합니다.
foreach (Candidate candi in list)
{
ListViewItem lvi = new ListViewItem(
new string[] { candi.Url, candi.Depth.ToString() });
lv_candidate.Items.Add(lvi);
}
수집 완료 사이트 목록 새로고침 버튼 클릭 이벤트 핸들러를 추가하세요.
private void btn_refresh_purl_Click(object sender, EventArgs e)
수집 완료 사이트 목록을 보여주는 ListView의 항목을 지워줍니다.
lv_posted.Items.Clear();
EHDbmForAll 정적 클래스를 이용하여 수집 완료 사이트 목록을 얻어옵니다.
List<PostedUrl> list = EHDbmForAll.GetPostedUrls();
수집 완료 사이트 목록의 각 PostedUrl 개체로 ListViewItem 개체를 생성하여 수집 완료 사이트 목록에 추가합니다.
foreach (PostedUrl purl in list)
{
ListViewItem lvi = new ListViewItem(
new string[] { purl.Url, purl.OriginUrl, purl.Depth.ToString() });
lv_posted.Items.Add(lvi);
}
모니터링 탭 페이지의 수집 목록 새로고침 버튼의 클릭 이벤트 핸들러를 추가합니다.
private void bnt_refresh_purl2_Click(object sender, EventArgs e)
수집 목록을 보여주는 ListBox 컨트롤의 항목을 지워줍니다.
lbox_posted_page.Items.Clear();
수집 목록을 얻어오는 부분은 DbmForAllLib를 이용해야 할 것 같은데 아직 제공하지 않는 기능입니다. EHDbmForAll 정적 클래스에 GetPostedUrls 메서드 이름으로 수집한 페이지 목록을 제공하는 메서드를 추가하여 이를 이용합시다.
List<PostedUrl> list = EHDbmForAll.GetPostedUrls();
얻어온 수집 목록을 리스트 박스 목록에 추가합니다.
foreach (PostedUrl purl in list)
{
lbox_posted_page.Items.Add(purl);
}
잠시 DbmForAllLib로 가서 EHDbmForAll 클래스에 GetPostedUrls 메서드를 작성합시다.
public static List<PostedUrl> GetPostedUrls()
결과 목록을 보관할 컬렉션을 생성합니다.
List<PostedUrl> list = new List<PostedUrl>();
PostedUrlTable의 모든 항목을 얻어올 SqlCommand 개체를 만듭니다.
SqlCommand scom = MakeSPCommand("Select * From PostedUrlTable"
, CommandType.Text);
SqlCommand 개체의 연결을 개방한 후 명령을 실행합니다.
scom.Connection.Open();
SqlDataReader sdr = scom.ExecuteReader();
명령으로 얻어온 SqlDataReader 개체의 결과로 PostedUrl 개체를 만들어서 결과를 보관할 컬렉션에 추가하고 SqlDataReader 개체를 닫습니다.
while (sdr.Read())
{
PostedUrl purl = new PostedUrl();
purl.Url = sdr["Url"].ToString();
purl.OriginUrl = sdr["OriginUrl"].ToString();
purl.Depth = (int)sdr["Depth"];
purl.Title = sdr["Title"].ToString();
purl.PostedTime = (DateTime)sdr["PostedTime"];
purl.Content = sdr["PostedContent"].ToString();
list.Add(purl);
}
sdr.Close();
SqlCommand 개체의 연결을 닫고 결과 목록을 반환합니다.
scom.Connection.Close();
return list;
▷ EHDbmForAll.cs에 추가한 내용(DbmForAllLib)
/// <summary> /// 수집한 사이트 목록 가져오기 메서드 /// </summary> /// <returns>수집한 사이트 목록</returns> public static List<PostedUrl> GetPostedUrls() { List<PostedUrl> list = new List<PostedUrl>(); SqlCommand scom = MakeSPCommand("Select * From PostedUrlTable" , CommandType.Text);
scom.Connection.Open(); SqlDataReader sdr = scom.ExecuteReader(); while (sdr.Read()) { PostedUrl purl = new PostedUrl(); purl.Url = sdr["Url"].ToString(); purl.OriginUrl = sdr["OriginUrl"].ToString(); purl.Depth = (int)sdr["Depth"]; purl.Title = sdr["Title"].ToString(); purl.PostedTime = (DateTime)sdr["PostedTime"]; purl.Content = sdr["PostedContent"].ToString(); list.Add(purl); } sdr.Close(); scom.Connection.Close(); return list; }
|
수집 목록 선택 변경 이벤트 핸들러를 추가하세요.
private void lbox_posted_page_SelectedIndexChanged(object sender, EventArgs e)
선택 항목이 없으면 핸들러를 종료합니다.
if (lbox_posted_page.SelectedIndex == -1)
{
return;
}
선택 항목을 PostedUrl 개체 형식으로 참조하여 결과를 보여주는 컬렉션에 추가합니다.
PostedUrl purl = lbox_posted_page.SelectedItem as PostedUrl;
ruc_selected.SetRankedUrl(new RankedUrl(purl, 0));
형태소 목록 새로고침 버튼의 클릭 이벤트 핸들러를 추가하세요.
private void btn_refresh_moph_Click(object sender, EventArgs e)
EHDbmForAll 정적 클래스를 이용하여 형태소 목록을 얻어와서 ListBox의 DataSource 속성을 설정합니다.
List<string> list = EHDbmForAll.GetMorphemes();
lbox_morpheme.DataSource = list;
형태소 목록 선택 변경 이벤트 핸들러를 추가하세요.
private void lbox_morpheme_SelectedIndexChanged(object sender, EventArgs e)
형태소 목록을 보여주는 ListView 컨트롤의 항목을 지워줍니다.
lview_morpheme.Items.Clear();
만약 선택 항목이 없으면 이벤트 핸들러를 종료합니다.
if (lbox_morpheme.SelectedIndex == -1)
{
return;
}
선택 항목의 이름을 참조합니다.
string mname = lbox_morpheme.SelectedItem as string;
EHDbmForSearch 정정 클래스를 이용하여 역 파일 목록을 얻어옵니다.
List<InvertedElem> list = EHDbmForSearch.GetInvertedFile(mname);
얻어온 정보의 페이지 주소로 형태소 전체 개수를 얻어와서 ListViewItem 개체를 생성하여 ListView 컨트롤의 목록에 추가합니다.
foreach (InvertedElem ie in list)
{
int tcnt = EHDbmForSearch.GetTotalCountInUrl(ie.Url);
ListViewItem lvi = new ListViewItem(
new string[] { ie.Url,ie.RefCount.ToString(),tcnt.ToString() });
lview_morpheme.Items.Add(lvi);
}
▷ MainForm.cs
using System; using System.Windows.Forms; using GenericWebRobotLib; using GenericSearchLib; using System.Runtime.Remoting.Channels.Http; using System.Runtime.Remoting.Channels; using System.Collections; using WSE_Core; using DBM_ForAll; using System.Collections.Generic; using DBMForSearchLib; using RankedUrlControlLib;
namespace WSEManager { public partial class MainForm : Form { GenericWebRobot WebRobot { get { GenericWebRobot robot = Activator.GetObject( typeof(GenericWebRobot), "http://[웹 수집 로봇 서버의 IP 주소]:10400/WebRobotSVC") as GenericWebRobot; return robot; } }
GenericSearch Searcher { get { GenericSearch searcher = Activator.GetObject( typeof(GenericSearch), "http://[검색 서비스 서버의 IP 주소]:10200/EHSearchSVC") as GenericSearch; return searcher; } }
public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { HttpChannel hc = new HttpChannel(); ChannelServices.RegisterChannel(hc, false); bool enable = WebRobot.GetEnabled(); SetStartStopButton(enable); }
private void SetStartStopButton(bool enable) { btn_start.Enabled = !enable; btn_stop.Enabled = enable; }
private void btn_search_Click(object sender, EventArgs e) { ruc_result.Clear();
string query = tbox_query.Text; ArrayList list = Searcher.Request(query); foreach (RankedUrl rurl in list) { ruc_result.AddRankedUrl(rurl);
} }
private void ruc_result_RUClick(object sender, RUrlClickEventArgs e) { if (e.RUrl != null) { RankedUrl rurl = e.RUrl; EHBrowser eb = new EHBrowser(rurl); eb.Show(); } }
private void btn_start_Click(object sender, EventArgs e) { WebRobot.SetEnabled(true); SetStartStopButton(true); }
private void btn_stop_Click(object sender, EventArgs e) { WebRobot.SetEnabled(false); SetStartStopButton(false); }
private void btn_set_period_Click(object sender, EventArgs e) { WebRobot.SetPeriod((int)nud_period.Value); }
private void btn_add_seed_Click(object sender, EventArgs e) { WebRobot.SetSeedSite(tbox_seed_site.Text); }
private void btn_refresh_candi_Click(object sender, EventArgs e) { lv_candidate.Items.Clear(); List<Candidate> list = EHDbmForAll.GetCandidates();
foreach (Candidate candi in list) { ListViewItem lvi = new ListViewItem( new string[] { candi.Url, candi.Depth.ToString() }); lv_candidate.Items.Add(lvi); } }
private void btn_refresh_purl_Click(object sender, EventArgs e) { lv_posted.Items.Clear(); List<PostedUrl> list = EHDbmForAll.GetPostedUrls(); foreach (PostedUrl purl in list) { ListViewItem lvi = new ListViewItem( new string[] { purl.Url, purl.OriginUrl, purl.Depth.ToString() }); lv_posted.Items.Add(lvi); } }
private void bnt_refresh_purl2_Click(object sender, EventArgs e) { lbox_posted_page.Items.Clear(); List<PostedUrl> list = EHDbmForAll.GetPostedUrls(); foreach (PostedUrl purl in list) { lbox_posted_page.Items.Add(purl); } }
void lbox_posted_page_SelectedIndexChanged(object sender, EventArgs e) { if (lbox_posted_page.SelectedIndex == -1) { return; } PostedUrl purl = lbox_posted_page.SelectedItem as PostedUrl; ruc_selected.SetRankedUrl(new RankedUrl(purl, 0)); } private void btn_refresh_moph_Click(object sender, EventArgs e) { List<string> list = EHDbmForAll.GetMorphemes(); lbox_morpheme.DataSource = list; }
void lbox_morpheme_SelectedIndexChanged(object sender, EventArgs e) { lview_morpheme.Items.Clear(); if (lbox_morpheme.SelectedIndex == -1) { return; } string mname = lbox_morpheme.SelectedItem as string; List<InvertedElem> list = EHDbmForSearch.GetInvertedFile(mname); foreach (InvertedElem ie in list) { int tcnt = EHDbmForSearch.GetTotalCountInUrl(ie.Url); ListViewItem lvi = new ListViewItem( new string[] { ie.Url,ie.RefCount.ToString(),tcnt.ToString() }); lview_morpheme.Items.Add(lvi); } } } } |
EHBrowser 컨트롤의 생성자는 순위화 한 페이지 개체를 입력 인자로 받는 것으로 변경하세요.
public EHBrowser(RankedUrl rurl)
생성자 메서드에서는 마법사에 의해 작성한 InitializeComponent 메서드 호출로 초기 자식 컨트롤 배치 등을 마친 후에 입력 인자로 받은 순위화 한 페이지 개체의 속성으로 자식 컨트롤의 Text속성을 설정합니다. 그리고 페이지 주소를 입력 인자로 WebBrowser 컨트롤인 wb의 Navigate 메서드를 호출합니다.
▷ EHBrowser.cs
using System.Windows.Forms; using WSE_Core;
namespace WSEManager { public partial class EHBrowser : Form { public EHBrowser(RankedUrl rurl) { InitializeComponent(); lb_addr.Text = rurl.Url; lb_title.Text = rurl.PUrl.Title; wb.Navigate(rurl.Url); } } } |
이제 WSA Manager 응용을 빌드하여 테스트 해 보세요.
'프로그래밍 기술 > 웹 검색 엔진 만들기' 카테고리의 다른 글
11. 웹 검색 응용 만들기 (0) | 2017.12.07 |
---|---|
10. 검색 서비스 만들기 (0) | 2017.12.07 |
9. 2 랭커 라이브러리 만들기 (0) | 2017.12.07 |
9. 랭커 만들기 (0) | 2017.12.07 |
8. 역 파일 생성기 만들기 (0) | 2017.12.07 |
7. 형태소 분석기 만들기 (0) | 2017.12.07 |
6.4.3 WebRobot 서비스 테스트 클라이언트 만들기 (0) | 2017.12.07 |
6.4.2 WebRobot 서비스 만들기 (0) | 2017.12.07 |
6. 4 웹 로봇 서비스 만들기 (0) | 2017.12.07 |
6. 3 웹 로봇 예광탄 구현 (0) | 2017.12.07 |