블로그 이미지
fiadot_old

칼퇴근을 위한 게임 서버 개발 방법론에 대한 심도있는 고찰 및 성찰을 위한 블로그!

Rss feed Tistory
마이크로소프트웨어 2008. 6. 21. 17:11

HtmlView를 이용한 Web Form 입력 자동화

[마소 플러스] 2008년 5월 원고(분량 수정 전)

HtmlView를 이용한

Web Form 입력 자동화

-------------------------------------

이근호 fiadot@gmail.com, http://www.fiadot.com |
현재 인제대학교 컴퓨터공학과에 재학 중이며, 온라인게임 개발업체인 NeonSoft R&D팀에서 서버 엔진을 개발하고 있다. 다양한 언어 중에서도 특히 C++에 많은 관심을 가지고 있고, 기회가 된다면 많은 서버개발자들에게 도움이 될 게임서버 관련 서적을 집필하고픈 꿈을 가지고 있다.

--------------------------------

DB에 접근할 수 있는 권한이 없고 웹페이지를 통해서만 대량의 데이터를 입력해야 한다면 어떻게 할 것 인가? 순수하게 소켓으로 HTTP프로토콜에 맞춰 전송하는 방법도 있겠지만 부수적인 요소에 많은 시간을 할애해야 할 것이다. Internet Explorer를 직, 간접적으로 이용한다면 문제에 집중할 수 있을 것이다. IWebBrowser와 IHtmlDocument 인터페이스를 통해 접근할 수 있는데 이를 이용해서 웹 브라우저의 기능과 파싱, 폼의 값 채우기 등의 방법들에 대해서 알아보자.

CHtmlView의 기본 사용법

IWebBrowser 인터페이스 Wrapper에 해당하는 CHtmlView는 doc/view구조에 맞춰서 웹브라우저의 기능을 제공하는 MFC의 클래스이다.CHtmlView를 통해 렌더링이나 컨트롤 제어 할 수 있다. 이제 기본적인 기능을 살펴보자.

<리스트1> 사이트 이동

Navigate2(_T("http://www.imaso.co.kr"), NULL, NULL);

해당 URL의 처리 완료시에 OnDocumentComplete() 이벤트가 발생하게 된다.

이외에도 Refresh(), GoBack(), GoForward(), Stop() 등의 브라우징에 필요한 여러 가지 기능들을 제공하고 있다.

<리스트2> 쿠키 얻기

void GetCookie()

{

CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2>

spHtmlDoc2(GetHtmlDocument());

CComBSTR bstrCookie;

spHtmlDoc2->get_cookie(&bstrCookie.m_str);

// To do something...

}

IHtmlDocument와 그와 관련된 인터페이스들을 통해 문서를 제어할 수 있는데, 별도의 구문분석을 위한 파서를 만들 필요 없이, 관련된 인터페이스를 통해 옵션들 하나하나까지 접근이 가능하다. CHtmlView에는 GetHtmlDocument()라는 메소드를 제공하고 있으므로 이를 통해 인터페이스 인스턴스를 얻어와 처리를 하게 된다. <리스트2>에서 IHtmlDocument2의 인터페이스를 통해 쿠키를 얻어오는 코드를 볼 수 있다. 쿠키의 형식에 따라 key=value 쌍으로 구성되어 저장된다.

<리스트3> 인증을 위한 부분

CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2>

spHtmlDoc2(GetHtmlDocument());

spHtmlDoc2->put_cookie(bstrPutCookie); // 쿠키넣기

CString bstrReferer("Referer: http://www.imaso.co.kr"); // Referer 넣기

Navigate2(strURL, NULL, NULL, bstrReferer, NULL);

인증이 필요한 웹페이지일 경우 대부분 쿠키와 Referer를 검사하기 때문에 추가적으로 웹페이지 요청 시 들어가야 하는 정보가 된다.

구문분석과 폼 채우기 및 제출

우리가 하고자 하는 바는 폼(form)에 존재하는 TextField, TextArea, FilePath, CheckBox, SelectBox등에 접근해서 내용을 채워서 전송하는 것이다. 이를 위해서는 IHtmlDocument의 전체적인 구조를 알아보자. 하나의 HTML문서에 대해 계층적으로 접근하게 되는데 문서를 IHtmlDocument로, 각각의 태그들의 집합을 IHtmlElementCollection으로 접근이 가능하다. 우리는 폼의 요소들 각각에 접근하기 때문에 IHtmlElementCollection을 통해 IHtmlFormElement를 얻는다. 다양한 타입이 존재하지만 대표적인 TextField에 대한 접근 방법을 알아보자.

<리스트4> IHtmlDocument를 이용해서 element collection 얻어오기

CComQIPtr<IHTMLDocument2,&IID_IHTMLDocument2>

spHtmlDoc2(GetHtmlDocument());

CComPtr<IHTMLElementCollection>spEleColl;

HRESULT hr = spHtmlDoc2->get_forms(&spEleColl);

long lFormLen = 0;

hr = spEleColl->get_length(&lFormLen);

문서를 얻어와 요소(element)를 얻어, 개수를 알아내고 폼 요소를 찾기 위한 준비단계이다. 우리가 하고자 하는바는 필드에 값을 집어넣는 것이기 때문에, get_forms 메소드를 통해 폼에 해당하는 요소만 받아온다.

<리스트5> Form Element

for(int i = 0; i < lFormLen; i++)

{

CComPtr<IDispatch> pDispFormEle;

hr = spEleColl->item(CComVariant(i), CComVariant(i), &pDispFormEle);

if(FAILED(hr)) continue;

CComQIPtr<IHTMLFormElement, &IID_IHTMLFormElement>

spFormEle(pDispFormEle);

long lElementLen = 0;

spFormEle->get_length(&lElementLen);

for( int j = 0; j < lElementLen ; j++ )

{

CComPtr<IDispatch> pDispItem

hr = spFormEle->item(CComVariant(j), CComVariant(j), &pDispItem);

if(FAILED(hr)) continue;

// 필드에 대한 처리를 할 위치

}

}

item메소드는 집합(collection)에 포함되는 객체나 다른 집합을 반환해주는 역할을 한다.

이제 각각의 폼의 요소에 대한 접근이 준비되었다.

<리스트6> TextField에 값 넣기

// CComBSTR bstrFieldName, bstrFieldValue; // 찾을 필드 이름, 찾은 필드에 들어갈 값

CComQIPtr<IHTMLInputTextElement, &IID_IHTMLInputTextElement>

spInputTextElement(pDispItem);

if( NULL != spInputTextElement.p )

{

CComBSTR bstrTextFieldName;

spInputTextElement->get_name(&bstrTextFieldName);

if ( bstrTextFieldName == bstrFieldName )

spInputTextElement->put_value(bstrFieldValue);

}

TextField에 해당하는 인터페이스는 IHTMLInputTextElement이다. get_name()을 통해 필드의 이름을 얻어서, put_value()를 이용하여 값을 변경한다.

<리스트7> 제출

spFormEle->submit();

최종적으로 폼의 각각의 요소에 대해 값을 채우고 IHTMLFormElement의 submit()을 호출하면 해당 폼이 웹서버로 전송 된다. 우리가 일반적으로 봐왔던 회원가입 페이지에 자신의 정보를 넣고 제출하기 버튼을 눌렀을 때와 동일한 효과가 나타나는 것이다.

TextField이외의 다른 폼 요소에 따라서 약간씩 다른 방법들이 사용되지만, 큰 흐름은 파악할 수 있으리라고 본다.



* 지면 관계상 생략된 내용을 포함한 글입니다. *


,
TOTAL TODAY