BeautifulSoup 웹 스크래핑 가이드

파이썬의 Beautiful Soup을 사용한 웹 스크래핑 시작을 돕는 빠른 튜토리얼을 찾고 계신가요? 바로 여기에서 시작하세요 – 계속 읽어보고 즉시 시작해 보세요.
3 분 읽기
How to Scrape with BeautifulSoup

웹 스크래핑은 일반적으로 분석이나 집계를 위해 정보를 검색하기 위해 스크립트나 소프트웨어 도구를 사용하여 웹사이트에서 데이터를 추출하는 자동화된 과정입니다.

Beautiful Soup은 HTML 및 XML 문서를 효율적으로 파싱하는 인기 있는 Python 라이브러리입니다.

이 포괄적인 가이드에서는 Beautiful Soup을 활용한 웹 스크래핑 방법을 배울 수 있습니다. 다양한 코드 샘플과 실용적인 조언이 담긴 이 글은 학습 과정 전반에 걸쳐 유용한 통찰력을 제공합니다.

Beautiful Soup을 이용한 웹 스크래핑

일반적으로 HTML 및 XML 언어는 웹 콘텐츠 구조화에 사용되며, 문서 객체 모델(DOM) 트리는 객체 트리 형태로 문서를 표현합니다. 자동화된 스크립트나 라이브러리를 사용해 DOM을 탐색함으로써 웹 콘텐츠에서 의미 있는 정보를 추출할 수 있습니다.

Beautiful Soup 파이썬 라이브러리는 HTML 및 XML 문서를 파싱하고 DOM 트리를 탐색할 수 있습니다. 이 라이브러리는 사용자의 기기에서 최적의 HTML 파서를 자동으로 선택하거나, 사용자 지정 HTML 파서를 명시할 수도 있습니다. 그런 다음 라이브러리는 HTML 문서를 탐색 가능한 파이썬 객체 트리로 변환합니다.

Beautiful Soup은 또한 빠르고 효율적인 lxml 파서를 사용하여 XML 콘텐츠를 파싱할 수 있게 합니다. HTML 문서와 유사하게, 이 라이브러리는 XML 문서로부터 Beautiful Soup 선택자를 사용하여 문서를 탐색하는 데 사용할 수 있는 Python 객체 트리를 생성합니다.

Beautiful Soup의 HTML 또는 XML 파서는 웹 콘텐츠를 파싱하여 DOM 트리와 유사한 Python 객체를 생성하는 데 사용될 수 있습니다. 생성된 Python 객체는 관련 요소를 선택하여 문서의 다양한 부분에서 데이터를 효율적으로 추출하는 데 활용됩니다. 요소 선택에는 여러 방법이 있습니다. find()는 선택기 조건을 받아 첫 번째 일치하는 HTML 요소를 반환하고, find_all()는 선택기 조건을 받아 모든 일치하는 HTML 요소의 목록을 반환합니다. 예를 들어 find_all('p') 선택기를 사용하면 단락(<p>) 태그 내의 모든 내용을 찾을 수 있습니다.

웹 스크래핑을 위한 Beautiful Soup 활용

웹 페이지에서 데이터를 스크래핑하기 전에, 페이지에서 어떤 데이터를 추출할지 그리고 어떻게 추출할지 파악해야 합니다.

웹 브라우저의 개발자 도구를 사용하여 웹 페이지의 요소를 검사할 수 있습니다. 예를 들어, 다음 스크린샷은 ‘추출할 인용문’ 웹 페이지의 인용문 블록에 대한 DOM 요소를 보여줍니다:

Quotes to scrape

인용문 텍스트는 span 태그 안에, 저자 이름은 small 태그 안에 있음을 확인할 수 있습니다. 태그 외에도 HTML 속성과 CSS 선택자를 조합하여 특정 요소를 선택할 수 있습니다. 이 가이드에서는 ‘인용문 스크래핑’ 페이지에서 인용문과 저자 이름을 추출할 것입니다.

새 프로젝트 생성

시작하려면 스크래핑 스크립트를 위한 beautifulsoup-scraping-example이라는 새 프로젝트 디렉터리를 생성하고 다음 명령어로 이동하세요:

