파이썬을 이용한 웹 스크래핑: 다양한 예제가 포함된 완전한 튜토리얼

인기 있는 라이브러리와 프레임워크를 활용하여 정적 및 동적 사이트 모두에 대한 실제 웹 스크래핑 프로젝트를 Python으로 설정, 코딩 및 실행하는 방법을 배우십시오.
10 분 읽기
Web Scraping With Python blog image

이 튜토리얼에서는 다음을 배웁니다:

  • 웹 스크래핑이 주로 파이썬으로 수행되는 이유와 이 프로그래밍 언어가 해당 작업에 적합한 이유.
  • 파이썬에서 정적 사이트와 동적 사이트 스크래핑의 차이점.
  • 파이썬 웹 스크레이퍼 프로젝트 설정 방법.
  • 파이썬으로 정적 사이트를 스크래핑하는 데 필요한 사항.
  • 다양한 Python HTTP 클라이언트를 사용하여 웹 페이지의 HTML을 다운로드하는 방법.
  • 인기 있는 Python HTML 파서로 HTML을 파싱하는 방법.
  • Python에서 동적 사이트를 스크래핑하는 데 필요한 사항.
  • 다양한 도구를 사용하여 Python에서 웹 스크래핑을 위한 데이터 추출 로직 구현 방법.
  • 스크랩한 데이터를 CSV 및 JSON으로 내보내는 방법.
  • Requests + Beautiful Soup, Playwright 및 Selenium을 사용한 완벽한 Python 웹 스크래핑 예제.
  • 페이지가 있는 사이트의 모든 데이터를 스크래핑하는 단계별 섹션.
  • Scrapy가 제공하는 독특한 웹 스크래핑 접근 방식.
  • Python에서 일반적인 웹 스크래핑 문제를 처리하는 방법.

자, 시작해 보겠습니다!

파이썬에서 웹 스크래핑이란 무엇인가?

웹 스크래핑은 일반적으로 자동화 도구를 사용하여 웹사이트에서 데이터를 추출하는 과정입니다. Python 환경에서 웹 스크래핑을 수행한다는 것은 하나 이상의 사이트에 걸쳐 하나 이상의 웹 페이지에서 데이터를 자동으로 가져오는 Python 스크립트를 작성하는 것을 의미합니다.

파이썬은 웹 스크래핑에 가장 널리 쓰이는 프로그래밍 언어 중 하나입니다. 이는 파이썬의 광범위한 채택과 강력한 생태계 덕분입니다. 구체적으로, 파이썬은 강력한 스크래핑 라이브러리를 다수 제공합니다.

파이썬의 거의 모든 웹 스크래핑 도구를 탐색하고 싶다면, 저희의 전용 파이썬 웹 스크래핑 GitHub 저장소를 살펴보세요.

이제 파이썬에서의 웹 스크래핑 과정은 다음 네 단계로 요약할 수 있습니다:

  1. 대상 페이지에 연결합니다.
  2. HTML 콘텐츠를 파싱합니다.
  3. 관심 있는 HTML 요소를 찾아 원하는 데이터를 추출하는 데이터 추출 로직 구현.
  4. 스크래핑된 데이터를 CSV나 JSON과 같이 접근성이 더 높은 형식으로 내보냅니다.

위 단계에 필요한 구체적인 기술과 적용 기법은 웹 페이지가 정적인지 동적인지에 따라 달라집니다. 따라서 다음으로 이를 살펴보겠습니다.

파이썬 웹 스크래핑: 정적 사이트 대 동적 사이트

웹 스크래핑에서 스크래핑 봇을 구축하는 방식을 결정하는 가장 큰 요소는 대상 사이트가 정적인지 동적인지 여부입니다.

정적 사이트의 경우 서버가 반환하는 HTML 문서에 원하는 데이터의 전부(또는 대부분)가 이미 포함되어 있습니다. 일부 사소한 클라이언트 측 상호작용을 위해 자바스크립트를 사용할 수는 있지만, 서버에서 수신하는 콘텐츠는 기본적으로 브라우저에 표시되는 페이지 전체입니다.

An example of a static site. What you see in the browser is what you get from the server

반면 동적 사이트는 브라우저에서 데이터를 로드하거나 렌더링하는 데 자바스크립트에 크게 의존합니다. 서버가 반환하는 초기 HTML 문서에는 실제 데이터가 거의 포함되지 않는 경우가 많습니다. 대신 데이터는 첫 페이지 로드 시 또는 사용자 상호작용( 무한 스크롤링이나 동적 페이지네이션 등) 후에 자바스크립트를 통해 가져와 렌더링됩니다.

An example of a dynamic site. Note the dynamic data loading

자세한 내용은 웹 스크래핑을 위한 정적 콘텐츠 대 동적 콘텐츠 가이드를 참조하세요.

상상할 수 있듯이, 이 두 시나리오는 매우 다르며 별도의 Python 스크래핑 스택이 필요합니다. 이 튜토리얼의 다음 장에서는 Python으로 정적 및 동적 사이트를 모두 스크래핑하는 방법을 배우게 됩니다. 마지막에는 완전한 실제 사례도 확인할 수 있습니다.

웹 스크래핑 파이썬 프로젝트 설정

대상 사이트가 정적 페이지든 동적 페이지든, 스크래핑을 위해서는 파이썬 프로젝트 설정이 필요합니다. 따라서 파이썬으로 웹 스크래핑 환경을 준비하는 방법을 살펴보겠습니다.

필수 조건

Python 웹 스크레이퍼를 구축하려면 다음 사전 조건이 필요합니다:

  • 로컬에 설치된 Python 3+
  • 로컬에pip 설치

참고: pip는 2014년에 출시된 버전 3.4부터 파이썬에 기본 포함되어 있으므로 별도로 설치할 필요가 없습니다.

대부분의 시스템에는 이미 Python이 사전 설치되어 있다는 점을 유념하세요. 설치 여부는 다음 명령어로 확인할 수 있습니다:

python3 --version

일부 시스템에서는 다음 명령을 사용하세요:

python --version

다음과 유사한 출력이 표시됩니다:

Python 3.13.1

“명령을 찾을 수 없음” 오류가 발생하면 Python이 설치되지 않았음을 의미합니다. 이 경우 공식 Python 웹사이트에서 다운로드하여 운영 체제에 맞는 설치 지침을 따르세요.

필수 사항은 아니지만, Python 코드 편집기나 IDE를 사용하면 개발이 더 수월해집니다. 추천하는 도구는 다음과 같습니다:

이러한 도구를 사용하면 구문 강조, 린팅, 디버깅 및 기타 도구를 활용하여 Python 스크레이퍼를 훨씬 원활하게 작성할 수 있습니다.

참고: 본 튜토리얼을 따라하려면 웹 작동 방식과 CSS 선택기 기능에 대한 기본적인 이해가 필요합니다.

