Back-End

[크롤링] Jsoup과 Selenium

Minch13r 2025. 2. 1. 17:30

Jsoup을 통해서 크롤링을 진행하고 크롤링을 한 내용을 바탕으로 콘솔 기반 프로그램을 만드려고 했다. 하지만 span 태그와 같이 간단한 것들은 크롤링이 되는 반면 우리가 원하는 내용은 크롤링이 진행되지 않았다.

 

이유가 뭔지 고민을 해봤다.

 

결론은 Jsoup은 정적 기반 크롤링이기 때문에 JavaScript에서 따로 처리를 해서 크롤링이 안 되는 것이였다. 그렇기에 나는 동적 기반의 크롤링인 Selenium을 선택했다.


Jsoup

Jsoup의 주요 특징들을 살펴보자면 다음과 같다.

  1. 손쉬운 HTML 파싱
    • 웹 사이트의 HTML을 마치 책을 읽듯이 쉽게 읽어들일 수 있습니다.
    • URL, 파일, 문자열 등 다양한 소스로부터 HTML을 파싱할 수 있습니다.
  2. CSS 선택자 지원
    • CSS 선택자를 사용하여 원하는 요소를 쉽게 찾을 수 있습니다.
    • 마치 jQuery처럼 편리하게 요소를 선택할 수 있습니다.
  3. 데이터 추출 및 조작
    • HTML 요소의 텍스트, 속성, HTML 등을 쉽게 가져올 수 있습니다.
    • HTML 문서의 내용을 수정할 수도 있습니다.
  4. 웹 스크래핑 기능
    • 웹 페이지의 데이터를 자동으로 수집할 수 있습니다.
    • 뉴스 기사, 상품 정보 등을 수집하는데 많이 사용됩니다.
  5. 안전한 HTML 처리
    • XSS(Cross-Site Scripting) 공격을 방지하기 위한 기능을 제공합니다.
    • HTML을 안전하게 정제할 수 있습니다.

예시)

  1. 웹 페이지 연결하기
Document doc = Jsoup.connect("https://example.com").get();

 

 

    2. 요소 선택하기

// 모든 링크 찾기
Elements links = doc.select("a");

// 특정 클래스를 가진 요소 찾기
Elements news = doc.select(".news-item");

   3.데이터 추출하기

// 제목 가져오기
String title = doc.select("h1").text();

// 이미지 URL 가져오기
String imageUrl = doc.select("img").first().attr("src");

 

Jsoup을 사용할 때 주의할 점:

  1. 웹 사이트의 이용약관을 반드시 확인해야 한다.
  2. 과도한 요청은 서버에 부담을 줄 수 있으므로 적절한 간격을 두어야 한다.
  3. 네트워크 오류에 대한 예외 처리가 필요하다.

Selenium

Selenium은 웹 브라우저를 자동으로 제어할 수 있는 강력한 자동화 도구이다. 마치 실제 사람이 웹 브라우저를 사용하는 것처럼 클릭, 키보드 입력, 스크롤 등의 동작을 자동으로 수행할 수 있다.

Selenium의 주요 특징

  1. 실제 브라우저 제어
    • Chrome, Firefox, Safari 등 다양한 브라우저를 직접 제어할 수 있다.
    • 실제 사용자처럼 웹 페이지와 상호작용이 가능하다.
  2. 동적 컨텐츠 처리
    • JavaScript로 생성되는 동적 컨텐츠도 처리할 수 있다.
    • Ajax 요청 결과도 기다렸다가 처리할 수 있다.
  3. 다양한 프로그래밍 언어 지원
    • Java, Python, JavaScript, C# 등 여러 언어로 사용 가능하다.
    • 각 언어의 특성에 맞는 API를 제공한다.

Selenium의 주요 용도

  1. 웹 테스트 자동화
    • 웹 애플리케이션의 기능 테스트
    • 회귀 테스트 자동화
    • 크로스 브라우저 테스트
  2. 웹 스크래핑
    • 동적 웹 페이지의 데이터 수집
    • 로그인이 필요한 페이지 접근
    • 복잡한 사용자 상호작용이 필요한 데이터 수집
  3. 웹 자동화
    • 반복적인 웹 작업 자동화
    • 폼 자동 입력
    • 스크린샷 자동 캡처

