1. HttpClient
HttpClient는 HTTP 프로토콜상에서 커뮤니케이션하는 자바 기반 어플리케이션 개발을 쉽게 할 수 있도록 돕는 컴포넌트이다. 만약 웹 브라우저 또는 그에 준하는 어플리케이션을 개발해야 한다면 HttpClient에서 많은 도움을 받을수 있다. 단, HttpClient는 이름에서와 같이 오직 HTTP 클라이언트 사이드를 위한 컴포넌트이기 때문에 서버측 프로세스를 처리하기 위한 코드를 지원하지 않는다.


2. Jericho Parser
Jericho Parser는 HTML태크를 포함하여 server-side 태크(jsp, asp, php 등) 분석이 가능한 자바기반 오픈소스 라이브러이며, Eclipse Public License (EPL) 그리고 GNU Lesser General Public License (LGPL) 라이센스를 따른다. HTML 자체는 견고하지 않기 때문에 때때로 결함을 포함하는(badly formatted) HTML문서를 발견하게 되는데, Jericho Parser는 이러한 결함을 포함하여 HTML문서를 쉽고 빠르게 파싱할수 있도록 해준다. 


3. 다운로드



4. HttpClient와 Jericho Parser를 이용해 HTML 문서 파싱

첫번째로 HttpClient 객체를 생성한다. 아래 예제에서는 HttpClient에 Connection Timout과 socket timeout을 설정하고 있다.
public HttpClient makeHttpClient(int connTimeout, int soTimeout) {
		HttpConnectionManager connMgr = new SimpleHttpConnectionManager();
		HttpConnectionManagerParams httpConnMgrParams = new HttpConnectionManagerParams();
		httpConnMgrParams.setConnectionTimeout(connTimeout);
		httpConnMgrParams.setSoTimeout(soTimeout);
		connMgr.setParams(httpConnMgrParams);
		return new HttpClient(connMgr);
}
위에서 만들어진 HttpClient 객체를 이용하여 인터넷상에 URL로 표현되는 HTML문서를 웹서버로 요청할수 있다. 아래 예제에서는 GET 메소드를 이용하지만 웹서버로 파라미터를 전달하기 위해 POST 메소드를 이용할수도 있다.
public GetMethod getHttpGetMethod(URL url) {
		HttpClient hc = makeHttpClient(5000, 20000);
		GetMethod  getMethod = new GetMethod(url.toString());
		getMethod.setRequestHeader("User-Agent", "HttpClient");
		getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
				new DefaultHttpMethodRetryHandler(3, false));
		try {
			int statusCode = hc.executeMethod(getMethod);
			if( statusCode == HttpStatus.SC_OK )
				return getMethod;
		} catch(HttpException e) {
			exceptionLogger.warn("Fatal protocol violation: "+e+": "+getMethod.getStatusLine()+", host: "+url);
		} catch(IOException e) {
			exceptionLogger.warn("Fatal transport error: "+e+": "+getMethod.getStatusLine()+", host: "+url);
		}
		return null;
}
GetMethod객체를 성공적으로 리턴했다면 GetMethod객체를 통해 HTML문서 스트림을 생성할수 있다. 스트림이 번거롭다면 HTML문서의 내용을 getResponseBodyAsString 메소드를 이용해 String으로 리턴받을수 있지만 HTML문서의 크기가 명확하게 알려져 있지 않다면 추천되지 않는다.
GetMethod getMethod = getHttpGetMethod(url);
BufferedInputStream responseBodyStream = new BufferedInputStream(method.getResponseBodyAsStream());
여기까지 HttpClient를 이용해 인터넷상의 HTML문서의 내용을 읽어오는 과정이며, 이제 Jericho Parser를 이용한 HTML 문서 파싱 과정은 다음과 같다. 추출하고자 하는 HTML태크명을 담고있는 tagNames와 HTML스트림을 파라미터로 전달한다.
public HashMap getHttpElementsMapFromStream(BufferedInputStream responseBodyStream, Vector tagNames) {
		HashMap elementMap = new HashMap();
		try {
			Source s = new Source(responseBodyStream);
			s.fullSequentialParse();
			List element = null;	
			for(String tag : tagNames) {
				element = s.findAllElements(tag);
				if( element != null ) {
					elementMap.put(tag, element);
				}
			}
		} catch (Exception e) {
			exceptionLogger.warn("Unexpected exception: "+e);
		}
		return elementMap;
}
getHttpElementsMapFromStream 메소드의 리턴값인 HashMap은 인자로 전달된 태그명과 Element List 객체를 담고있다. Element 객체를 추가로 조사함으로서 HTML 파싱을 완료할수 있다. 아래 예에서는 A태그의 href 속성값을 추출하는 예제이다.
Vector tagNames = new Vector();
tagNames.add(HTMLElementName.A);