프로젝트 설정

터미널을 열고 Python 스크래핑 프로젝트용 폴더를 생성한 후 해당 폴더로 이동하세요:

mkdir python-web-scraper
cd python-web-scraper

다음으로 이 폴더 안에 Python 가상 환경을 생성하세요:

python -m venv venv

가상 환경을 활성화합니다. Linux 또는 macOS에서는 다음을 실행하세요:

source venv/bin/activate

Windows에서는 동일하게 다음을 실행합니다:

venvScriptsactivate

가상 환경이 활성화된 상태에서 웹 스크래핑에 필요한 모든 패키지를 로컬에 설치할 수 있습니다.

이제 선호하는 Python IDE에서 이 프로젝트 폴더를 엽니다. 그런 다음 scraper.py라는 새 파일을 생성하세요. 웹 데이터를 가져오고 파싱하기 위한 Python 코드를 여기에 작성하게 됩니다.

이제 Python 웹 스크래핑 프로젝트 디렉터리는 다음과 같아야 합니다:

python-web-scraper/
├── venv/          # 가상 환경
└── scraper.py     # Python 스크래핑 스크립트

훌륭합니다! 이제 Python 스크레이퍼 코딩을 시작할 준비가 모두 완료되었습니다.

파이썬으로 정적 사이트 스크래핑하기

정적 웹 페이지를 다룰 때는 서버가 반환하는 HTML 문서에 스크래핑하려는 모든 데이터가 이미 포함되어 있습니다. 따라서 이러한 시나리오에서는 다음 두 가지 구체적인 단계를 기억해야 합니다:

  1. HTTP 클라이언트를 사용하여 페이지의 HTML 문서를 가져옵니다. 이는 브라우저가 웹 서버에 보내는 요청을 재현하는 것입니다.
  2. HTML 파서를 사용하여 해당 HTML 문서의 내용을 처리하고 데이터를 추출할 준비를 합니다.

그런 다음 특정 데이터를 추출하여 사용자가 쉽게 활용할 수 있는 형식으로 내보내야 합니다. 높은 수준에서 이러한 작업은 정적 사이트와 동적 사이트 모두 동일합니다. 따라서 후반부에 이에 집중하겠습니다.

따라서 정적 사이트의 경우 일반적으로 다음을 결합합니다:

  1. 웹 페이지를 다운로드하기 위한 Python HTTP 클라이언트.
  2. HTML 구조를 파싱하고 탐색하며 데이터를 추출하는 파이썬 HTML 파서.

샘플 정적 사이트로, 앞으로는 ‘스크래핑할 인용문 ‘ 페이지를 참조하겠습니다:

The target static site

이 페이지는 웹 스크래핑 연습을 위해 설계된 간단한 정적 웹 페이지입니다. 브라우저에서 페이지 위를 마우스 오른쪽 버튼으로 클릭하고 “페이지 소스 보기” 옵션을 선택하면 정적 페이지임을 확인할 수 있습니다. 다음과 같은 내용이 표시됩니다:

The HTML of the target static page

보시는 내용은 브라우저에서 렌더링되기 전 서버가 반환한 원본 HTML 문서입니다. 페이지에 표시된 모든 인용문 데이터가 이미 포함되어 있음을 유의하세요.

다음 세 장에서는 다음을 배우게 됩니다:

  1. 파이썬 HTTP 클라이언트를 사용하여 이 정적 페이지의 HTML 문서를 다운로드하는 방법.
  2. HTML 파서로 이를 파싱하는 방법.
  3. 전용 스크래핑 프레임워크에서 두 단계를 함께 수행하는 방법.

이를 통해 정적 사이트용 완전한 Python 스크래퍼를 구축할 준비가 될 것입니다.

대상 페이지의 HTML 문서 다운로드

파이썬에는 여러 HTTP 클라이언트가 있지만, 가장 널리 사용되는 세 가지는 다음과 같습니다:

  • requests: HTTP 요청 전송을 매우 간단하게 만드는 간단하고 우아한 Python용 HTTP 라이브러리입니다. 동기식이며 널리 채택되어 있으며 대부분의 중소 규모 스크래핑 작업에 적합합니다.
  • httpx: requests의 개념을 기반으로 하지만 동기식 및 비동기식 사용, HTTP/2, 연결 풀링을 모두 지원하는 차세대 HTTP 클라이언트입니다.
  • aiohttp: asyncio를 위해 구축된 비동기 HTTP 클라이언트(및 서버) 프레임워크입니다. 다중 요청을 병렬로 실행해야 하는 고동시성 스크래핑 시나리오에 이상적입니다.

Requests vs HTTPX vs AIOHTTP 비교에서 이들의 차이점을 확인해 보세요.

다음으로, 이러한 라이브러리를 설치하고 대상 페이지의 HTML 문서를 가져오기 위해 HTTP GET 요청을 수행하는 방법을 살펴보겠습니다.

Requests

다음 명령어로 Requests 설치:

pip install requests

다음과 같이 대상 웹 페이지의 HTML을 가져오세요:

import requests

url = "http://quotes.toscrape.com/"
response = requests.get(url)
html = response.text

# HTML 파싱 로직...

get() 메서드는 지정된 URL로 HTTP GET 요청을 수행합니다. 웹 서버는 해당 페이지의 HTML 문서로 응답합니다.

추가 자료:

HTTPX

HTTPX 설치 방법:

pip install httpx

다음과 같이 대상 페이지의 HTML을 가져오기 위해 활용하세요:

import httpx

url = "http://quotes.toscrape.com/"
response = httpx.get(url)
html = response.text

# HTML 파싱 로직...

보시다시피, 이 간단한 시나리오에서는 API가 Requests와 동일합니다. HTTPX가 Requests보다 갖는 주요 장점은 비동기 지원도 제공한다는 점입니다.

추가 자료:

AIOHTTP

AIOHTTP 설치 방법:

pip install aiohttp

다음과 같이 비동기적으로 대상 URL에 연결하도록 채택하세요:

import asyncio
import aiohttp

async def main():
    async with aiohttp.ClientSession() as session:
        url = "http://quotes.toscrape.com/"
        async with session.get(url) as response:
            html = await response.text()

            # HTML 파싱 로직...

asyncio.run(main())

위 코드 조각은 AIOHTTP를 사용하여 비동기 HTTP 세션을 생성합니다. 그런 다음 이를 활용하여 지정된 URL로 GET 요청을 전송하고 서버의 응답을 기다립니다. 비동기 리소스의 적절한 개방 및 폐쇄를 보장하기 위해 async with 블록을 사용하는 점에 유의하십시오.

AIOHTTP는 기본적으로 비동기적으로 작동하므로 Python 표준 라이브러리의 asyncio를 임포트하여 사용해야 합니다.

