본문 바로가기
programming/UWP

uwp html 파싱 웹데이터 추출 하는 방법

by 개코 - 개발과 코딩 2021. 4. 20.

uwp는 C#과 거의 비슷하다. WPF와 C#를 합한 느낌이랄까. 그렇기에 html 문서를 파싱하여 데이터를 추출하는 것 또한 비슷하다. html 문서를 파싱한다는 것은 곧 자신이 원하는 데이터를 추출하고 가공한다는 것을 의미한다. 물론, 이 작업은 엑셀의 VBA에서도 가능하다.

 

uwp html 웹데이터 가져오기

웹데이터를 가져온다는 것은 웹 화면의 데이터를 크롤링하거나 스크래핑 하여 데이터를 가져온다는 것이다.

이 데이터를 수집하고 가공하여 통계 보고서를 내는 것은 사용하는 사람들의 목적에 따라 여러가지 목적으로 사용될 수 있다.

uwp에서 웹데이터를 얻는 방법은 이전에 작성한 글을 참고하자.

 

>>> uwp 웹 데이터 스크래핑 크롤링 하기 <<<

 

uwp에서 웹 데이터 추출하기

웹 데이터를 추출하는 작업은 파싱이라 하며 html 문서를 파싱하는 것은 그리 어렵지 않다.

하지만, 웹문서가 암호화가 되어 있다면 불가능하거나 시간이 많이 걸릴 수 있다.

uwp에서 데이터를 추출하려면 먼저 html 문자열이 있어야 한다.

이것은 위에 언급한 포스팅을 참고하자.

 

파싱작업을 하기전에 비주얼스튜디오의 NuGet 패키를 설치할 필요가 있다.

NuGet 에서 HtmlAgilityPack 을 검색하여 설치하도록 하자.

 

디자인을 담당하는 xaml 에는 TextBox를 하나 두었다.

파싱되는 데이터가 올바르게 넘어오는지 확인하기 위함이기도 하다.

비하인드 코드에는 메서드를 3개 생성하였다.

 

  • 화면디자인 XAML
    TextBox 를 추가하여 파싱한 웹데이터를 출력한다.
  • HtmlAgilityPack
    Html 를 파싱하기 위한 NuGet 패키지
  • 비하인드 코드 메서드
    GetHtmlParsingData() : 웹데이터를 얻고 html를 파싱한다.
    GetWebData() : 웹데이터를 얻는다.
    ParserHtml() : HTML 정보를 파싱하고 추출한다.

MainPag() 생성자는 uwp 프로그램이 실행되면 가장 먼저 시작한다.

GetHtmlParsingData(), GetWebData() 는 async, await 키워드를 사용하여 비동기로 실행하도록 하였다.

이것은 해당 메서드의 작업이 완전히 완료될 때까지 기다리고 다른 로직에 방해를 주지 않도록 하기 위함이다.

스레드와 연관이 있다.

이렇게 하면 시간이 걸리는 여러 작업을 동시에 처리할 수 있도록 한다.

ParserHtml() 은 html 문자열에서 특정 데이터를 추출하는 작업을 하도록 하였다.

 

추출을 위해 html 문서의 XPATH 를 사용하여 웹데이터에 접근할 수 있도록 하였다.

추출하고자 하는 것이 동일한 형태의 여러 문자열이기 때문에 foreach 로 반복을 해 주도록 한다.

 

완성된 코드와 실행 화면

코드를 보면 알 수 있다.

데이터의 결과는 민감할 것 같아 삭제하였다.

정상적으로 처리된 것을 확인할 수 있다.

 

코드가 정상이라 하더라도 만약 타겟 웹페이지가 리뉴얼되거나 수정이 되는 경우는 해당 코드의 XPATH 부분을 수정해 주어야 한다.

 

현재 많은 업체에서는 이런 크롤링을 막고자 웹페이지를 암호화하거나 데이터의 접근을 막기 위한 별도의 조치를 취한느 곳들이 늘어나고 있기도 하다.

<!-- XAML -->

<StackPanel>
	<TextBox x:Name="tb"
			 TextWrapping="Wrap"
			 MaxHeight="150" Width="300" Header="컨텐츠내용"
			 ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</StackPanel>
/** UWP 비하인드 코드 */

public MainPage()
{
	this.InitializeComponent();

	GetHtmlParsingData();
}

private async void GetHtmlParsingData()
{
	ParserHtml(await GetWebData());
}

private void ParserHtml(String p_HtmlString)
{
	if (String.IsNullOrEmpty(p_HtmlString))
	{
		return;
	}

	HtmlDocument doc = new HtmlDocument();
	doc.LoadHtml(p_HtmlString);

	var vSelectNodes = doc.DocumentNode.SelectNodes("//div[@class='search_keyword']/dl/dd/a");

	if (vSelectNodes == null)
	{
		return;
	}

	StringBuilder vStringBuilder = new StringBuilder();
	foreach (HtmlNode node in vSelectNodes)
	{
		vStringBuilder.Append(node.InnerText.TrimStart().TrimEnd() + ", ");
	}

	this.tb.Text = vStringBuilder.ToString();
	
}

private async Task<string> GetWebData()
{
	String vContent = String.Empty;
	var webView = new WebView();

	using (SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 1))
	{
		async void handler(WebView sender, WebViewNavigationCompletedEventArgs args)
		{
			vContent = await webView.InvokeScriptAsync("eval", new string[] { "document.body.outerHTML;" });
			webView.NavigationCompleted -= handler;
			semaphoreSlim.Release();
		}

		webView.NavigationCompleted += handler;
		webView.Navigate(new Uri("웹데이터를 가져올 URL주소"));
		await semaphoreSlim.WaitAsync().ConfigureAwait(false);

	}

	return vContent;
}

반응형

댓글