반응형

 

 

0. 아이스브레이크를 위한 서론

  • 예전에 Jsoup을 사용해서 크롤링 예제를 만든적이 있습니다만, Jsoup에 대한 이해도가 낮아 Apache HTTP를 사용해서 만든적이 있습니다.

  • 결론부터 말하면, Jsoup 자체가 HTTP Connection 을 기반으로 만들어졌기 때문에 단독 라이브러리로도 웹 크롤링이 충분히 가능 합니다.

  • 짧게 말해서 그냥 Jsoup Jar 하나면 웹 크롤링이 가능합니다.

  • Java Project는 1.7 / 1.8 에 대해서는 테스트 해보았습니다.

  • 빠르게 실무 적용이 가능한 예제를 보시려면 제일 아래로 내리세요.

 
 

 

 

1. Jsoup 다운로드 및 프로젝트 추가

  • 다운로드

  • File

    • jsoup-1.11.2.jar core library

    • jsoup-1.11.2-sources.jar optional sources jar

    • jsoup-1.11.2-javadoc.jar optional javadoc jar

  • 다운로드 파일은?

    • 기본적으로 jsoup-x.xx.x.jar 만 다운 받아도 됩니다만 source로 들여다 보고 싶다, API도 보고 싶다하면 선택적으로 -sources나 -javadoc jar 도 다운로드 받으시면 됩니다.

  • 프로젝트 추가

    • 여기서 설명하는 예제는 기본 Java Project로 만들었고 수동 Build Path를 통해 Jar를 등록했습니다.

    • Maven 에서는 아래와 같이 사용하시면 됩니다.

      <dependency>  
        <groupId>org.jsoup</groupId>  
        <artifactId>jsoup</artifactId>
        <version>1.11.2</version>
      </dependency>

 

 

 

2. 가장 기본이 되는 Jsoup GET 방식 예제

  • 가장 기본이 되는 GET 방식 예제는 아래와 같습니다.

    try {
    
     // 1. URL 선언
     String connUrl = "https://www.daum.net";
     
     // 2. HTML 가져오기
     Document doc = Jsoup.connect(connUrl).get();
    
     // 3. 가져온 HTML Document 를 확인하기 
     System.out.println(doc.toString());
     
    } catch (IOException e) {
     // Exp : Connection Fail
     e.printStackTrace();
    }

 

 

 

3. 가장 기본이 되는 Jsoup POST 방식 예제

  • 가장 기본이 되는 Jsoup POST 방식 호출은 아래와 같습니다.

    try {
     // 1. URL 선언 
     String connUrl = "http://map.daum.net";
    
     // 2. HTML 가져오기 
     Document doc = Jsoup.connect(connUrl).post();
    
     // TODO POST의 data 값은 Jsoup.data(...) 을 사용하시면 됩니다. 
    
     // 3. 가져온 HTML Document 를 확인하기  
     System.out.println(doc.toString());
     
    } catch (IOException e) {
     // Exp : Connection Fail
     e.printStackTrace();
    }
    • POST의 data 값은 Jsoup.data(...) 을 사용하시면 됩니다.

 

 

4. 쓸만한 Jsoup 예제

  • 기본 예제는 Hello World 예제를 보셨다면, 실제로 적용하기에는 문제들이 있습니다.

    • USER AGENT 가 없어 Malform URL 이 될 수 있습니다.

    • HTTPS 호출 시, 인증서가 없어 에러가 발생합니다.

  • 위에 두가지에 대해서 적용가능한 JSOUP 예제는 계속해서 예제로 설명드리겠습니다.

 

 

 

이슈해결 > Malform URL 은 어떻게?

  • Malform URL 에러는 아래와 같이 header / userAgent / ignoreContentType(true) 옵션을 추가하면 해결 됩니다.

 

    private final static String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36";
    public static void main(String[] args) {
     try {

      // 1. URL 선언            
      String connUrl = "http://map.daum.net";
      
      // 2. HTML 가져오기            
      Connection conn = Jsoup.connect(connUrl)
      						.header("Content-Type", "application/json;charset=UTF-8")
                            .userAgent(USER_AGENT)
                            .method(Connection.Method.GET)
                            .ignoreContentType(true);
      Document doc = conn.get();
      
      // 3. 가져온 HTML Document 를 확인하기            
      System.out.println(doc.toString());
      
     } catch (IOException e) {
      // Exp : Connection Fail            
      e.printStackTrace();
     }
    }

 

 

