본문 바로가기
오픈소스를 위한 기초 상식

BeautifulSoup4: 웹 크롤링의 기초와 활용법

by 지나가는 프로도 2025. 1. 29.

BeautifulSoup4

 

웹 크롤링은 다양한 데이터를 수집하고 분석하는 데 있어 중요한 기술입니다. 특히 Python의 BeautifulSoup4 라이브러리는 HTML 및 XML 문서를 손쉽게 처리하고 원하는 데이터를 추출할 수 있는 강력한 도구로, 초보자부터 전문가까지 폭넓게 사용됩니다. 이 글에서는 BeautifulSoup4의 기본 사용법과 웹 데이터 크롤링의 핵심을 단계적으로 설명하겠습니다.


1. BeautifulSoup4란 무엇인가?

BeautifulSoup4(이하 BS4)는 HTML이나 XML 문서를 Pythonic하게 처리할 수 있도록 설계된 파싱 라이브러리입니다. 이를 통해 개발자는 복잡한 웹 페이지의 구조를 쉽게 분석하고, 원하는 데이터를 추출할 수 있습니다. BS4는 다음과 같은 장점을 제공합니다:

  • 간편한 HTML 구조 탐색: BS4는 DOM(Document Object Model) 트리를 생성해, HTML 문서를 객체처럼 다룰 수 있습니다.
  • 다양한 파서 지원: 내장 HTML 파서인 html.parser부터, 외부 라이브러리 기반의 lxml과 같은 빠르고 강력한 파서까지 지원합니다.
  • 유연한 태그 탐색: CSS 선택자, 태그 이름, 속성 등 다양한 방식으로 HTML 요소를 찾을 수 있습니다.

설치 방법

BeautifulSoup4는 Python의 패키지 관리 도구인 pip로 간단히 설치할 수 있습니다:

pip install beautifulsoup4

이와 함께, lxml 파서를 사용하려면 아래 명령으로 추가 설치가 필요합니다:

pip install lxml

 

BeautifulSoup4와 HTML

 

2.1 HTML 문서 로드 및 파싱

웹 페이지의 HTML 문서를 가져와 BeautifulSoup 객체로 변환하려면, requests와 같은 HTTP 클라이언트를 사용하여 페이지 내용을 가져오고 이를 BS4로 처리합니다.

import requests
from bs4 import BeautifulSoup

url = 'https://example.com'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

여기서 html.parser는 내장 파서로, 별도의 설치 없이 사용 가능합니다. 하지만 더 복잡한 HTML을 처리하려면 lxml을 사용하는 것이 좋습니다.

2.2 HTML 구조 탐색

BS4를 사용하면 다양한 방식으로 HTML 요소를 탐색할 수 있습니다. 주요 탐색 방법은 다음과 같습니다:

  • 태그 이름으로 찾기: find() 또는 find_all() 메서드를 사용합니다.
# 첫 번째 <a> 태그 찾기
tag = soup.find('a')

# 모든 <a> 태그 찾기
tags = soup.find_all('a')
  • CSS 선택자로 찾기: select() 메서드를 사용합니다.
# 특정 클래스명을 가진 태그 찾기
tags = soup.select('.classname')

# id를 가진 태그 찾기
tag = soup.select_one('#element_id')
  • 속성으로 필터링: attrs를 사용하여 특정 속성을 가진 태그를 찾습니다.
tag = soup.find('a', attrs={'href': 'https://example.com'})

2.3 HTML 데이터 추출

HTML 요소에서 텍스트나 속성을 추출하려면 textattrs를 사용합니다.

# 텍스트 추출
print(tag.text)

# 특정 속성 추출
print(tag['href'])

 

실습: 네이버 해드라인 뉴스

 

우선, 크롬 개발자 도구를 활용해야 합니다.

그래서 해당 내용에 대해서 찾아봐야 하는데, 여기에서 보이는 것처럼 헤드라인 뉴스가 있는 위치를 탐색하는 과정이 중요한데, 이를 빠르게 진행하기 위해서는 html구조를 기본적으로 인식할 수 있어야 합니다.

 

근데 네이버 헤드라인은 시간이 지나면 자동으로 넘어가므로 li를 포함하는 ui클라스가 변화합니다.

 

이를 동적 클라스로 하며, 일반적인 정적 클라스 방식으로 대처하기에는 무리가 있습니다.