mkdir beautifulsoup-scraping-example
cd beautifulsoup-scraping-example

웹 스크래핑 시에는 먼저 HTTP GET 요청을 사용하여 URL에서 웹 페이지 콘텐츠를 가져와야 합니다. 다음 명령어로 requests 라이브러리를 설치하세요:

pip install requests

이 라이브러리는 나중에 GET 요청을 수행하는 데 사용됩니다.

실제 웹 스크래핑 작업을 위해 다음 명령어로 beautifulsoup4 파이썬 라이브러리를 설치하세요:

pip install beautifulsoup4

스크립트 협업이나 버전 관리 시스템 체크인을 위해 종속성 목록을 파일에 저장할 수도 있습니다. 프로젝트 루트에 다음 내용으로 requirements.txt 파일을 생성하세요:

requests
beautifulsoup4

그런 다음 이 명령어로 앞서 정의한 의존성을 설치하세요:

pip install -r requirements.txt

웹 스크래핑 스크립트 정의

다음으로, 웹 페이지 콘텐츠를 가져와 BeautifulSoup을 사용하여 파싱하여 soup 객체를 생성하는 Python 스크립트를 정의해야 합니다. soup 객체와 함께 다양한 선택자를 사용하여 웹 페이지에서 요소를 찾고 원하는 정보를 추출할 수 있습니다.

프로젝트 루트에 main.py라는 Python 스크립트 파일을 생성하고 requestsbeautifulsoup4에 대한 import 문을 추가하세요:

import requests
from bs4 import BeautifulSoup

다음으로 웹 URL을 인수로 받아 페이지 내용을 반환하는 메서드를 정의합니다:

def get_page_contents(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
    }
    
    page = requests.get(url, headers=headers)
    
    if page.status_code == 200:
        return page.text

    return None

get_page_contents 메서드는 requests 라이브러리를 사용하여 GET 메서드를 호출하고 텍스트 응답을 반환합니다. 또한 웹 서버로부터 오류 응답을 받지 않도록 GET 요청과 함께 User-Agent 헤더 요청을 전달합니다. User-Agent 헤더 전달은 선택 사항이지만, 일부 웹 서버는 알 수 없는 사용자 에이전트를 수신하면 요청을 거부할 수 있습니다.

페이지 콘텐츠에서 인용문과 저자를 추출하려면, BeautifulSoup을 사용하여 원시 HTML 데이터를 파싱하고 원하는 데이터를 반환하는 메서드를 정의하세요:

def get_quotes_and_authors(page_contents):
    soup = BeautifulSoup(page_contents, 'html.parser')
    quotes = soup.find_all('span', class_='text')
    authors = soup.find_all('small', class_='author')
    return quotes, authors

여기서 메서드는 get_page_contents 메서드에서 얻은 page_contents를 인수로 받습니다. 페이지 콘텐츠를 사용하여 BeautifulSoup 인스턴스를 생성하고 사용할 파서 유형을 지정합니다. 두 번째 인수를 생략하면 BeautifulSoup은 페이지 콘텐츠를 기반으로 기기에 설치된 최적의 파서를 자동으로 사용합니다.

그런 다음 soup 인스턴스를 사용하여 인용문과 저자에 대한 모든 요소를 찾고 find_all 메서드를 사용하여 태그를 기반으로 요소를 선택합니다. 마지막으로 검색 기준을 정교화하기 위해 CSS 선택기를 지정합니다.

이제 모든 것을 통합하여 main.py 파일 끝에 다음 코드 스니펫을 추가하세요:

if __name__ == '__main__':
    url = 'http://quotes.toscrape.com'
    page_contents = get_page_contents(url)
    
    if page_contents:
        quotes, authors = get_quotes_and_authors(page_contents)
        for i in range(len(quotes)):
            print(quotes[i].text)
            print(authors[i].text)
            print()
    else:
        print('페이지 콘텐츠를 가져오는 데 실패했습니다.')

이 코드는 get_page_contents를 사용하여 페이지 내용을 가져오고, 페이지 내용을 바탕으로 get_quotes_and_authors 메서드를 통해 모든 인용문과 저자를 추출합니다. 마지막으로 인용문 목록을 순회하며 결과를 출력합니다.

