제가 만드는 앱의 기능중 HTML 페이지의 소스를 긁어와서 Parsing 해야 하는 부분이 있었습니다..

일단 구글링을 해본바로는 HTML Parsing하는데는 Jericho를 대부분 사용하고 있고 관련 예제도 많이 있어서..

Parsing 하는 부분에 있어서는 큰 무리는 없었는데요..

문제는 HTML 소스를 가져오는 부분에서 발생하더군요..

요즘 안드로이드 앱들이 HTML 소스를 긁어가는 식이 많아져서 웹서버에 부하가 생기는 것인지는 몰라도..

그렇게 가져가는 것을 막는 웹사이트가 있더군요..

웹브라우저(IE, 파폭 등)로 접속하면 웹페이지가 잘 뜨지만..

안드로이드 상에서 HttpClient 객체를 이용해서 웹페이지 소스를 가져올려고 하면 가져오지 못하더군요..

정확하게 말하면 소스는 가져오는데..웹페이지에서 보는 소스와는 다른 내용의 소스를 가져오게 됩니다..

그래서 이에 대한 내용을 말씀드리고자 합니다..

Http 프로토콜로 통신을 할땐 header라고 하는 일종의 정보 저장하는 곳이 있습니다.

header는 복수개의 Key / Value 구성으로 이루어져 있습니다..

그래서 웹브라우저에서 Http 프로토콜로 웹서버에 웹페이지를 요청할때의 header는 ..

request(요청) header 라는 이름으로 웹서버에서 필요한 정보를 보내주게 되구요..

웹서버에서 웹브라우저로 Http 프로토콜을 이용해서 요청된 페이지 내용을 보낼때는..

마찬가지로 response(응답) header 라는 이름으로 웹브라우저에서 필요한 정보를 보내주게 됩니다.

request header에 들어가는 값들중 대표적인 것으로 사용자가 웹페이지에서 입력한 값들이 들어가게 되고..

response header에 들어가는 값들중 대표적인 것으로는 웹페이지의 character set이 들어가게 됩니다.

웹서버는 웹브라우저가 보내주는 request header 정보에서 사용자가 어떤 웹브라우저를 쓰는지 알 수 있는데요..

이 항목을 저장하고 있는 것이 User-Agent 란 항목입니다.

예를 들어 파이어폭스 4.0에서 어떤 웹페이지를 읽고자 한다면 웹서버는 request header에서 User-Agent 항목을 읽게 되는데..

파이어 폭스의 User-Agent 항목의 값은 Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0 이런 값이 들어갑니다
(이 값은 웹브라우저가 실행되는 OS, 웹브라우저의 종류에 따라 크거나 작게 변경 사항이 발생됩니다)

일반적으로 웹페이지 프로그래밍에서 사용되는 asp, php, jsp에서는 바로 이러한 웹브라우저의 header 정보를 읽어올수 있습니다.

그래서 만약 웹브라우저를 통한 접근이 아닌 HttpClient 객체를 이용한 접근을 하게 되면 header에 이런 내용이 없기 때문에 접근을 못하게끔 할 수 있습니다.

그래서 웹브라우저에서 보는 내용이 아닌 다른 내용을 보여주는 것이지요..

저도 단순히 HttpClient 객체를 만들어서 접근시도를 해본뒤 소스를 Logcat으로 출력해보면..

정상적인 경로로 접근하지 않았습니다..란 문구가 소스에 나오고 그 뒤로 아무것도 없는 내용의 소스를 받게 되었습니다..

그래서 이 부분을 어떻게 해결하느냐 하면..

HttpClient 객체를 이용하실때 HttpGet 객체를 만드실꺼고 거기에 접근하고자 하는 URL을 넣으실겁니다..이렇게요..


1.HttpGet httpGet = new HttpGet(strurl);


이때 인위적으로 header의 User-Agent 항목에 값을 넣어줍니다..이렇게요..


1.httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0");


이렇게 하시면 웹서버에서 HttpClient 객체가 파이어폭스 4.0 웹브라우저로 접근한것으로 속일수 있기때문에 asp,php,jsp에서 header값을 이용한 걸러내기 작업을 피할수가 있습니다..

단 이 방법은 해당 웹사이트가 User-Agent 항목을 이용해서 사용자가 어떤 경로로 들어왔는지를 체크하여 그에 따라 작업하는 사이트 일 경우에 가능한 겁니다..

사실 이 방법 말고도 웹서버에서는 정상적인 경로로 들어온것인지를 체크하는 방법이 또 하나 더 있습니다..

request header 중에 referer란 값을 읽으면 현재 읽고자 하는 페이지를 들어오기 전에 어떤 페이지에서 왔는지를 기록하는 값이 있습니다..

이 값으로는 정상적인 경로로 들어왔는지를 확인하기가 어려운것이 여러가지 이전 페이지에서 접근을 할 수 있기 때문에 이것으로 제어하기가 어렵지만..

만약 내가 읽고자 하는 페이지가 반드시 어떤 페이지를 거쳐야만 한다..라는 주제가 잡힌 하에서 웹사이트가 구성된 것이라면..

User-Agent가 아닌 referer 값으로 제어할수도 있습니다.

이럴 경우는 addHeader 함수에 User-Agent가 아닌 referer 항목으로 해서 값을 넣어야 하는것이죠..

마지막으로 제가 이렇게 구현한 함수 소스를 올리면서 글을 마무리짓겠습니다..

사소한 팁이었습니다..


01.public InputStream getHtmlContents(){
02. // strurl 변수엔 접근하고자 하는 웹페이지 URL이 들어가 있습니다..
03. HttpGet httpGet = new HttpGet(strurl);  
04.   
05. httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0");
06.   
07. HttpClient httpClient = new DefaultHttpClient();
08. HttpParams tmpparms = httpClient.getParams();
09. HttpConnectionParams.setConnectionTimeout(tmpparms, REGISTRATION_TIMEOUT);
10. HttpConnectionParams.setSoTimeout(tmpparms, REGISTRATION_TIMEOUT);
11. ConnManagerParams.setTimeout(tmpparms, REGISTRATION_TIMEOUT);
12. HttpResponse resp;
13. InputStream instream = null;
14.   
15. try{
16.  resp = httpClient.execute(httpGet);
17.  if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
18.   HttpEntity respEntity = resp.getEntity();
19.   if(respEntity != null){
20.    instream = respEntity.getContent();
21.      
22.   }
23.  }
24. }catch(IOException e){
25.    
26. }
27. return instream;
28.}
 
출처: 안드로이드펍