추가 자료:

파이썬으로 HTML 파싱하기

현재 html 변수는 서버에서 반환된 HTML 문서의 원시 텍스트만 포함하고 있습니다. 이를 확인하려면 다음과 같이 출력해 보세요:

print(html)

터미널에 다음과 같은 출력이 표시됩니다:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>스크래핑할 인용문</title>
    <link rel="stylesheet" href="/static/bootstrap.min.css">
    <link rel="stylesheet" href="/static/main.css">
</head>
<body>
    <!-- 생략... -->

HTML 노드를 프로그래밍 방식으로 선택하고 데이터를 추출하려면 이 HTML 문자열을 탐색 가능한 DOM 구조로 파싱해야 합니다.

파이썬에서 가장 널리 쓰이는 HTML 파싱 라이브러리는 Beautiful Soup입니다. 이 패키지는 HTML 또는 XML 파서 위에 구축되어 웹 페이지에서 정보를 쉽게 추출할 수 있게 합니다. 파싱 트리를 반복, 검색, 수정하기 위한 파이썬식 메서드를 제공합니다.

덜 흔하지만 여전히 강력한 또 다른 옵션은 PyQuery입니다. 이 라이브러리는 HTML을 파싱하고 쿼리하기 위한 jQuery와 유사한 구문을 제공합니다.

다음 두 장에서는 HTML 문자열을 파싱된 트리 구조로 변환하는 방법을 살펴볼 것입니다. 이 트리에서 특정 데이터를 추출하는 실제 로직은 나중에 소개됩니다.

Beautiful Soup

먼저 Beautiful Soup을 설치하세요:

pip install beautifulsoup4

그런 다음 다음과 같이 HTML을 파싱하는 데 사용하세요:

from bs4 import BeautifulSoup

# HTML 가져오기 로직...

soup = BeautifulSoup(html, "html.parser")

# 데이터 추출 로직...

위 코드 조각에서 "html.parser" 는 Beautiful Soup가 HTML 문자열을 파싱하는 데 사용하는 기본 파서 이름입니다. 구체적으로 html.parser는 Python 표준 라이브러리에 포함된 기본 HTML 파서입니다.

성능 향상을 위해 lxml을 사용하는 것이 좋습니다. Beautiful Soup과 lxml은 다음과 같이 설치할 수 있습니다:

pip install beautifulsoup4 lxml

그런 다음 파싱 로직을 다음과 같이 업데이트하세요:

soup = BeautifulSoup(html, "lmxl")

이제 soup은 Beautiful Soup의 API를 사용하여 태그 찾기, 텍스트 추출, 속성 읽기 등을 수행할 수 있는 파싱된 DOM과 유사한 트리 구조입니다.

추가 자료:

PyQuery

pip으로 PyQuery 설치:

pip install pyquery

다음과 같이 HTML을 파싱하는 데 사용:

from pyquery import PyQuery as pq

# HTML 가져오기 로직...

d = pq(html)

# 데이터 추출 로직...

d는 파싱된 DOM과 유사한 트리를 포함하는 PyQuery 객체입니다. CSS 선택자를 적용하여 탐색하고 jQuery와 유사한 구문을 사용하여 메서드를 연쇄적으로 호출할 수 있습니다.

Python으로 동적 사이트 스크래핑하기

동적 웹 페이지를 다룰 때, 서버가 반환하는 HTML 문서는 종종 최소한의 골격에 불과합니다. 여기에는 브라우저가 데이터를 가져오고 페이지 콘텐츠를 동적으로 생성하거나 업데이트하기 위해 실행하는 많은 자바스크립트가 포함됩니다.

동적 페이지를 완전히 렌더링할 수 있는 것은 브라우저뿐이므로, 파이썬으로 동적 사이트를 스크래핑하려면 브라우저에 의존해야 합니다. 특히 브라우저 자동화 도구를 사용해야 합니다. 이 도구들은 웹 브라우저를 프로그래밍 방식으로 제어할 수 있는 API를 제공합니다.

이 경우 웹 스크래핑은 일반적으로 다음으로 귀결됩니다:

  1. 관심 있는 페이지를 방문하도록 브라우저에 지시합니다.
  2. 동적 콘텐츠가 로드되기를 기다리거나 선택적으로 사용자 상호작용을 시뮬레이션합니다.
  3. 완전히 렌더링된 페이지에서 데이터를 추출합니다.

브라우저 자동화 도구는 일반적으로 헤드리스 모드에서 브라우저를 제어합니다. 즉, GUI 없이 브라우저가 작동한다는 의미입니다. 이는 많은 리소스를 절약해주며, 대부분의 브라우저가 리소스를 많이 소모한다는 점을 고려할 때 중요합니다.

이번에는 ‘추출할 인용문’ 페이지의 동적 버전을 대상으로 합니다:

The target dynamic page

이 버전은 AJAX를 통해 인용문 데이터를 가져오고 JavaScript를 사용하여 페이지에 동적으로 렌더링합니다. 개발자 도구에서 네트워크 요청을 확인하여 이를 검증할 수 있습니다:

The AJAX request made by the page to retrieve the quotes data

현재 Python에서 가장 널리 사용되는 두 가지 브라우저 자동화 도구는 다음과 같습니다:

  • Playwright: 마이크로소프트에서 개발한 현대적인 브라우저 자동화 라이브러리입니다. 크로미움, 파이어폭스, 웹킷을 지원합니다. 빠르고 강력한 선택기를 제공하며 동적 콘텐츠 대기 기능을 내장하고 있습니다.
  • Selenium: 스크래핑 및 테스트 용도로 파이썬에서 브라우저 자동화를 위한 확립되고 널리 채택된 프레임워크입니다.

Playwright와 Selenium 비교를 통해 두 솔루션을 자세히 살펴보세요.

다음 섹션에서는 이 도구들을 설치하고 구성하는 방법을 살펴보겠습니다. 제어된 Chrome 인스턴스가 대상 페이지로 이동하도록 지시하는 데 이 도구들을 활용할 것입니다.

참고: 이번에는 별도의 HTML 파싱 단계가 필요하지 않습니다. 브라우저 자동화 도구가 DOM에서 노드를 선택하고 데이터를 추출하기 위한 직접적인 API를 제공하기 때문입니다.

Playwright

Playwright 설치 방법:

pip install playwright

그런 다음 모든 Playwright 종속성(예: 브라우저 바이너리, 브라우저 드라이버 등)을 설치해야 합니다:

python -m playwright install

Playwright를 사용하여 헤드리스 Chromium 인스턴스가 아래와 같이 대상 동적 페이지에 연결하도록 지시하세요:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # 제어 가능한 Chromium 인스턴스를 헤드리스 모드로 열기
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()

    # 대상 페이지 방문
    url = "http://quotes.toscrape.com/scroll"
    page.goto(url)

    # 데이터 추출 로직...
    # 데이터 내보내기 로직...

    # 브라우저 닫기 및 리소스 해제
    browser.close()