다음 명령어를 실행하여 스크립트를 테스트하세요:

python main.py

출력 결과는 다음과 같아야 합니다:

"우리가 창조한 세상은 우리의 사고 과정이다. 우리의 사고를 바꾸지 않고서는 세상을 바꿀 수 없다."
알버트 아인슈타인

--- 출력 생략 ---

"햇빛 없는 하루는, 말하자면, 밤과 같다."
스티브 마틴

보시다시피, 이제 스크래핑 스크립트를 성공적으로 만들었습니다. 더 배우고 싶다면, 고급 스크래핑 기법도 포함된 Python을 이용한 웹 스크래핑 가이드를 확인해 보세요.

여기서 사용된 모든 코드는 이 GitHub 저장소에서 확인할 수 있습니다.

일반적인 문제 처리

스크래핑하려는 웹 페이지의 복잡성에 따라 다음과 같은 문제를 겪을 수 있습니다:

동적 콘텐츠

일부 웹사이트는 정적 렌더링(여기서 사용한 ‘스크래핑할 인용문’ 웹 페이지처럼) 대신 자바스크립트를 사용해 동적으로 콘텐츠를 로드합니다. 예를 들어, Scraping Sandbox 홈페이지에는 동적으로 렌더링되는 동일한 웹 페이지의 자바스크립트 버전이 나열되어 있습니다. 이제 작성한 스크립트가 이 동적 콘텐츠에서 작동하는지 확인해 보세요.

main.py 스크립트 내 URL 을 다음과 같이 교체하세요:

# main.py 스크립트 내 URL 업데이트
url = 'https://quotes.toscrape.com/js/'

그런 다음 스크립트를 실행하세요. 출력이 비어 있음을 확인할 수 있습니다.

동적 콘텐츠를 렌더링하고 스크래핑하려면 Selenium과 같은 헤드리스 브라우저를 사용해야 합니다. 헤드리스 브라우저는 그래픽 사용자 인터페이스(GUI) 없이 실행되며, 널리 사용되는 웹 브라우저와 유사한 환경에서 웹 페이지를 자동으로 조작할 수 있게 합니다. Selenium은 실제 브라우저를 활용하여 웹 페이지를 렌더링함으로써 자바스크립트에 의존하는 웹 페이지를 스크래핑할 수 있게 합니다.

페이지네이션

동적 콘텐츠 외에도 웹 페이지에는 여러 방식으로 구현된 페이지네이션이 있을 수 있습니다. 데이터를 스크래핑하기 전에, 스크래핑하려는 웹사이트에서 페이지네이션이 어떻게 구현되었는지 이해해야 합니다.

일반적인 페이지 매김 기법은 다음과 같습니다:

표시자 또는 URL 패턴

웹 페이지에는 URL이 포함된 이전 /다음 페이지 마커가 있을 수 있습니다. 또한 웹사이트가 페이지네이션된 콘텐츠에 대해 특정 패턴을 따를 수도 있습니다. 예를 들어, ‘스크랩할 인용문 ‘ 페이지 하단에는 다음 페이지 마커가 있습니다.

Beautiful Soup 라이브러리를 사용해 다음 페이지 마커를 찾아 상대 경로를 획득하면, 다음 페이지의 URL을 구성하여 해당 데이터를 스크래핑할 수 있습니다.

무한 스크롤

무한 스크롤은 사용자가 아래로 스크롤할 때마다 웹 페이지가 더 많은 콘텐츠를 로드하는 방식입니다. 예를 들어, ToScrape 웹사이트에는 스크롤 버전 ‘스크랩할 인용문’ 페이지가 있으며, 스크롤할 때마다 더 많은 인용문이 로드됩니다. 이러한 웹 페이지의 경우 스크롤 기능이 있는 헤드리스 브라우저를 사용해야 합니다. Selenium의 스크롤 휠 액션을 사용하여 웹 페이지를 스크롤하고 더 많은 콘텐츠를 로드할 수 있습니다.

오류 처리

웹 스크래핑 중 원하는 요소가 누락되거나 불완전한 데이터가 포함될 수 있습니다. 일관된 결과를 보장하려면 이러한 상황을 처리하는 것이 중요합니다.