HashMap elementsMap = getHttpElementsMapFromStream(responseBodyStream, tagNames);
List elementsList = elementsMap .get(HTMLElementName.A);

String href = null;
if( elementList != null ) {
	for(Element element : elementList) {
		href = element.getAttributeValue("href");
                System.out.printle(href);
        }			
}
마지막으로 모든 작업을 마쳤다면 스트림과 GetMethod를 finally 구문에서 닫아주도록 한다.
finally {
	if( responseBodyStream != null )
		try { responseBodyStream.close(); } catch (IOException ignore) {}
	if( method != null ) method.releaseConnection();
}
만약 URL이 포함하는 리소스가 이미지나 기타바이너리파일인지를 확인하여 선택적으로 처리하기를 원한다면 GetMethod대신 HeadMethod를 이용하여 효과적으로 처리할 수 있다.
public HeadMethod getHttpHeadMethod(URL url) {
		HttpClient hc = makeHttpClient(3000, 5000);
		HeadMethod hm = new HeadMethod(url.toString());
		hm.setRequestHeader("User-Agent", agent.getAgentConfig().AgentName);
		hm.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
				new DefaultHttpMethodRetryHandler(3, false));
		try {
			int statusCode = hc.executeMethod(hm);
			if( statusCode == HttpStatus.SC_OK )
				return hm;
		} catch(HttpException e) {
			exceptionLogger.warn("Fatal protocol violation: "+e+": "+hm.getStatusLine()+", host: "+url);
		} catch(IOException e) {
			exceptionLogger.warn("Fatal transport error: "+e+": "+hm.getStatusLine()+", host: "+url);
		}
		return null;
}
public String getContentType(URL url) {
		String contentType = "";
		HeadMethod headMethod = null;
		try {
			headMethod = agent.getHttpHandler().getHttpHeadMethod(url);
			if( headMethod == null ) {
				return null;
			}
			Header header = headMethod.getResponseHeader("Content-Type");
			if( header != null ) {
				contentType = header.getValue();
			}
		} catch (Exception e) {
		} finally {
			if( headMethod != null ) headMethod.releaseConnection();
		}
		return contentType;
}
getContentType 메소드에서 리턴된 String은 "text/html"과 같은 리소스의 타입을 나타내는 문자열을 담고 있다.

'프로그래밍 > 오픈소스' 카테고리의 다른 글

SQLite with Eclipse  (1) 2010.05.06
SWF파일 분석 도구  (0) 2010.04.13
boost library 설치  (0) 2010.03.17
libcurl 사용하기  (0) 2010.03.15
SQLite  (3) 2009.09.11
ACE(ADAPTIVE Communication Environment)  (0) 2009.09.03
MySQL++  (0) 2009.08.21
C++ 암복호화 라이브러리 Crypto++  (0) 2009.08.20
C/C++ XML Parser TinyXml  (1) 2009.08.20
HttpClient와 Jericho Parser를 이용한 HTML 파싱  (0) 2009.07.28
GeoIP를 이용한 IP대역별 국가코드 검색  (1) 2009.07.07
Posted by devop

댓글을 달아 주세요