이 코드는 헤드리스 Chromium 브라우저를 열고 goto() 메서드를 사용하여 해당 페이지로 이동합니다.

추가 자료:

Selenium

Selenium 설치 방법:

pip install selenium

참고: 과거에는 브라우저 드라이버(예: 크롬 브라우저 제어용 ChromeDriver )를 수동으로 설치해야 했습니다. 그러나 최신 Selenium 버전(4.6 이상)에서는 더 이상 필요하지 않습니다. Selenium은 이제 설치된 브라우저에 적합한 드라이버를 자동으로 관리합니다. 로컬에 Google Chrome만 설치되어 있으면 됩니다.

다음과 같이 Selenium을 활용하여 동적 웹 페이지에 연결하세요:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# 헤드리스 모드로 Chrome 인스턴스 실행
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)

# 대상 페이지 방문
url = "http://quotes.toscrape.com/scroll"
driver.get(url)

# 데이터 추출 로직...
# 데이터 내보내기 로직...

# 브라우저 종료 및 리소스 정리
driver.quit()

Playwright와 비교했을 때, Selenium에서는 Chrome CLI 플래그를 사용해 헤드리스 모드를 명시적으로 설정해야 합니다. 또한 브라우저에 URL로 이동하라고 지시하는 방법은 get()입니다.

추가 자료:

Python 웹 데이터 파싱 로직 구현하기

이전 단계에서는 정적/동적 페이지의 HTML을 각각 파싱/렌더링하는 방법을 배웠습니다. 이제 그 HTML에서 실제로 데이터를 스크래핑하는 방법을 살펴볼 차례입니다.

첫 번째 단계는 대상 페이지의 HTML에 익숙해지는 것입니다. 특히 원하는 데이터를 포함하는 요소에 집중하세요. 이 경우, 대상 페이지에서 모든 인용문(텍스트와 저자)을 스크래핑한다고 가정합니다.

브라우저에서 페이지를 열고, 인용문 요소를 마우스 오른쪽 버튼으로 클릭한 후 “검사” 옵션을 선택하세요:

The quote HTML elements

각 인용문이 .quote CSS 클래스를 가진 HTML 요소로 감싸져 있음을 확인하세요.

다음으로, 단일 인용문의 HTML을 확장합니다:

The HTML of a single quote element

다음과 같은 내용을 확인할 수 있습니다:

  • 인용문 텍스트는 .text HTML 요소 안에 있습니다.
  • 저자 이름은 .author HTML 노드 안에 있습니다.

페이지에 여러 인용문이 포함되어 있으므로 이를 저장할 데이터 구조도 필요합니다. 간단한 리스트가 적합합니다:

quotes = []

요약하면, 전체 데이터 추출 계획은 다음과 같습니다:

  1. 페이지 내 모든 .quote 요소를 선택합니다.
  2. 각 인용문을 순회하며:
    1. .text 노드에서 인용문 텍스트 추출
    2. .author 노드에서 저자 이름을 추출합니다.
    3. 추출한 인용문과 저자로 새 사전 생성
    4. 인용문 목록에 추가합니다.

이제 Beautiful Soup, PyQuery, Playwright, Selenium을 사용하여 위의 Python 웹 데이터 추출 로직을 구현하는 방법을 살펴보겠습니다.

Beautiful Soup

Beautiful Soup으로 데이터 추출 로직 구현:

# HTML 가져오기 로직...

# 추출된 데이터 저장 위치
quotes = []

# 페이지 내 모든 인용문 HTML 요소 선택
quote_elements = soup.select(".quote")
for quote_element in quote_elements:
    # 인용문 텍스트 추출
    text_element = quote_element.select_one(".text")
    text = text_element.get_text(strip=True)

    # 저자 이름 추출
    author_element = quote_element.select_one(".author")
    author = author_element.get_text(strip=True)

    # 추출된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }
    # 목록에 추가
    quotes.append(quote)

# 데이터 내보내기 로직...

위 코드 조각은 select() 메서드를 호출하여 지정된 CSS 선택자와 일치하는 모든 HTML 요소를 찾습니다. 그런 다음 해당 요소 각각에 대해 select_one()으로 특정 데이터 노드를 선택합니다. 이 메서드는 select() 와 동일하게 작동하지만 결과를 단일 노드로 제한합니다.

다음으로 get_text()를 사용해 현재 노드의 내용을 추출합니다. 스크랩된 데이터로 사전(dictionary)을 생성하고 quotes 목록에 추가합니다.

(단계별 섹션에서 나중에 보게 되겠지만) find_all()find() 를 사용해도 동일한 결과를 얻을 수 있습니다.

PyQuery

PyQuery를 사용하여 데이터 추출 코드를 다음과 같이 작성하세요:

# HTML 가져오기 로직...

# 스크랩된 데이터 저장 위치
quotes = []

# 페이지의 모든 quote HTML 요소 선택
quote_elements = d(".quote")
for quote_element in quote_elements:
    # PyQuery 메서드 사용을 위해 요소를 다시 PyQuery로 감쌈
    q = d(quote_element)

    # 인용문 텍스트 추출
    text = q(".text").text().strip()

    # 저자 이름 추출
    author = q(".author").text().strip()

    # 스크랩된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }

    # 목록에 추가
    quotes.append(quote)

# 데이터 내보내기 로직...

구문 구조가 jQuery와 얼마나 유사한지 주목하세요.

Playwright

Playwright에서 Python 데이터 추출 로직을 구축하려면:

# 페이지 방문 로직...

# 스크랩된 데이터 저장 위치
quotes = []

# 페이지 내 모든 quote HTML 요소 선택
quote_elements = page.locator(".quote")
# quote 요소가 페이지에 나타날 때까지 대기
quote_elements.first.wait_for()

# 각 quote 요소를 반복 처리
for quote_element in quote_elements.all():
    # quote 텍스트 추출
    text_element = quote_element.locator(".text")
    text = text_element.text_content().strip()

    # quote 저자 추출
    author_element = quote_element.locator(".author")
    author = author_element.text_content().strip()

    # 추출된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }

    # 목록에 추가
    quotes.append(quote)

# 데이터 내보내기 로직...

이 경우 동적 페이지에서 작업 중임을 기억하세요. 즉, CSS 선택자를 적용할 때 인용문 요소가 즉시 렌더링되지 않을 수 있습니다(JavaScript를 통해 동적으로 로드되기 때문).

Playwright는 대부분의 로케이터 작업에 자동 대기 메커니즘을 구현하지만, 이는 all() 메서드에는 적용되지 않습니다. 따라서 all()을 호출하기 전에 wait_for()를 사용하여 인용문 요소가 페이지에 나타날 때까지 수동으로 대기해야 합니다. wait_for()는 최대 30초까지 자동으로 대기합니다.