사용 예시

 

1. Webdriver 설정

// Chrome 드라이버 설정
WebDriver driver = new ChromeDriver();

 

2. 웹 페이지 접속

// 웹 페이지 열기
driver.get("https://www.example.com");

 

3. 요소 찾기와 조작

// ID로 요소 찾기
WebElement element = driver.findElement(By.id("search"));

// 클래스로 요소 찾기
WebElement element = driver.findElement(By.className("search-input"));

// CSS 선택자로 요소 찾기
WebElement element = driver.findElement(By.cssSelector("#search-form .input"));

// 텍스트 입력하기
element.sendKeys("검색어");

// 클릭하기
element.click();

 

4. 대기 처리

// 명시적 대기
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(
    ExpectedConditions.presenceOfElementLocated(By.id("result"))
);

 

Selenium 사용 시 주의사항

  1. 성능 고려
    • 실제 브라우저를 실행하므로 리소스 사용량이 많다.
    • 많은 수의 동시 실행은 시스템에 부담을 줄 수 있다.
  2. 안정성 관리
    • 네트워크 상태에 따른 대기 시간 설정이 중요하다.
    • 예외 처리를 철저히 해야 한다.
  3. 웹사이트 정책 준수
    • 웹사이트의 이용약관을 반드시 확인해야 한다.
    • 과도한 요청은 피해야 한다.

Jsoup과 Selenium의 차이점

1. 기본 특성 차이

Jsoup

  • HTML 파서(Parser) 라이브러리
  • 가볍고 빠른 처리 속도
  • 정적 웹 페이지 처리에 특화
  • 메모리 사용량이 적음

Selenium

  • 웹 브라우저 자동화 도구
  • 실제 브라우저를 구동
  • 동적 웹 페이지 처리 가능
  • 상대적으로 많은 리소스 사용

2. 주요 기능 비교

Jsoup의 기능

// HTML 문서 가져오기
Document doc = Jsoup.connect("https://example.com").get();

// 요소 선택
Elements elements = doc.select("div.content");

// 텍스트 추출
String text = elements.text();

Selenium의 기능

// 브라우저 실행
WebDriver driver = new ChromeDriver();

// 페이지 이동
driver.get("https://example.com");

// 요소와 상호작용
WebElement element = driver.findElement(By.cssSelector("button.login"));
element.click();

3. 사용 케이스 비교

Jsoup이 적합한 경우

  1. 단순 데이터 수집
    • 뉴스 기사 내용 수집
    • 상품 정보 수집
    • 블로그 포스트 내용 파싱
  2. 정적 웹페이지 처리
    • HTML 구조가 단순한 사이트
    • JavaScript 없이 내용이 표시되는 페이지
    • RSS 피드나 XML 문서 파싱
  3. 빠른 처리가 필요한 경우
    • 대량의 웹페이지 수집
    • 실시간 데이터 파싱
    • 서버 부하를 최소화해야 하는 경우

Selenium이 적합한 경우

  1. 동적 컨텐츠 처리
    • JavaScript로 생성되는 컨텐츠
    • SPA(Single Page Application) 처리
    • Ajax 요청 결과 처리
  2. 사용자 상호작용 필요
    • 로그인이 필요한 페이지
    • 폼 입력 및 제출
    • 버튼 클릭, 스크롤 등의 동작
  3. 자동화 테스트
    • 웹 애플리케이션 테스트
    • 사용자 시나리오 테스트
    • 크로스 브라우저 테스트

4. 성능 비교

Jsoup

  • 메모리 사용: 낮음
  • 처리 속도: 빠름
  • 리소스 소비: 적음
  • 설정 복잡도: 낮음

Selenium

  • 메모리 사용: 높음
  • 처리 속도: 상대적으로 느림
  • 리소스 소비: 많음
  • 설정 복잡도: 높음

5. 코드 예시 비교

Jsoup으로 데이터 수집

// 간단한 데이터 수집
Document doc = Jsoup.connect("https://example.com").get();
String title = doc.select("h1").text();
String content = doc.select("div.content").text();

Selenium으로 데이터 수집

// 동적 데이터 수집
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");