스크레이퍼 코드를 try-catch 블록으로 감싸면 예상치 못한 오류 발생 시 스크립트 중단을 방지할 수 있습니다. 예를 들어 Quotes to Scrape 웹사이트에서는 일부 명언에서 저자 이름이 누락될 수 있습니다. get_quotes_and_authors 메서드를 수정하여 try-catch 블록을 추가해 오류를 포착하고 기록할 수 있습니다:

def get_quotes_and_authors(page_contents):
    soup = BeautifulSoup(page_contents, 'html.parser')
    try:
        quotes = soup.find_all('span', class_='text')
        authors = soup.find_all('small', class_='author')
    except Exception as e:
    print(e)
    return None, None
return quotes, authors

보너스 섹션 – 팁과 트릭

이 섹션에서는 Beautiful Soup을 사용한 스크래핑 과정을 최적화하는 데 도움이 되는 몇 가지 흥미로운 트릭을 다룹니다.

문서에서 사용된 모든 태그 찾기

HTML 태그를 찾으려면 Python의 Beautiful Soup 같은 라이브러리를 활용할 수 있습니다. 한 가지 방법은 Beautiful Soup으로 HTML 파일을 읽고, 그 후 하위 요소들을 반복 처리하여 파일에 존재하는 모든 태그 목록을 추출하는 것입니다. Beautiful Soup에서 제공하는 soup.descendants 생성자를 사용하면 HTML 구조의 일부인 각 태그의 이름에 접근하고 출력할 수 있습니다. 이 과정은 HTML 파일을 열고, Beautiful Soup으로 파싱한 후, 하위 요소를 반복 처리하여 문서에서 발견된 HTML 태그의 이름을 식별하고 표시하는 것을 포함합니다.

HTML 태그에서 전체 콘텐츠 추출하기

이 작업을 수행하는 단계별 안내는 다음과 같습니다:

  1. HTML 및 XML 문서 파싱에 사용되는 필수 라이브러리인 BeautifulSoup을 먼저 임포트합니다.
  2. 추출하려는 콘텐츠가 포함된 HTML 파일을 엽니다. Python의 파일 처리 기능을 사용하여 수행할 수 있습니다. 파일 내용을 읽고 변수에 저장합니다.
  3. HTML 파일 내용과 지정된 파서(이 경우 “html.parser”)를 제공하여 BeautifulSoup 객체를 생성합니다.
  4. BeautifulSoup 객체가 생성되면, 문서 내 특정 HTML 태그를 해당 태그 이름을 속성으로 사용하여 접근할 수 있습니다. 예를 들어, h2 태그 내 콘텐츠를 추출하려면 soup.h2를 사용해 접근할 수 있습니다.
  5. 마찬가지로, 각각 soup.p와 soup.li를 사용하여 단락(<p>)과 목록 항목(<li>) 내의 내용을 추출할 수 있습니다.
  6. 마지막으로, 이러한 지시문을 실행하면 문서에 나타나는 순서대로 지정된 HTML 태그의 전체 내용을 출력할 수 있습니다.

이러한 단계를 따르고 BeautifulSoup 라이브러리를 활용하면 HTML 문서에 존재하는 HTML 태그의 전체 내용을 효과적으로 추출할 수 있습니다.

윤리적 고려 사항

데이터를 스크래핑하기 전에, 정의된 제한 사항에 따라 스크립트를 정의하여 웹사이트의 서비스 약관을 검토하고 준수해야 합니다. 스크래핑하는 동안 대상 웹사이트의 robot.txt에 정의된 규칙을 따라야 합니다.

또한, 개인정보 보호 규정을 위반할 수 있으므로 동의 없이 개인정보를 수집하지 않도록 주의해야 합니다.

서버 과부하를 유발하거나 사이트 성능에 영향을 줄 수 있는 공격적인 스크래핑도 피해야 합니다. 웹 서버는 속도 제한 적용, CAPTCHA 표시, IP 주소 차단 등의 보호 조치를 시행할 수 있습니다. 가능하다면 출처 웹사이트에 대한 출처를 명시하여 해당 웹사이트가 제공한 노력과 콘텐츠를 인정해야 합니다.