참고: Playwright의 엄격 모드 위반을 방지하려면 wait_for()는 반드시 단일 로케이터에 대해 호출해야 합니다. 따라서 먼저 .first를 사용하여 단일 로케이터에 접근해야 합니다.

Selenium

Selenium을 사용하여 데이터를 추출하는 방법은 다음과 같습니다:

# 페이지 방문 로직...

# 스크랩된 데이터 저장 위치
quotes = []

# 페이지에 인용문 요소가 나타날 때까지 대기 (기본값 최대 30초)
wait = WebDriverWait(driver, 30)
quote_elements = wait.until(
    EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".quote")))


# 각 quote 요소를 반복 처리
for quote_element in quote_elements:
    # 명언 텍스트 추출
    text_element = quote_element.find_element(By.CSS_SELECTOR, ".text")
    text = text_element.text.strip()

    # 저자 이름 추출
    author_element = quote_element.find_element(By.CSS_SELECTOR, ".author")
    author = author_element.text.strip()

    # 추출된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }

    # 목록에 추가
    quotes.append(quote)

# 데이터 내보내기 로직...

이번에는 Selenium의 예상 조건 메커니즘을 사용하여 페이지에 인용문 요소가 나타날 때까지 기다릴 수 있습니다. 이는 WebDriverWait와 presence_of_all_elements_located() 를 함께 사용하여 .quote 선택자와 일치하는 모든 요소가 DOM에 존재할 때까지 대기합니다.

위 코드에는 다음 세 가지 추가 임포트가 필요합니다:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

스크랩된 데이터 내보내기

현재 스크랩된 데이터는 quotes 리스트에 저장되어 있습니다. 일반적인 Python 웹 스크래핑 워크플로를 완료하려면 마지막 단계로 이 데이터를 CSV나 JSON과 같은 접근성이 더 좋은 형식으로 내보내야 합니다.

Python에서 두 가지 방법을 모두 확인해 보세요!

CSV로 내보내기

스크랩한 데이터를 CSV로 내보내려면:

import csv

# Python 스크래핑 로직...

with open("quotes.csv", mode="w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["text", "author"])
    writer.writeheader()
    writer.writerows(quotes)

이 코드는 Python의 내장 csv 라이브러리를 사용하여 인용문 목록을 quotes.csv라는 출력 파일에 기록합니다. 파일에는 text와 author라는 열 헤더가 포함됩니다.

JSON으로 내보내기

스크래핑한 인용문 데이터를 JSON 파일로 내보내려면 다음을 사용하세요:

import json

# Python 스크래핑 로직...

with open("quotes.json", mode="w", encoding="utf-8") as file:
    json.dump(quotes, file, indent=4, ensure_ascii=False)

이렇게 하면 JSON 형식의 명언 목록이 담긴 quotes.json 파일이 생성됩니다.

완벽한 Python 웹 스크래핑 예제

이제 Python으로 웹 스크래핑을 수행하는 데 필요한 모든 구성 요소를 갖추셨습니다. 마지막 단계는 Python 프로젝트 내의 scraper.py 파일에 모든 것을 통합하는 것입니다.

참고: 보다 단계별 접근을 선호한다면 다음 장으로 건너뛰세요.

아래에서는 Python에서 가장 흔히 사용되는 스크래핑 스택을 활용한 완전한 예제를 확인할 수 있습니다. 실행하려면 필요한 라이브러리를 설치하고, 코드를 scraper.py에 복사한 후 다음 명령어로 실행하세요:

python3 scraper.py

또는 Windows 및 기타 시스템에서는 다음과 같이 실행하세요:

python scraper.py

스크립트 실행 후 프로젝트 폴더에 quotes.csv 파일 또는 quotes.json 파일이 생성됩니다.

quotes.csv 파일은 다음과 같습니다:

The quotes.csv output file

quotes.json 파일에는 다음과 같은 내용이 포함됩니다:

The quotes.json output file

이제 완전한 웹 스크래핑 Python 예제를 확인해 볼 시간입니다!

Requests + Beautiful Soup

# pip install requests beautifulsoup4 lxml

import requests
from bs4 import BeautifulSoup
import csv

# 대상 페이지의 HTML 가져오기
url = "http://quotes.toscrape.com/"
response = requests.get(url)
html = response.text

# HTML 파싱
soup = BeautifulSoup(html, "lxml")

# 추출된 데이터 저장 위치
quotes = []

# 페이지 내 모든 인용문 HTML 요소 선택
quote_elements = soup.select(".quote")
for quote_element in quote_elements:
    # 인용문 텍스트 추출
    text_element = quote_element.select_one(".text")
    text = text_element.get_text(strip=True)

    # 저자 이름 추출
    author_element = quote_element.select_one(".author")
    author = author_element.get_text(strip=True)

    # 추출된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }
    # 목록에 추가
    quotes.append(quote)

# 추출한 데이터를 CSV로 내보내기
with open("quotes.csv", mode="w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["text", "author"])
    writer.writeheader()
    writer.writerows(quotes)

Playwright

# pip install playwright
# python -m install playwright install

from playwright.sync_api import sync_playwright
import json

with sync_playwright() as p:
    # 헤드리스 모드에서 제어 가능한 크로미움 인스턴스 열기
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()

    # 대상 페이지 방문
    url = "http://quotes.toscrape.com/scroll"
    page.goto(url)

    # 스크랩된 데이터 저장 위치
    quotes = []

    # 페이지의 모든 quote HTML 요소 선택
    quote_elements = page.locator(".quote")
    # 페이지에 인용문 요소가 나타날 때까지 대기
    quote_elements.first.wait_for()

    # 각 인용문 요소를 반복 처리
    for quote_element in quote_elements.all():
        # 인용문 텍스트 추출
        text_element = quote_element.locator(".text")
        text = text_element.text_content().strip()

        # 인용문 작성자 추출
        author_element = quote_element.locator(".author")
        author = author_element.text_content().strip()

        # 추출된 데이터로 새 인용문 사전 생성
        quote = {
            "text": text,
            "author": author
        }

        # 목록에 추가
        quotes.append(quote)

    # 추출한 데이터를 JSON으로 내보내기
    with open("quotes.json", mode="w", encoding="utf-8") as file:
        json.dump(quotes, file, indent=4, ensure_ascii=False)

    # 브라우저 닫기 및 리소스 해제
    browser.close()

Selenium

# pip install selenium

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import csv

# 헤드리스 모드로 Chrome 인스턴스 실행
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)

# 대상 페이지 방문
url = "http://quotes.toscrape.com/scroll"
driver.get(url)


# 스크랩된 데이터 저장 위치
quotes = []

# 페이지에 인용문 요소가 나타날 때까지 대기 (기본값 30초)
wait = WebDriverWait(driver, 30)
quote_elements = wait.until(
    EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".quote"))
)