// 요소가 로드될 때까지 대기
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(
    ExpectedConditions.presenceOfElementLocated(By.cssSelector("h1"))
);

String title = element.getText();

6. 결론

  1. Jsoup 선택 시기
    • 단순한 HTML 파싱이 필요할 때
    • 빠른 처리가 중요할 때
    • 리소스 사용을 최소화하고 싶을 때
  2. Selenium 선택 시기
    • 동적 컨텐츠 처리가 필요할 때
    • 사용자 상호작용이 필요할 때
    • 자동화 테스트가 목적일 때

소스 코드 비교

Jsoup

package day018.class01;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Test03 {
    public static void main(String[] args) {
        try {
            // 1. 웹페이지 연결
            String url = "https://m.kinolights.com/ranking/netflix";
            Document doc = Jsoup.connect(url).get();

            System.out.println("페이지 연결 성공!");

            // 2. 영화 제목이 있는 링크 선택 (table-td 클래스 내의 a 태그)
            Elements titleElements = doc.select(".info__title");

            // 3. 결과 출력
            int rank = 1;
            for (Element title : titleElements) {
                // 텍스트에서 Netflix original 텍스트를 제거하고 출력
                String titleText = title.text().replace("Netflix original", "").trim();
                System.out.println(rank + ". " + titleText);
                rank++;
            }

        } catch (Exception e) {
            System.out.println("오류 발생: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Jsoup 출력 결과

 

Selenium

package day018.class01;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.List;

public class Selenium {
    public static void main(String[] args) {
        try {
            // ChromeDriver 경로 지정
            String driverPath = "C:\\Users\\3333c\\Desktop\\school\\ACADEMY\\study\\src\\day018\\class01\\driver\\chromedriver.exe";

            // setProperty()로 ChromeDriver의 위치를 시스템에 넘김
            System.setProperty("webdriver.chrome.driver", driverPath);

            // Chrome 옵션 설정
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless");           // 브라우저 창을 띄우지 않고 백그라운드에서 실행
            options.addArguments("--disable-gpu");        // GPU 하드웨어 가속 비활성화
            options.addArguments("--no-sandbox");         // 샌드박스 모드 비활성화
            options.addArguments("--disable-dev-shm-usage"); // 공유 메모리 사용 비활성화

            // WebDriver 생성
            WebDriver driver = new ChromeDriver(options);

            try {
                // 웹페이지 로드
                driver.get("https://m.kinolights.com/ranking/netflix");

                // 페이지가 완전히 로드될 때까지 충분히 기다림
                Thread.sleep(3000); // 3초 대기

                // 명시적 대기 설정
                // 최대 대기 10초 설정
                WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
                // .info__title이 나타날 때까지 대기
                wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(
                        By.cssSelector(".info__title")));

                // .info__title 클래스를 가진 모든 요소를 찾아 리스트로 저장합
                List<WebElement> titleElements = driver.findElements(
                        By.cssSelector(".info__title"));

                // 결과 출력 (상위 20개만)
                System.out.println("\n===== 넷플릭스 TOP 20 =====");
                int count = 0;
                for (WebElement element : titleElements) {
                    String title = element.getText().trim(); // 요소의 텍스트를 가져와서 공백 제거
                    if (!title.isEmpty() && count < 20) { // 빈 문자열이 아니고 20개 미만일 때만
                        System.out.println((count + 1) + ". " + title);
                        count++;
                    }
                }

            } finally {
                driver.quit();
                System.out.println("브라우저 종료 완료");
            }

        } catch (Exception e) {
            System.out.println("오류 발생: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Selenium 출력 결과

 

같은 웹사이트, 같은 태그를 향해 크롤링을 진행해봤는데, 결과가 이렇게 다르다. 상황에 따라 알맞은 선택을 하길 바란다.

'Back-End' 카테고리의 다른 글

[JAVA] 오답노트 및 발표 피드백  (1) 2025.02.17
[JAVA] Toy-Project  (1) 2025.02.07
[JAVA] 기초 공부 15 크롤링  (5) 2025.01.24
[JAVA] 기초 공부 14 MVC-1  (1) 2025.01.23
[JAVA] 기초 공부 13 MVC  (1) 2025.01.22