네이버 헤드라인처럼 시간이 지나면 UI 클래스가 동적으로 변화하는 경우를 다룰 때, 몇 가지 전략을 고려해야 합니다. HTML 구조의 변화를 효과적으로 다룰 수 있는 방법을 아래에 정리했습니다.


1. 고정된 부모 요소를 기준으로 탐색

HTML 구조에서 변하지 않는 상위 요소를 기준으로 접근하는 방법입니다. UI 클래스가 바뀌더라도 고정된 부모 요소(예: <div>나 <section>)가 있다면 이를 기준으로 크롤링 범위를 좁힙니다.

해결 방법

상위 요소를 찾은 뒤, 모든 li 태그나 a 태그를 탐색합니다. 예를 들어:

python
복사편집
news_section = soup.find('div', id='news') # 고정된 id나 속성 활용 headlines = news_section.find_all('a') # 모든 a 태그 검색

 

2. CSS 선택자 활용

변하지 않는 고정된 상위 요소의 ID클래스를 사용해 select()로 특정 범위 내의 데이터를 모두 가져옵니다. 하위 요소가 변경되더라도 상위 요소는 그대로 유지되는 경우에 적합합니다.

예시 코드:

더보기
news_section = soup.select_one('div[class^="MediaNewsView"]') # 'MediaNewsView'로 시작하는 클래스 선택 headlines = news_section.select('li a') # 모든 li 태그 내부의 a 태그 찾기

 

3. 동적 클래스 패턴 처리

클래스 이름이 일정한 규칙(예: __desc_item, __news_item)을 따른다면, 정규 표현식으로 해당 패턴을 처리할 수 있습니다. BeautifulSoup의 find_all()과 attrs 옵션에서 정규식을 사용할 수 있습니다.

예시 코드:

더보기
import re # 동적으로 변화하는 클래스 패턴 처리 news_items = soup.find_all('li', class_=re.compile(r'__desc_item|__news_item')) for item in news_items: headline = item.find('a') if headline: print(headline.text.strip())
  • re.compile()은 클래스 이름이 특정 패턴(예: __desc_item, __news_item)과 일치하면 모두 선택합니다.

 

4. JavaScript 동적 로딩 처리

네이버 메인 페이지처럼 JavaScript에 의해 동적으로 콘텐츠가 변경되는 경우, 서버에서 크롤링한 HTML 소스에는 업데이트된 내용이 반영되지 않을 수 있습니다. 이를 해결하려면 Selenium과 같은 브라우저 자동화 도구를 활용해야 합니다.

Selenium 예시 코드:

더보기
from selenium import webdriver
from seleniuhttp://m.webdriver.common.by import By
from bs4 import BeautifulSoup
import time

# Selenium WebDriver 설정
driver = webdriver.Chrome()  # chromedriver 경로 필요
driver.get('https://www.naver.com')

time.sleep(2)  # 페이지 로딩 대기 (필요 시 조정)

# 페이지 HTML 가져오기
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')

# 고정된 상위 UI 클래스에서 뉴스 크롤링
news_section = soup.find('div', class_='MediaNewsView-module__news_desc___a55yg')  # 예시 클래스
if news_section:
    headlines = news_section.find_all('a')
    for headline in headlines:
        print(headline.text.strip())

driver.quit()

 

5. 동적인 HTML 클래스가 없는 경우 대응

만약 상위 클래스도 시간에 따라 바뀌어 특정 기준을 잡기 어려운 경우, DOM 구조 자체를 기반으로 접근해야 합니다.

예시 코드 (상위 부모 요소 기준 탐색):

더보기
# 고정된 부모 요소로부터 li 태그를 모두 탐색
parent_div = soup.find('div', id='news')  # 고정된 id 활용
if parent_div:
    list_items = parent_div.find_all('li')  # 모든 li 태그 탐색
    for item in list_items:
        headline = item.find('a')
        if headline:
            print(headline.text.strip())

 

6. 결론 및 추천

  1. HTML 구조 분석:
    • 변하지 않는 상위 요소를 기준으로 탐색합니다.
    • 동적으로 바뀌는 클래스는 정규식(re.compile)을 사용합니다.
  2. JavaScript 처리:
    • 콘텐츠가 JavaScript로 변경된다면 Selenium과 같은 브라우저 자동화 도구를 사용합니다.
  3. 주기적인 점검:
    • 네이버의 HTML 구조가 종종 업데이트될 가능성이 있으므로, 일정 간격으로 HTML 구조를 점검합니다.