# 각 인용문 요소 반복
for quote_element in quote_elements:
    # 인용문 텍스트 추출
    text_element = quote_element.find_element(By.CSS_SELECTOR, ".text")
    text = text_element.text.strip()

    # 저자 이름 추출
    author_element = quote_element.find_element(By.CSS_SELECTOR, ".author")
    author = author_element.text.strip()

    # 스크랩된 데이터로 새 인용문 사전 생성
    quote = {
        "text": text,
        "author": author
    }

    # 목록에 추가
    quotes.append(quote)

# 추출한 데이터를 CSV로 내보내기
with open("quotes.csv", mode="w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["text", "author"])
    writer.writeheader()
    writer.writerows()(quotes)

# 브라우저 종료 및 리소스 정리
driver.quit()

파이썬으로 웹 스크레이퍼 구축하기: 단계별 가이드

더 완전하고 단계별 접근법을 원한다면, Requests와 Beautiful Soup을 사용해 Python으로 웹 스크레이퍼를 구축하는 이 섹션을 따라가세요.

목표는 대상 사이트에서 모든 명언 데이터를 추출하고, 각 페이지네이션 페이지를 탐색하는 방법을 보여주는 것입니다. 각 명언에 대해 텍스트, 저자, 태그 목록을 스크래핑할 것입니다. 마지막으로 스크래핑된 데이터를 CSV 파일로 내보내는 방법을 살펴보겠습니다.

1단계: 대상 URL 연결

이미 Python 프로젝트가 설정되어 있다고 가정합니다. 활성화된 가상 환경에서 다음 명령어로 필요한 라이브러리를 설치하세요:

pip install requests beautifulsoup4 lxml

또한 scraper.py 파일에는 이미 필요한 임포트가 포함되어 있어야 합니다:

import requests
from bs4 import BeautifulSoup

웹 스크레이퍼에서 가장 먼저 해야 할 일은 대상 웹사이트에 연결하는 것입니다. requests를 사용하여 다음 코드 줄로 웹 페이지를 다운로드하세요:

page = requests.get("https://quotes.toscrape.com")

page.text에는 서버가 반환한 HTML 문서가 문자열 형식으로 포함됩니다. 이제 이 텍스트 속성을 Beautiful Soup에 전달하여 웹 페이지의 HTML 콘텐츠를 파싱할 차례입니다!

2단계: HTML 콘텐츠 파싱

page.text를 BeautifulSoup() 생성자에 전달하여 HTML 문서를 파싱합니다:

soup = BeautifulSoup(page.text, "lxml")

이제 이를 사용하여 페이지에서 원하는 HTML 요소를 선택할 수 있습니다. 방법을 살펴보세요!

단계 #3: 노드 선택 로직 정의

웹 페이지에서 데이터를 추출하려면 먼저 관심 있는 HTML 요소를 식별해야 합니다. 특히, 스크래핑하려는 데이터를 포함하는 요소에 대한 선택 전략을 정의해야 합니다.

브라우저에서 제공하는 개발자 도구를 사용하면 이를 달성할 수 있습니다. Chrome에서는 관심 있는 HTML 요소를 마우스 오른쪽 버튼으로 클릭하고 “검사” 옵션을 선택하세요. 이 경우 인용문 요소에 대해 이 작업을 수행합니다:

여기서 볼 수 있듯이, <div> HTML 노드인 인용문은 .quote 선택자로 식별됩니다. 각 인용문 노드에는 다음이 포함됩니다:

  1. 인용문 텍스트는 <span> 에 포함되어 있으며 .text로 선택할 수 있습니다.
  2. 인용문의 저자는 <small> 태그에 포함되어 있으며 .author 선택자로 선택할 수 있습니다 .
  3. <div> 요소 내의 태그 목록으로, 각각 <a>에 포함됩니다. .tags .tag로 모두 선택할 수 있습니다.

훌륭합니다! 이제 Python 스크래핑 로직을 구현할 준비를 하세요.

4단계: 인용문 요소에서 데이터 추출

스크래핑된 데이터를 추적할 데이터 구조가 필요합니다. 이를 위해 배열 변수를 초기화하세요:

quotes = []

그런 다음, 앞서 정의한 .quote CSS 선택자를 적용하여 soup을 사용하여 DOM에서 quote 요소를 추출합니다.

여기서는 지금까지 살펴본 방법과 다른 접근법을 소개하기 위해 Beautiful Soup의 find()find_all() 메서드를 사용합니다:

  • find(): 입력된 선택기 전략과 일치하는 첫 번째 HTML 요소를 반환합니다(해당 요소가 존재할 경우).
  • find_all(): 매개변수로 전달된 선택기 조건에 맞는 HTML 요소들의 목록을 반환합니다.

다음으로 모든 quote 요소를 선택합니다:

quote_elements = soup.find_all("div", class_="quote")

find_all() 메서드는 quote 클래스로 식별된 모든 <div> HTML 요소 목록을 반환합니다. 인용문 목록을 반복하며 아래와 같이 인용문 데이터를 수집합니다:

for quote_element in quote_elements:
    # 인용문의 텍스트 추출
    text = quote_element.find("span", class_="text").get_text(strip=True)
    # 인용문의 저자 추출
    author = quote_element.find("small", class_="author").get_text(strip=True)

    # 인용문과 관련된 <a> 태그 HTML 요소 추출
    tag_elements = quote_element.select(".tags .tag")

    # 태그 문자열 목록을 리스트에 저장
    tags = []
    for tag_element in tag_elements:
        tags.append(tag_element.get_text(strip=True))

Beautiful Soup의 find() 메서드는 관심 있는 단일 HTML 요소를 가져옵니다. 인용문과 관련된 태그 문자열이 하나 이상이므로, 이를 리스트에 저장해야 합니다.

그런 다음, 수집한 데이터를 사전(dictionary)으로 변환하여 다음과 같이 인용문 목록에 추가할 수 있습니다:

quotes.append(
    {
        "text": text,
        "author": author,
        "tags": ", ".join(tags) # 태그를 "A, B, ..., Z" 형식의 문자열로 병합
    }
)

훌륭합니다! 이제 단일 페이지에서 모든 명언 데이터를 추출하는 방법을 확인하셨습니다.

하지만 대상 웹사이트는 여러 페이지로 구성되어 있다는 점을 명심하세요. 전체 웹사이트를 크롤링하는 방법을 배워보세요 !

단계 #5: 크롤링 로직 구현

홈페이지 하단에는 다음 페이지로 이동하는 “다음 →” <a> HTML 요소가 있습니다:

The “Next →” element

이 HTML 요소는 마지막 페이지를 제외한 모든 페이지에 포함되어 있습니다. 이러한 시나리오는 페이지가 나누어진 모든 웹사이트에서 흔히 볼 수 있습니다. “다음 →” 요소에 포함된 링크를 따라가면 전체 웹사이트를 쉽게 탐색할 수 있습니다.

따라서 홈페이지에서 시작하여 대상 웹사이트를 구성하는 각 페이지를 어떻게 통과할지 살펴보세요. .next <li> HTML 요소를 찾아 다음 페이지로의 상대 경로를 추출하기만 하면 됩니다.

크롤링 로직을 다음과 같이 구현하세요:

# 대상 웹사이트 홈페이지 URL
base_url = "https://quotes.toscrape.com"

# 페이지 불러오기 및 soup 초기화...

# "다음 →" HTML 요소 가져오기
next_li_element = soup.find("li", class_="next")

# 스크랩할 다음 페이지가 존재하는 경우
while next_li_element is not None:
    next_page_relative_url = next_li_element.find("a", href=True)["href"]

    # 새 페이지 가져오기
    page = requests.get(base_url + next_page_relative_url, headers=headers)

    # 새 페이지 파싱
    soup = BeautifulSoup(page.text, "lxml")

    # 스크래핑 로직...

    # 새 페이지에서 "Next →" HTML 요소 찾기
    next_li_element = soup.find("li", class_="next")

while 루프는 다음 페이지가 없을 때까지 각 페이지를 반복합니다. 다음 페이지의 상대 URL을 추출하여 스크래핑할 다음 페이지의 URL을 생성합니다. 그런 다음 다음 페이지를 다운로드합니다. 마지막으로 페이지를 스크래핑하고 이 과정을 반복합니다.

훌륭합니다! 이제 웹사이트 전체를 스크래핑하는 방법을 알게 되었습니다. 남은 것은 추출한 데이터를 CSV와 같은 더 유용한 형식으로 변환하는 방법을 배우는 것뿐입니다.

6단계: 스크랩한 데이터를 CSV 파일로 추출하기

스크랩한 인용문 데이터가 담긴 사전 목록을 CSV 파일로 내보냅니다:

import csv

# 스크래핑 로직...

# CSV 파일을 열고(또는 생성하고) 이후에 제대로 닫도록 보장
with open("quotes.csv", "w", encoding="utf-8", newline="") as csv_file:
    writer = csv.writer(csv_file)

    # 헤더 행 작성
    writer.writerow(["Text", "Author", "Tags"])

    # 각 인용문을 행으로 작성
    for quote in quotes:
        writer.writerow(quote.values())

이 코드 조각은 open()으로 CSV 파일을 생성합니다. 그런 다음 csv 라이브러리의 Writer 객체에서 제공하는 writerow() 함수를 사용해 출력 파일에 데이터를 채웁니다. 이 함수는 각 인용문 사전(dictionary)을 CSV 형식의 행으로 작성합니다.

대단하네요! 웹사이트에 포함된 원시 데이터를 CSV 파일에 저장된 반구조화된 데이터로 변환했습니다. 데이터 추출 과정이 완료되었으며, 이제 전체 Python 데이터 스크래퍼를 살펴볼 수 있습니다.

7단계: 모든 것을 통합하기

완성된 데이터 스크래핑 파이썬 스크립트는 다음과 같습니다:

# pip install requests beautifulsoup4 lxml

import requests
from bs4 import BeautifulSoup
import csv

def scrape_page(soup, quotes):
    # 페이지의 모든 quote <div> HTML 요소를 가져옵니다
    quote_elements = soup.find_all("div", class_="quote")

    # 인용문 요소 목록을 반복하며 스크래핑 로직 적용
    for quote_element in quote_elements:
        # 인용문 텍스트 추출
        text = quote_element.find("span", class_="text").get_text(strip=True)
        # 인용문의 저자 추출
        author = quote_element.find("small", class_="author").get_text(strip=True)

        # 인용문과 관련된 <a> HTML 태그 요소 추출
        tag_elements = quote_element.select(".tags .tag")

        # 태그 문자열 목록을 리스트에 저장
        tags = []
        for tag_element in tag_elements:
            tags.append(tag_element.get_text(strip=True))

        # 스크랩한 인용문 데이터를 포함하는 사전 추가
        quotes.append(
            {
                "text": text,
                "author": author,
                "tags": ", ".join(tags)  # 태그를 "A, B, ..., Z" 문자열로 병합
            }
        )

# 대상 웹사이트의 홈페이지 URL
base_url = "https://quotes.toscrape.com"
# 대상 웹 페이지 가져오기
page = requests.get(base_url)

# Beautiful Soup으로 대상 웹 페이지 파싱
soup = BeautifulSoup(page.text, "lxml")

# 스크랩된 데이터 저장 위치
quotes = []

# 홈페이지 스크래핑
scrape_page(soup, quotes)

# "다음 →" HTML 요소 가져오기
next_li_element = soup.find("li", class_="next")

# 스크랩할 다음 페이지가 있는 경우
while next_li_element is not None:
    next_page_relative_url = next_li_element.find("a", href=True)["href"]

    # 새 페이지 가져오기
    page = requests.get(base_url + next_page_relative_url)

    # 새 페이지 파싱
    soup = BeautifulSoup(page.text, "lxml")

    # 새 페이지 스크래핑
    scrape_page(soup, quotes)

    # 새 페이지에서 "Next →" HTML 요소 찾기
    next_li_element = soup.find("li", class_="next")

# CSV 파일 열기(또는 생성) 및 이후 올바르게 닫기 보장
with open("quotes.csv", "w", encoding="utf-8", newline="") as csv_file:
    writer = csv.writer(csv_file)

    # 헤더 행 작성
    writer.writerow(["Text", "Author", "Tags"])

    # 각 명언을 행으로 작성
    for quote in quotes:
        writer.writerow(quote.values())

여기서 보듯이, 80줄 미만의 코드로 파이썬 웹 스크레이퍼를 구축할 수 있습니다. 이 스크립트는 전체 웹사이트를 크롤링하고, 모든 데이터를 자동으로 추출하여 CSV로 내보낼 수 있습니다.

축하합니다! Requests와 Beautiful Soup을 사용한 Python 웹 스크래핑 방법을 배웠습니다.

프로젝트 디렉토리 내 터미널에서 다음 명령어로 Python 스크립트를 실행하세요:

python3 scraper.py

또는 일부 시스템에서는:

python scraper.py

프로세스가 완료될 때까지 기다리면 quotes.csv 파일에 접근할 수 있습니다. 파일을 열면 다음과 같은 데이터가 포함되어 있을 것입니다:

The quotes.csv file with all quotes from the entire site

자, 이제 대상 웹사이트에 있는 100개의 명언이 모두 읽기 쉬운 형식의 단일 파일에 담겼습니다.

Scrapy: 올인원 파이썬 웹 스크래핑 프레임워크

지금까지 설명한 바에 따르면, Python으로 웹사이트를 스크래핑하려면 HTTP 클라이언트 + HTML 파서 설정이나 브라우저 자동화 도구가 필요하다고 했습니다. 하지만 이는 완전히 사실이 아닙니다. 단일 라이브러리 내에서 필요한 모든 것을 제공하는 전용 올인원 스크래핑 프레임워크가 존재합니다.

파이썬에서 가장 널리 쓰이는 스크래핑 프레임워크는Scrapy입니다. 기본적으로 정적 사이트에서 바로 작동하지만, Scrapy Splash나 Scrapy Playwright 같은 도구를 사용해 동적 사이트 처리로 확장할 수 있습니다.

기본 형태의 Scrapy는 HTTP 클라이언트 기능과 HTML 파싱을 하나의 강력한 패키지로 결합합니다. 이 섹션에서는 Quotes to Scrape의 정적 버전을 스크래핑하기 위한 Scrapy 프로젝트 설정 방법을 배웁니다.

다음 명령어로 Scrapy 설치:

pip install scrapy

그런 다음 새 Scrapy 프로젝트를 생성하고 Quotes to Scrape용 스파이더를 생성합니다:

scrapy startproject quotes_scraper
cd quotes_scraper
scrapy genspider quotes quotes.toscrape.com

이 명령어는 quotes_scraper라는 새 Scrapy 프로젝트 폴더를 생성하고, 해당 폴더로 이동한 후 quotes.toscrape.com 사이트를 대상으로 하는 quotes라는 이름의 스파이더를 생성합니다.

이 절차에 익숙하지 않다면 Scrapy를 이용한 스크래핑 가이드를 참고하세요.

스파이더 파일(quotes_scraper/spiders/quotes.py)을 편집하고 다음 스크래핑 Python 로직을 추가하세요:

# quotes_scraper/spiders/quotes.py

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"

    # 방문할 사이트
    start_urls = [
        "http://quotes.toscrape.com/"
    ]

    def parse(self, response):
        # 스크래핑 로직
        for quote in response.css(".quote"):
            yield {
                "text": quote.css(".text::text").get(),
                "author": quote.css(".author::text").get(),
                "tags": quote.css(".tags .tag::text").getall(),
            }

        # 페이지네이션 처리 로직
        next_page = response.css("li.next a::attr(href)").get()
        if next_page:
            yield response.follow(next_page, self.parse)

배경에서 Scrapy는 대상 페이지에 HTTP 요청을 보내고, 스파이더에 지정된 대로 데이터를 추출하기 위해 내장된 HTML 파서인 Parsel을 사용합니다.

이제 다음 명령어로 스크랩된 데이터를 프로그래밍 방식으로 CSV로 내보낼 수 있습니다:

scrapy crawl quotes -o quotes.csv

또는 JSON으로 내보내려면:

scrapy crawl quotes -o quotes.json

이 명령어들은 스파이더를 실행하고 추출된 데이터를 지정된 파일 형식으로 자동 저장합니다.

추가 참고 자료:

파이썬에서 스크래핑 과제와 극복 방법

이 튜토리얼에서는 웹 스크래핑을 쉽게 할 수 있도록 구축된 사이트를 스크래핑하는 방법을 배웠습니다. 이러한 기술을 실제 대상에 적용할 때 훨씬 더 많은 스크래핑 문제를 마주하게 될 것입니다.

가장 흔한 스크래핑 문제점과 방어 기법 (해결 가이드 포함)은 다음과 같습니다:

현재 대부분의 솔루션은 일시적으로만 작동하는 우회 방법에 기반합니다. 이는 스크래핑 스크립트를 지속적으로 유지 관리해야 함을 의미합니다. 또한 고품질 웹 프록시와 같은 프리미엄 리소스에 대한 접근이 필요할 때도 있습니다.

따라서 프로덕션 환경이나 스크래핑이 너무 복잡해지는 경우에는 Bright Data와 같은 완벽한 웹 데이터 공급자에 의존하는 것이 합리적입니다.

Bright Data는 다음과 같은 다양한 웹 스크래핑 서비스를 제공합니다:

  • 언락커 API: 대규모 페이지 수집 성공을 보장하기 위해 차단, CAPTCHA, 봇 방지 문제를 자동으로 해결합니다.
  • 크롤 API: 전체 웹사이트를 구조화된 AI 활용 가능한 데이터로 파싱합니다.
  • SERP API: 지리적 타겟팅, 기기 에뮬레이션, 내장된 안티-CAPTCHA 기능을 통해 실시간 검색 엔진 결과(Google, Bing 등)를 검색합니다.
  • 브라우저 API: 은밀한 지문 인식 기능을 갖춘 원격 헤드리스 브라우저를 실행하여 자바스크립트 중심 페이지 렌더링 및 복잡한 상호작용을 자동화합니다. Playwright 및 Selenium과 호환됩니다.
  • CAPTCHA Solver: reCAPTCHA, hCaptcha, px_captcha, SimpleCaptcha, GeeTest CAPTCHA 등의 도전을 우회할 수 있는 신속하고 자동화된 CAPTCHA 솔버입니다.
  • 웹 스크레이퍼 API: LinkedIn, Amazon, TikTok 등 100개 이상의 주요 사이트에서 실시간 데이터를 추출하는 사전 구축된 스크레이퍼입니다.
  • 프록시 서비스: 주거용 프록시, 모바일 프록시, ISP 프록시, 데이터센터 프록시에서 1억 5천만 개 이상의 IP를 제공합니다.

이 모든 솔루션은 Python 또는 기타 기술 스택과 원활하게 통합됩니다. Python 웹 스크래핑 프로젝트 구현을 크게 단순화합니다.

결론

이 블로그 글에서는 Python을 활용한 웹 스크래핑의 개념, 시작에 필요한 요소, 그리고 여러 도구를 사용한 실행 방법을 알아보았습니다. 이제 Python으로 사이트를 스크래핑하는 기본기를 갖추셨으며, 스크래핑 기술을 연마하는 데 도움이 될 추가 자료 링크도 확인하셨습니다.

웹 스크래핑에는 많은 어려움이 따릅니다. 봇 방지 및 스크래핑 방지 기술이 점점 더 보편화되고 있습니다. 따라서 Bright Data가 제공하는 것과 같은 고급 웹 스크래핑 솔루션이 필요할 수 있습니다.

직접 스크래핑하기보다는 데이터 접근만 원하신다면, 저희 데이터셋 서비스를 살펴보시기 바랍니다.

Bright Data 계정을 무료로 생성하고 당사 솔루션을 활용하여 Python 웹 스크래퍼를 한 단계 업그레이드하세요!