웹 스크래핑 최적화

웹 스크래핑 스크립트의 신뢰성과 효율성을 높이기 위해 다음 기법 중 일부를 구현하는 것을 고려하십시오:

병렬화 활용

중첩된 데이터 처리를 위해 다중 스레드를 활용하여 스크립트에서 병렬화를 고려하십시오. 예를 들어, ‘스크래핑할 인용문’ 웹 페이지에서 모든 인용문 div 블록을 찾아내고 div 블록을 병렬로 처리하도록 스크립트를 수정할 수 있습니다. DOM 트리가 복잡한 경우 이 기법은 스크립트 실행 속도를 크게 향상시킬 수 있습니다.

재시도 로직 추가

스크립트에 네트워크 호출에 대한 재시도 로직을 추가하면 신뢰성을 높일 수 있습니다. 예를 들어, 이 사용 사례에서는 get_page_contents에 재시도 로직을 추가하여 페이지 콘텐츠를 처음 시도할 때 가져올 수 없더라도 스크립트가 실패하지 않도록 할 수 있습니다.

사용자 에이전트 순환

웹 서버가 동일한 사용자 에이전트로부터 대량의 요청을 수신하면 요청을 차단할 수 있습니다. 이 문제를 해결하려면 요청마다 새로운 User-agent를 생성하여 사용자 에이전트를 순환할 수 있습니다. get_page_contents 메서드는 requests.get API 호출에 정적 User-agent 헤더를 전달합니다. 동적 사용자 에이전트를 생성하는 get_random_user_agent라는 메서드를 정의할 수 있습니다.

속도 제한 구현

짧은 시간 내에 너무 많은 요청을 보내면 웹 서버가 요청을 차단하거나 거부할 수 있습니다. 이 문제를 해결하려면 요청 사이에 수동 지연을 구현할 수 있습니다.

프록시 서버 사용

스크래핑 스크립트와 대상 페이지 사이에 프록시 서버를 중개자로 활용할 수 있습니다. 프록시 서버는 웹 페이지 콘텐츠를 가져오는 요청 시 IP 주소를 순환시켜 IP 차단(IP bans)을 피하는 데 도움이 됩니다. Python IP 순환에 대해 자세히 알아보세요.

Bright Data는 다양한 프록시 네트워크, 강력한 웹 스크레이퍼, 즉시 사용 가능한 다운로드용 데이터 세트를 제공합니다. Bright Data는 또한 주거용, 데이터센터, ISP, 모바일 프록시를 포함한 여러 프록시 서비스를 제공하여 웹 스크레이핑 요구 사항에 부응합니다. 웹 스크레이핑을 한 단계 업그레이드하고 싶다면 Bright Data를 고려해 보세요.

결론

Beautiful Soup은 웹 스크래핑에 유용한 도구로, 다양한 XML 및 HTML 파서와 원활하게 통합됩니다. 스크래핑할 데이터를 식별하고 웹 페이지 구조를 이해한 후에는 Beautiful Soup Python 라이브러리를 활용해 신속하게 스크립트를 작성할 수 있습니다. 다만 웹 페이지의 복잡성에 따라 동적 콘텐츠, 페이지네이션, 오류 처리와 관련된 문제를 해결해야 할 수도 있습니다.

개발 노력을 줄이고 스크래핑 규모를 확장하려면 차단 방지 프록시 인프라 위에 구축된 서버리스 함수 제품을 고려해 보세요. 인기 웹사이트에서 가져온 사전 구축된 자바스크립트 함수와 코드 템플릿이 포함되어 있습니다. 프로덕션 환경에 바로 적용 가능한 API를 갖춘 간편한 자동화 솔루션을 찾고 계신가요? 새로운 웹 스크래핑 API를 사용해 보세요.

또한 Bright Data 프록시 서비스는 195개국 프록시를 통해 지역 제한을 우회할 수 있는 효율적인 성능의 고급 프록시 인프라를 제공합니다. 일반 데이터 보호 규정(GDPR) 및 캘리포니아 소비자 개인정보 보호법(CCPA)을 준수하며, 모든 주요 프로그래밍 언어와 호환됩니다.