이슈해결 > SSL (HTTPS) 은 어떻게 호출해야하나?

  • 아래 에러는 SSL 인증 에러입니다.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)    at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:730)    at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:706)    at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:299)    at org.jsoup.helper.HttpConnection.get(HttpConnection.java:288)    at com.derveljun.jsoup.JsoupCrawlerExample.main(JsoupCrawlerExample.java:27)Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)    at sun.security.validator.Validator.validate(Validator.java:260)    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)    ... 15 moreCaused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)    ... 21 more
    • SSL 에러 발생은 아래 예제를 통해 적용가능합니다. JAVA Vers해봅니다. SSL을 우회적으로 인증하는 방법입니다.

        // SSL 우회 등록    
        public static void setSSL() throws NoSuchAlgorithmException, KeyManagementException {
         TrustManager[] trustAllCerts = new TrustManager[] {
          new X509TrustManager() {
           public X509Certificate[] getAcceptedIssuers() {
            return null;
           }​
           public void checkClientTrusted(X509Certificate[] certs, String authType) {}​
           public void checkServerTrusted(X509Certificate[] certs, String authType) {}
          }
         };
         SSLContext sc = SSLContext.getInstance("SSL");
         sc.init(null, trustAllCerts, new SecureRandom());
         HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
          @Override public boolean verify(String hostname, SSLSession session) {
           return true;
          }
         });
         HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        }
    • SSL 설정을 메소드로 따로 빼서 사용하는 예제 입니다.

      package com.derveljun.jsoup;​
      import java.io.IOException;
      import java.security.KeyManagementException;
      import java.security.NoSuchAlgorithmException;
      import java.security.SecureRandom;
      import java.security.cert.X509Certificate;​
      import javax.net.ssl.HostnameVerifier;
      import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager;​
      import org.jsoup.Connection;
      import org.jsoup.Jsoup;
      import org.jsoup.nodes.Document;​
      public class JsoupCrawlerExample {
       private final static String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36";
       // SSL 우회 등록    
       public static void setSSL() throws NoSuchAlgorithmException, KeyManagementException {
        TrustManager[] trustAllCerts = new TrustManager[] {
         new X509TrustManager() {
          public X509Certificate[] getAcceptedIssuers() {
           return null;
          }​
          public void checkClientTrusted(X509Certificate[] certs, String authType) {}​
          public void checkServerTrusted(X509Certificate[] certs, String authType) {}
         }
        };
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
         @Override public boolean verify(String hostname, SSLSession session) {
          return true;
         }
        });
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
       }
       public static void main(String[] args) {
        try {
         // 1. URL 선언            
         String connUrl = "https://www.daum.net";
         
         // 2. SSL 체크            
         if (connUrl.indexOf("https://") >= 0) {
          JsoupCrawlerExample.setSSL();
         }
         
         // 3. HTML 가져오기            
         Connection conn = Jsoup.connect(connUrl).header("Content-Type", "application/json;charset=UTF-8").userAgent(USER_AGENT).method(Connection.Method.GET).ignoreContentType(true);
         Document doc = conn.get();
         
         // 4. 가져온 HTML Document 를 확인하기            
         System.out.println(doc.toString());
        } catch (IOException e) {
         // Exp : Connection Fail            
         e.printStackTrace();
        } catch (KeyManagementException e) {
         // TODO Auto-generated 
         catch block e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
         // TODO Auto-generated 
         catch block e.printStackTrace();
        }
       }
      }​

 

 

점심시간 안에 끝내려고 했는데 시간이 너무 많이 지났네요 ^^;;

 

다음에 시간되면 조금더 글좀 다듬겠습니다.

부족한 부분이나 첨언 / 문의 사항은 댓글 부탁드립니다.

반응형

WRITTEN BY
데르벨준

,