본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 17. · 6 Views
웹 스크래핑 기초 완벽 가이드
파이썬으로 웹에서 데이터를 추출하는 기본 방법을 배웁니다. BeautifulSoup을 사용하여 HTML을 분석하고, 필요한 정보를 효율적으로 수집하는 방법을 실무 예제와 함께 익힙니다.
목차
- 웹 스크래핑이란?
- HTML 구조 이해하기
- BeautifulSoup 설치 및 기초
- find()와 find_all() 사용
- CSS 선택자로 추출
- 테이블 데이터 추출
- 스크래핑 윤리와 주의사항
1. 웹 스크래핑이란?
어느 날 김개발 씨가 팀 미팅에 참석했습니다. 팀장님이 말했습니다.
"경쟁사 제품 가격을 매일 수집해서 엑셀로 정리해주세요." 김개발 씨는 당황했습니다. 수십 개 사이트를 매일 일일이 방문해서 복사 붙여넣기를 해야 한다니!
웹 스크래핑은 웹사이트에서 필요한 데이터를 자동으로 수집하는 기술입니다. 마치 신문에서 필요한 기사만 오려내는 것처럼, 웹페이지에서 우리가 원하는 정보만 골라낼 수 있습니다.
반복적인 데이터 수집 작업을 자동화하여 시간을 절약하고, 실시간으로 최신 정보를 확보할 수 있습니다.
다음 코드를 살펴봅시다.
import requests
from bs4 import BeautifulSoup
# 웹페이지 가져오기
url = 'https://example.com'
response = requests.get(url)
# HTML 파싱하기
soup = BeautifulSoup(response.text, 'html.parser')
# 제목 추출하기
title = soup.find('h1').text
print(f'페이지 제목: {title}')
김개발 씨는 선배 박시니어 씨에게 고민을 털어놓았습니다. "매일 이 작업을 손으로 하려면 하루 종일 걸릴 것 같아요." 박시니어 씨가 웃으며 대답했습니다.
"그럴 땐 웹 스크래핑을 사용하면 되죠." 웹 스크래핑이란 정확히 무엇일까요? 쉽게 비유하자면, 웹 스크래핑은 마치 도서관에서 자동으로 책을 찾아주는 로봇과 같습니다.
사람이 직접 서가를 돌아다니며 책을 찾는 대신, 로봇이 정확히 필요한 책만 골라서 가져다주는 것입니다. 웹 스크래핑도 마찬가지로 웹페이지를 자동으로 방문하여 필요한 정보만 추출합니다.
과거에는 어떻게 데이터를 수집했을까요? 예전에는 사람이 직접 웹사이트를 방문해서 마우스로 드래그하고, 복사하고, 엑셀에 붙여넣는 작업을 반복했습니다.
단 하나의 사이트라면 괜찮지만, 수십 개의 사이트에서 매일 데이터를 수집해야 한다면 어떨까요? 엄청난 시간이 소요되고, 실수도 자주 발생했습니다.
더욱이 실시간으로 변하는 정보를 놓치기 일쑤였습니다. 바로 이런 문제를 해결하기 위해 웹 스크래핑이 등장했습니다.
웹 스크래핑을 사용하면 반복 작업을 자동화할 수 있습니다. 한 번 코드를 작성해두면 매일 자동으로 데이터를 수집할 수 있습니다.
또한 사람보다 훨씬 빠르고 정확하게 데이터를 처리합니다. 무엇보다 24시간 쉬지 않고 작동할 수 있다는 큰 장점이 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 requests 라이브러리로 웹페이지의 HTML 코드를 가져옵니다.
이것은 마치 책을 도서관에서 빌려오는 것과 같습니다. 다음으로 BeautifulSoup을 사용하여 HTML을 분석 가능한 형태로 변환합니다.
마지막으로 원하는 데이터를 찾아서 추출합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 부동산 중개 서비스를 개발한다고 가정해봅시다. 여러 부동산 사이트에서 매물 정보를 실시간으로 수집하여 우리 서비스에 통합할 수 있습니다.
네이버, 쿠팡 같은 많은 기업에서 경쟁사 가격 모니터링, 시장 조사, 데이터 분석 등에 웹 스크래핑을 적극적으로 활용하고 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 무작정 대량으로 요청을 보내는 것입니다. 이렇게 하면 서버에 부담을 주어 접속이 차단될 수 있습니다.
따라서 요청 사이에 적절한 시간 간격을 두어야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다. "그럼 매일 수작업으로 하던 걸 자동화할 수 있겠네요!" 웹 스크래핑을 제대로 이해하면 데이터 수집 업무를 획기적으로 효율화할 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 웹 스크래핑 전에 해당 사이트의 robots.txt를 확인하여 허용 여부를 체크하세요
- 요청 사이에 time.sleep()으로 1-2초 간격을 두어 서버 부담을 줄이세요
- API가 제공된다면 웹 스크래핑보다 API 사용을 우선 검토하세요
2. HTML 구조 이해하기
김개발 씨가 첫 스크래핑 코드를 작성하려고 하는데, 막막했습니다. "데이터를 어디서 찾아야 하지?" 박시니어 씨가 조언했습니다.
"먼저 HTML 구조를 이해해야 해요. 집의 설계도를 알아야 방을 찾을 수 있는 것처럼요."
HTML은 웹페이지를 구성하는 마크업 언어로, 태그라는 요소들이 계층적으로 중첩된 구조를 가집니다. 각 태그는 여는 태그와 닫는 태그로 이루어지며, 속성을 통해 추가 정보를 제공합니다.
HTML 구조를 이해하면 원하는 데이터가 어디에 위치하는지 정확히 찾을 수 있습니다.
다음 코드를 살펴봅시다.
<!-- 전형적인 HTML 구조 -->
<html>
<head>
<title>상품 목록</title>
</head>
<body>
<div class="container">
<h1 id="main-title">베스트 상품</h1>
<ul class="product-list">
<li class="product-item">
<span class="name">노트북</span>
<span class="price">1200000</span>
</li>
</ul>
</div>
</body>
</html>
김개발 씨는 크롬 브라우저를 켜고 F12 키를 눌렀습니다. 개발자 도구가 열리면서 복잡한 코드들이 나타났습니다.
"이게 다 뭐죠?" 박시니어 씨가 화면을 가리키며 설명을 시작했습니다. HTML 구조란 무엇일까요?
쉽게 비유하자면, HTML은 마치 러시아 인형처럼 상자 안에 상자가 들어있는 구조입니다. 큰 상자 안에 중간 상자가 있고, 그 안에 또 작은 상자가 있습니다.
HTML도 마찬가지로 태그 안에 태그가 중첩되어 계층 구조를 만듭니다. 이런 구조를 이해해야 원하는 데이터가 어느 상자에 들어있는지 찾을 수 있습니다.
HTML을 모르고 스크래핑을 시도하면 어떻게 될까요? 마치 지도 없이 미로를 헤매는 것과 같습니다.
어디에 어떤 데이터가 있는지 알 수 없어 무작정 모든 요소를 살펴봐야 합니다. 시간도 오래 걸리고, 엉뚱한 데이터를 가져올 가능성도 높습니다.
더 큰 문제는 웹사이트 구조가 조금만 바뀌어도 코드가 작동하지 않는다는 것입니다. HTML 구조를 이해하면 무엇이 좋을까요?
첫째, 원하는 데이터의 정확한 위치를 파악할 수 있습니다. 둘째, class나 id 같은 속성을 활용하여 효율적으로 데이터를 추출할 수 있습니다.
셋째, 웹사이트 구조가 변경되어도 빠르게 대응할 수 있습니다. 위의 HTML 코드를 살펴보겠습니다.
가장 바깥쪽에 html 태그가 있고, 그 안에 head와 body가 있습니다. head는 페이지 정보를, body는 실제 내용을 담고 있습니다.
body 안을 보면 div 태그에 "container"라는 class가 있습니다. 이것은 마치 집 안의 거실이라는 이름표와 같습니다.
그 안에 제목과 상품 목록이 차례로 배치되어 있습니다. 실제 웹페이지에서 어떻게 활용할까요?
예를 들어 쇼핑몰에서 상품 가격을 추출한다고 가정해봅시다. 크롬 개발자 도구로 페이지를 분석하면 가격이 span 태그의 "price"라는 class 안에 있음을 발견할 수 있습니다.
이 정보를 바탕으로 정확히 가격 데이터만 추출하는 코드를 작성할 수 있습니다. 태그의 속성도 중요합니다.
class는 여러 요소에 같은 스타일을 적용할 때 사용합니다. 상품 목록에 있는 모든 상품이 같은 class를 가지는 경우가 많습니다.
반면 id는 페이지에서 유일한 요소를 식별할 때 사용합니다. 메인 제목 같은 것이 대표적입니다.
주의할 점도 있습니다. 초보자들이 자주 하는 실수는 태그 이름만 보고 데이터를 추출하려는 것입니다.
예를 들어 모든 span 태그를 가져오면 필요 없는 데이터까지 함께 추출됩니다. 따라서 class나 id를 함께 활용하여 정확한 요소를 지정해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. "아, 이렇게 계층 구조로 되어 있었군요!" 김개발 씨는 개발자 도구로 여러 웹사이트를 분석하며 HTML 구조에 익숙해졌습니다.
HTML 구조를 제대로 이해하면 웹 스크래핑이 훨씬 수월해집니다. 여러분도 자주 방문하는 웹사이트를 개발자 도구로 분석해 보세요.
실전 팁
💡 - 크롬 개발자 도구(F12)의 Elements 탭에서 요소를 클릭하면 해당 HTML 코드로 바로 이동합니다
- 마우스를 HTML 코드 위에 올리면 페이지에서 해당 영역이 하이라이트되어 쉽게 찾을 수 있습니다
- class는 점(.), id는 샵(#)으로 표현되는 것을 기억하세요
3. BeautifulSoup 설치 및 기초
김개발 씨가 본격적으로 스크래핑을 시작하려는데, 어떤 도구를 써야 할지 막막했습니다. 박시니어 씨가 추천했습니다.
"파이썬에는 BeautifulSoup이라는 훌륭한 라이브러리가 있어요. 설치부터 해볼까요?"
BeautifulSoup은 파이썬에서 HTML을 파싱하고 데이터를 추출하는 가장 인기 있는 라이브러리입니다. 간단한 문법으로 복잡한 HTML 구조를 쉽게 탐색할 수 있으며, 다양한 검색 방법을 제공합니다.
설치는 pip 명령어로 간단히 할 수 있고, requests 라이브러리와 함께 사용하면 강력한 스크래핑 도구가 됩니다.
다음 코드를 살펴봅시다.
# 터미널에서 설치
# pip install beautifulsoup4 requests
from bs4 import BeautifulSoup
import requests
# 웹페이지 가져오기
url = 'https://example.com'
response = requests.get(url)
# BeautifulSoup 객체 생성 - html.parser로 파싱
soup = BeautifulSoup(response.text, 'html.parser')
# 페이지 제목 추출
title = soup.title.string
print(f'제목: {title}')
김개발 씨는 터미널을 열고 박시니어 씨가 알려준 명령어를 입력했습니다. 몇 초 후 설치가 완료되었습니다.
"이렇게 간단한가요?" 박시니어 씨가 미소 지으며 답했습니다. "네, 파이썬의 장점이죠." BeautifulSoup이란 정확히 무엇일까요?
쉽게 비유하자면, BeautifulSoup은 마치 복잡하게 얽힌 실타래를 깔끔하게 정리해주는 도구와 같습니다. 웹페이지의 HTML 코드는 사람이 읽기 어렵게 뒤섞여 있는 경우가 많습니다.
BeautifulSoup은 이것을 체계적으로 정리하여 우리가 원하는 데이터를 쉽게 찾을 수 있도록 도와줍니다. BeautifulSoup이 없던 시절에는 어땠을까요?
개발자들은 정규표현식을 사용하여 직접 HTML 문자열을 파싱해야 했습니다. 정규표현식은 강력하지만 복잡하고 실수하기 쉽습니다.
특히 중첩된 태그를 처리할 때 코드가 매우 복잡해졌습니다. 또한 HTML이 조금만 불규칙해도 코드가 작동하지 않는 경우가 많았습니다.
BeautifulSoup을 사용하면 어떤 이점이 있을까요? 첫째, 직관적인 문법으로 HTML 요소에 접근할 수 있습니다.
마치 객체의 속성에 접근하듯이 간단합니다. 둘째, 불완전한 HTML도 자동으로 보정하여 처리합니다.
실제 웹에는 문법이 완벽하지 않은 HTML이 많은데, BeautifulSoup은 이런 경우도 잘 처리합니다. 셋째, 다양한 파서를 선택할 수 있어 상황에 맞게 활용할 수 있습니다.
위의 코드를 단계별로 살펴보겠습니다. 먼저 **requests.get()**으로 웹페이지의 HTML을 문자열로 가져옵니다.
이것은 마치 인터넷에서 웹페이지를 다운로드하는 것과 같습니다. 다음으로 BeautifulSoup() 생성자에 HTML 문자열과 파서 이름을 전달합니다.
파서는 HTML을 해석하는 방법을 지정하는 것인데, html.parser는 파이썬 내장 파서로 별도 설치가 필요 없습니다. 마지막으로 soup 객체의 속성이나 메서드를 통해 원하는 데이터를 추출합니다.
실제 프로젝트에서는 어떻게 활용할까요? 예를 들어 뉴스 사이트에서 기사 제목과 내용을 수집하는 서비스를 만든다고 가정해봅시다.
BeautifulSoup으로 각 기사 페이지를 파싱하고, 제목, 작성일, 본문 등을 추출하여 데이터베이스에 저장할 수 있습니다. 많은 스타트업에서 시장 동향 파악, 경쟁사 분석 등에 이런 방식을 활용하고 있습니다.
파서 선택도 중요합니다. html.parser는 별도 설치가 필요 없고 적당한 속도를 보입니다.
lxml은 속도가 매우 빠르지만 별도 설치가 필요합니다. html5lib은 가장 관대하게 HTML을 파싱하지만 속도가 느립니다.
일반적으로는 html.parser로 시작하고, 속도가 중요하면 lxml을 고려하면 됩니다. 초보자가 주의할 점이 있습니다.
response.text가 아니라 response.content를 사용하는 경우도 있습니다. text는 유니코드 문자열이고, content는 바이트입니다.
한글이 깨지는 경우 인코딩 문제일 수 있으니 response.encoding을 확인해보세요. 다시 김개발 씨의 이야기로 돌아가 봅시다.
첫 코드를 실행한 김개발 씨는 화면에 웹페이지 제목이 출력되는 것을 보고 감탄했습니다. "와, 정말 간단하네요!" BeautifulSoup의 기본만 익혀도 대부분의 스크래핑 작업을 수행할 수 있습니다.
여러분도 간단한 페이지부터 시작해서 실력을 쌓아보세요.
실전 팁
💡 - html.parser는 파이썬 내장이라 추가 설치가 필요 없어 가장 무난합니다
- response.status_code로 요청 성공 여부를 확인하세요 (200이 정상)
- soup.prettify()를 사용하면 HTML을 보기 좋게 출력할 수 있습니다
4. find()와 find all() 사용
김개발 씨가 웹페이지에서 특정 요소를 찾으려고 하는데, 방법을 몰라 헤맸습니다. 박시니어 씨가 말했습니다.
"BeautifulSoup의 핵심은 find()와 find_all()이에요. 이 두 메서드만 잘 써도 웬만한 건 다 할 수 있어요."
**find()**는 조건에 맞는 첫 번째 요소 하나를 찾아 반환하고, **find_all()**은 조건에 맞는 모든 요소를 리스트로 반환합니다. 태그 이름, class, id 등 다양한 조건으로 검색할 수 있으며, 중첩된 구조에서도 재귀적으로 찾을 수 있습니다.
웹 스크래핑에서 가장 자주 사용되는 핵심 메서드입니다.
다음 코드를 살펴봅시다.
from bs4 import BeautifulSoup
import requests
url = 'https://example.com/products'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 첫 번째 h1 태그 찾기
main_title = soup.find('h1')
print(f'메인 제목: {main_title.text}')
# class가 'product-item'인 모든 요소 찾기
products = soup.find_all('div', class_='product-item')
for product in products:
name = product.find('span', class_='name').text
price = product.find('span', class_='price').text
print(f'{name}: {price}원')
김개발 씨는 상품 목록 페이지를 열고 개발자 도구로 구조를 분석했습니다. 수십 개의 상품이 같은 형태로 반복되고 있었습니다.
"이걸 어떻게 한 번에 가져오지?" 박시니어 씨가 코드를 보여주며 설명했습니다. **find()**와 **find_all()**은 무엇이 다를까요?
쉽게 비유하자면, find()는 마치 "빨간 사과 하나만 주세요"라고 하는 것이고, find_all()은 "빨간 사과 전부 주세요"라고 하는 것입니다. find()는 조건에 맞는 첫 번째 요소를 찾으면 바로 반환하고 검색을 멈춥니다.
반면 find_all()은 페이지 전체를 검색하여 조건에 맞는 모든 요소를 리스트로 모아서 반환합니다. 이 메서드들이 없다면 어떻게 해야 할까요?
직접 HTML 구조를 순회하면서 일일이 태그를 확인해야 합니다. 코드가 복잡해지고, 실수하기도 쉽습니다.
특히 중첩된 구조에서 원하는 요소를 찾으려면 여러 단계를 거쳐야 해서 매우 번거롭습니다. 또한 코드의 가독성도 떨어집니다.
find()와 find_all()을 사용하면 무엇이 좋을까요? 첫째, 간결한 코드로 원하는 요소를 정확히 찾을 수 있습니다.
둘째, 태그 이름뿐만 아니라 class, id, 다른 속성들도 조건으로 사용할 수 있어 매우 유연합니다. 셋째, 찾은 요소 안에서 다시 find()를 호출하여 중첩 검색이 가능합니다.
위의 코드를 자세히 분석해보겠습니다. 첫 번째 예시에서 **soup.find('h1')**은 페이지에서 첫 번째 h1 태그를 찾습니다.
보통 페이지의 메인 제목은 하나뿐이므로 find()를 사용합니다. 두 번째 예시에서 **find_all('div', class_='product-item')**은 class가 'product-item'인 모든 div를 찾아 리스트로 반환합니다.
주의할 점은 파이썬에서 class가 예약어이므로 class_로 언더스코어를 붙여야 한다는 것입니다. 반복문 안을 살펴보겠습니다.
각 product 요소 안에서 다시 **find()**를 호출합니다. 이것은 전체 페이지가 아니라 해당 product 요소 안에서만 검색합니다.
이렇게 하면 각 상품의 이름과 가격을 정확히 매칭하여 추출할 수 있습니다. .text는 태그의 텍스트 내용만 가져오는 속성입니다.
실제 프로젝트에서는 어떻게 활용할까요? 예를 들어 부동산 사이트에서 매물 정보를 수집한다고 가정해봅시다.
find_all()로 모든 매물 카드를 가져온 후, 각 카드 안에서 find()로 가격, 면적, 위치 등을 추출할 수 있습니다. 이렇게 수집한 데이터를 데이터베이스에 저장하고, 시간대별 가격 변동을 분석할 수 있습니다.
다양한 검색 조건을 사용할 수 있습니다. id로 검색할 때는 soup.find('div', id='main-content')처럼 작성합니다.
여러 속성을 동시에 지정할 수도 있습니다. 예를 들어 soup.find('a', class_='link', href=True)는 class가 'link'이고 href 속성이 있는 a 태그를 찾습니다.
초보자가 자주 하는 실수가 있습니다. find()의 결과가 None일 수 있다는 것을 잊고 바로 .text를 호출하면 에러가 발생합니다.
따라서 if element: 같은 체크를 먼저 하거나, try-except로 예외 처리를 해야 합니다. 또한 find_all()은 리스트를 반환하므로 반드시 반복문을 사용해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 코드를 실행한 김개발 씨는 화면에 모든 상품의 이름과 가격이 차례로 출력되는 것을 보고 놀랐습니다.
"이렇게 간단하게 전부 가져올 수 있다니!" find()와 find_all()만 잘 활용해도 대부분의 웹 스크래핑은 해결됩니다. 여러분도 다양한 조건으로 실습해보며 익숙해지세요.
실전 팁
💡 - find()의 결과는 Tag 객체 또는 None이므로 반드시 None 체크를 하세요
- class는 파이썬 예약어이므로 class_로 언더스코어를 붙여야 합니다
- find_all()에 limit 매개변수를 사용하면 원하는 개수만큼만 가져올 수 있습니다
5. CSS 선택자로 추출
김개발 씨가 복잡한 HTML 구조에서 데이터를 추출하려니 find()만으로는 부족했습니다. 박시니어 씨가 새로운 방법을 알려주었습니다.
"CSS 선택자를 사용하면 훨씬 강력하고 정확하게 찾을 수 있어요."
CSS 선택자는 웹 디자이너들이 스타일을 적용할 요소를 지정할 때 사용하는 문법으로, BeautifulSoup에서도 select() 메서드를 통해 활용할 수 있습니다. class는 점(.), id는 샵(#)으로 표현하며, 계층 구조와 속성까지 표현할 수 있어 매우 정밀한 검색이 가능합니다.
복잡한 조건의 요소를 찾을 때 특히 유용합니다.
다음 코드를 살펴봅시다.
from bs4 import BeautifulSoup
import requests
url = 'https://example.com/products'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# id가 'main-title'인 요소 찾기
title = soup.select_one('#main-title')
print(f'제목: {title.text}')
# class가 'product-item'인 모든 요소 찾기
products = soup.select('.product-item')
# 계층 구조로 정확히 찾기
# div.container 안의 ul.product-list 안의 li
items = soup.select('div.container > ul.product-list > li')
for item in items:
print(item.text.strip())
김개발 씨는 여러 개의 div가 중첩된 복잡한 페이지를 마주했습니다. find()로는 정확히 원하는 부분을 찾기 어려웠습니다.
박시니어 씨가 개발자 도구를 열며 말했습니다. "요소를 우클릭하고 Copy Selector를 선택해보세요." CSS 선택자란 정확히 무엇일까요?
쉽게 비유하자면, CSS 선택자는 마치 상세한 주소와 같습니다. "서울시 강남구 테헤란로 123번지 2층 201호"처럼 정확한 위치를 지정할 수 있습니다.
단순히 "201호"라고만 하면 어디인지 모르지만, 계층적으로 상세히 지정하면 정확히 그 위치를 찾을 수 있습니다. CSS 선택자도 마찬가지로 HTML 구조의 정확한 경로를 표현합니다.
CSS 선택자 없이는 어떤 문제가 있을까요? 예를 들어 class가 'name'인 요소가 페이지에 수십 개 있다면, find()나 find_all()만으로는 원하는 것을 정확히 지정하기 어렵습니다.
부모 요소를 먼저 찾고, 그 안에서 다시 찾고, 또 그 안에서 찾는 식으로 여러 단계를 거쳐야 합니다. 코드가 길어지고 복잡해집니다.
CSS 선택자를 사용하면 어떤 이점이 있을까요? 첫째, 한 줄의 코드로 복잡한 계층 구조를 표현할 수 있습니다.
둘째, 프론트엔드 개발자가 익숙한 문법이므로 협업이 쉽습니다. 셋째, 크롬 개발자 도구에서 CSS 선택자를 바로 복사할 수 있어 매우 편리합니다.
위의 코드를 단계별로 살펴보겠습니다. **select_one()**은 조건에 맞는 첫 번째 요소 하나만 반환하는 메서드입니다.
find()와 비슷하지만 CSS 선택자 문법을 사용합니다. #main-title에서 샵 기호는 id를 의미합니다.
다음으로 **select()**는 조건에 맞는 모든 요소를 리스트로 반환합니다. .product-item에서 점은 class를 의미합니다.
계층 구조 선택자를 살펴보겠습니다. > 기호는 직계 자식을 의미합니다.
div.container > ul.product-list는 class가 'container'인 div의 직계 자식 중에서 class가 'product-list'인 ul을 찾습니다. 만약 > 대신 공백을 사용하면 직계 자식뿐만 아니라 모든 하위 요소를 검색합니다.
실제 프로젝트에서는 어떻게 활용할까요? 예를 들어 뉴스 사이트에서 특정 카테고리의 기사만 추출한다고 가정해봅시다.
soup.select('section.news > article.tech')처럼 작성하면 news 섹션 안의 tech 기사만 정확히 가져올 수 있습니다. 복잡한 구조의 포털 사이트에서도 CSS 선택자를 사용하면 원하는 데이터를 정확히 추출할 수 있습니다.
다양한 CSS 선택자 문법이 있습니다. 속성 선택자도 사용할 수 있습니다.
예를 들어 a[href^="https"]는 href가 "https"로 시작하는 모든 a 태그를 찾습니다. input[type="text"]는 type이 "text"인 input을 찾습니다.
이런 방식으로 매우 세밀한 조건 지정이 가능합니다. 주의할 점도 있습니다.
CSS 선택자가 너무 복잡하면 코드 가독성이 떨어집니다. 또한 웹사이트 구조가 변경되면 선택자도 함께 수정해야 합니다.
따라서 가능한 한 간단하면서도 명확한 선택자를 사용하는 것이 좋습니다. class나 id가 명확하다면 계층 구조까지 모두 명시할 필요는 없습니다.
개발자 도구를 적극 활용하세요. 크롬에서 원하는 요소를 우클릭하고 Copy > Copy selector를 선택하면 CSS 선택자가 클립보드에 복사됩니다.
이것을 그대로 사용하거나 필요한 부분만 간소화하여 사용할 수 있습니다. 매우 편리한 기능입니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 복사한 선택자를 코드에 붙여넣고 실행한 김개발 씨는 정확히 원하는 데이터가 추출되는 것을 보고 감탄했습니다.
"이렇게 편한 방법이 있었다니!" CSS 선택자를 익히면 웹 스크래핑의 정확도와 효율성이 크게 향상됩니다. 여러분도 개발자 도구와 함께 다양한 선택자를 실습해보세요.
실전 팁
💡 - 크롬 개발자 도구에서 Copy Selector로 CSS 선택자를 바로 복사할 수 있습니다
- select()는 리스트를, select_one()은 단일 요소를 반환합니다
- 선택자가 복잡하면 변수로 분리하여 가독성을 높이세요
6. 테이블 데이터 추출
김개발 씨가 통계 사이트에서 표 형태의 데이터를 가져오려고 하는데, 행과 열이 복잡하게 얽혀 있었습니다. 박시니어 씨가 조언했습니다.
"테이블은 규칙적인 구조라 오히려 쉬워요. 패턴을 이해하면 됩니다."
HTML table 태그는 tr(행), th(헤더 셀), td(데이터 셀)로 구성된 규칙적인 구조를 가집니다. BeautifulSoup으로 테이블을 파싱하면 2차원 배열처럼 데이터를 추출할 수 있으며, pandas 라이브러리와 결합하면 더욱 강력합니다.
통계 데이터, 순위표, 가격 비교표 등 정형화된 데이터를 수집할 때 매우 유용합니다.
다음 코드를 살펴봅시다.
from bs4 import BeautifulSoup
import requests
url = 'https://example.com/statistics'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 테이블 찾기
table = soup.find('table', class_='data-table')
# 헤더 추출
headers = []
for th in table.find_all('th'):
headers.append(th.text.strip())
print('헤더:', headers)
# 데이터 추출
rows = []
for tr in table.find_all('tr')[1:]: # 첫 행은 헤더이므로 제외
cells = [td.text.strip() for td in tr.find_all('td')]
if cells: # 빈 행 제외
rows.append(cells)
print(cells)
김개발 씨는 코로나19 통계 사이트를 열었습니다. 날짜별 확진자 수가 깔끔한 표로 정리되어 있었습니다.
"이 데이터를 엑셀로 옮기려면 시간이 한참 걸리겠는데..." 박시니어 씨가 테이블 구조를 보여주며 설명했습니다. HTML 테이블은 어떤 구조일까요?
쉽게 비유하자면, HTML 테이블은 마치 엑셀 스프레드시트와 같습니다. 행(row)과 열(column)로 구성되어 데이터가 격자 형태로 배열되어 있습니다.
table 태그가 전체 표를 감싸고, 그 안에 tr 태그가 각 행을 나타내며, td 또는 th 태그가 각 셀을 나타냅니다. 이런 규칙적인 구조 덕분에 프로그램으로 처리하기 매우 좋습니다.
테이블을 수동으로 복사하면 어떤 문제가 있을까요? 수십 개, 수백 개의 행이 있는 경우 일일이 복사 붙여넣기를 하다 보면 실수가 발생합니다.
특히 셀 병합이 있거나 구조가 복잡한 경우 더욱 그렇습니다. 또한 데이터가 매일 업데이트되는 경우 매번 수작업을 반복해야 합니다.
시간도 많이 걸리고 지루합니다. BeautifulSoup으로 테이블을 추출하면 무엇이 좋을까요?
첫째, 자동화가 가능합니다. 한 번 코드를 작성하면 매일 자동으로 최신 데이터를 수집할 수 있습니다.
둘째, 정확합니다. 사람의 실수가 개입할 여지가 없습니다.
셋째, 추출한 데이터를 바로 엑셀, CSV, 데이터베이스 등 원하는 형태로 저장할 수 있습니다. 위의 코드를 단계별로 분석해보겠습니다.
먼저 **find('table')**로 테이블 요소를 찾습니다. 페이지에 테이블이 여러 개라면 class나 id로 구분합니다.
다음으로 **find_all('th')**로 헤더 셀들을 모두 찾아 리스트에 저장합니다. **.strip()**은 앞뒤 공백을 제거하는 메서드로, 깔끔한 데이터를 얻을 수 있습니다.
데이터 추출 부분을 자세히 살펴보겠습니다. **find_all('tr')[1:]**는 모든 행을 찾되, 첫 번째 행은 건너뜁니다.
왜냐하면 첫 행은 보통 헤더이기 때문입니다. 각 행에서 **find_all('td')**로 모든 셀을 찾습니다.
리스트 컴프리헨션을 사용하여 간결하게 작성했습니다. 마지막으로 빈 행이 있을 수 있으므로 **if cells:**로 체크합니다.
실제 프로젝트에서는 어떻게 활용할까요? 예를 들어 증권 사이트에서 주가 데이터를 수집한다고 가정해봅시다.
종목별 현재가, 등락률, 거래량 등이 테이블로 제공됩니다. 위의 방법으로 데이터를 추출한 후 pandas DataFrame으로 변환하면 강력한 데이터 분석이 가능합니다.
많은 퀀트 트레이딩 시스템이 이런 방식으로 데이터를 수집합니다. pandas와 결합하면 더욱 편리합니다.
사실 pandas에는 read_html() 함수가 있어 더 간단하게 테이블을 추출할 수 있습니다. df = pd.read_html(url)[0]처럼 한 줄로 가능합니다.
하지만 복잡한 전처리가 필요하거나 특정 조건의 데이터만 필요한 경우 BeautifulSoup을 직접 사용하는 것이 더 유연합니다. 주의할 점도 있습니다.
일부 테이블은 thead, tbody 태그로 헤더와 본문을 구분합니다. 이런 경우 table.find('tbody').find_all('tr')처럼 tbody 안에서만 검색해야 합니다.
또한 colspan이나 rowspan 속성으로 셀이 병합된 경우 구조가 복잡해질 수 있으니 주의해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
코드를 실행한 김개발 씨는 수백 개의 데이터가 순식간에 추출되는 것을 보고 놀랐습니다. "수작업으로 했다면 하루 종일 걸렸을 텐데!" 테이블 데이터 추출은 웹 스크래핑에서 매우 흔한 작업입니다.
여러분도 통계 사이트나 순위표에서 실습해보세요.
실전 팁
💡 - pandas.read_html()을 사용하면 더 간단하지만, 유연성은 BeautifulSoup이 더 높습니다
- 테이블 구조가 복잡하면 먼저 prettify()로 출력하여 구조를 파악하세요
- 셀 병합(colspan, rowspan)이 있는 테이블은 주의가 필요합니다
7. 스크래핑 윤리와 주의사항
김개발 씨가 본격적으로 스크래핑을 시작하려는데, 박시니어 씨가 진지하게 말했습니다. "잠깐, 시작하기 전에 꼭 알아야 할 윤리와 주의사항이 있어요.
기술적으로 가능하다고 해서 마음대로 해도 되는 건 아니에요."
웹 스크래핑은 강력한 도구이지만, 법적, 윤리적 책임이 따릅니다. robots.txt 파일을 확인하여 사이트 정책을 준수해야 하며, 과도한 요청으로 서버에 부담을 주지 않도록 적절한 딜레이를 두어야 합니다.
개인정보나 저작권이 있는 콘텐츠는 함부로 수집하면 안 되며, 수집한 데이터의 사용 목적도 명확해야 합니다.
다음 코드를 살펴봅시다.
import requests
from bs4 import BeautifulSoup
import time
# robots.txt 확인하기
robots_url = 'https://example.com/robots.txt'
robots = requests.get(robots_url)
print(robots.text)
# User-Agent 설정하기 (봇임을 명시)
headers = {
'User-Agent': 'MyBot/1.0 (contact@example.com)'
}
# 적절한 딜레이 두기
for page in range(1, 6):
url = f'https://example.com/page/{page}'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# 데이터 추출
# ...
# 서버 부담을 줄이기 위해 2초 대기
time.sleep(2)
print(f'{page}페이지 완료')
김개발 씨는 의아했습니다. "공개된 웹사이트인데 왜 안 되나요?" 박시니어 씨가 설명했습니다.
"공개되어 있다는 것과 마음대로 사용해도 된다는 것은 다른 문제예요." 웹 스크래핑 윤리란 무엇일까요? 쉽게 비유하자면, 웹사이트는 마치 공개된 도서관과 같습니다.
누구나 들어가서 책을 읽을 수 있지만, 그렇다고 책을 마음대로 복사하거나 도서관 규칙을 무시해도 되는 것은 아닙니다. 도서관마다 이용 규칙이 있듯이, 웹사이트도 각자의 정책과 규칙이 있습니다.
이것을 존중하는 것이 웹 스크래핑의 윤리입니다. 윤리를 지키지 않으면 어떻게 될까요?
첫째, 법적 문제가 발생할 수 있습니다. 한국의 경우 개인정보보호법, 저작권법 등에 저촉될 수 있습니다.
실제로 무단 스크래핑으로 인한 법적 분쟁 사례가 여럿 있습니다. 둘째, 서버 운영자가 여러분의 IP를 차단할 수 있습니다.
셋째, 과도한 요청으로 서버에 장애를 일으키면 다른 사용자에게 피해를 줍니다. 그렇다면 어떻게 윤리적으로 스크래핑할까요?
첫째, robots.txt 파일을 반드시 확인합니다. 이 파일은 웹사이트의 루트에 위치하며, 크롤러에게 허용되는 경로와 금지되는 경로를 명시합니다.
https://example.com/robots.txt처럼 접근할 수 있습니다. Disallow 항목에 명시된 경로는 스크래핑하면 안 됩니다.
둘째, User-Agent를 설정합니다. User-Agent는 요청을 보내는 클라이언트가 누구인지 알려주는 헤더입니다.
브라우저인 척하지 말고, 봇임을 명시하고 연락처를 포함하는 것이 바람직합니다. 서버 관리자가 문제를 발견했을 때 연락할 수 있도록 말이죠.
위의 코드처럼 'MyBot/1.0 (contact@example.com)' 형식으로 작성합니다. 셋째, 적절한 딜레이를 둡니다.
**time.sleep()**으로 요청 사이에 간격을 두어 서버 부담을 줄입니다. 1-2초 정도가 적당하며, 트래픽이 많은 시간대라면 더 길게 두는 것이 좋습니다.
절대로 초당 수십 개씩 요청을 보내면 안 됩니다. 이것은 사실상 디도스 공격과 다름없습니다.
실제 프로젝트에서는 어떤 점을 주의해야 할까요? 예를 들어 뉴스 기사를 수집한다고 가정해봅시다.
기사 제목과 요약 정도는 괜찮지만, 전문을 그대로 복사하여 상업적으로 사용하면 저작권 침해입니다. 또한 개인정보(이름, 이메일, 전화번호 등)는 절대 수집하면 안 됩니다.
수집한 데이터의 사용 목적이 합법적이고 윤리적인지 항상 고민해야 합니다. API가 제공된다면 API를 사용하세요.
많은 서비스가 공식 API를 제공합니다. 네이버, 카카오, 구글 등 대부분의 대형 서비스가 그렇습니다.
API는 서비스 제공자가 공식적으로 허용한 데이터 접근 방법이므로 안전하고 합법적입니다. 스크래핑보다 데이터 형식도 깔끔하고, 서버 부담도 적습니다.
가능하다면 항상 API를 우선 검토하세요. 주의할 점이 더 있습니다.
로그인이 필요한 페이지는 스크래핑하지 않는 것이 좋습니다. 이것은 서비스 약관 위반일 가능성이 높습니다.
또한 CAPTCHA가 있는 사이트는 자동화를 원하지 않는다는 명확한 신호입니다. 이것을 우회하려는 시도는 윤리적으로나 법적으로 문제가 됩니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.
"기술적으로 할 수 있다고 해서 다 해도 되는 건 아니군요. 책임감 있게 사용해야겠어요." 웹 스크래핑은 강력한 도구이지만, 그만큼 책임도 따릅니다.
여러분도 항상 윤리와 법률을 준수하며 스크래핑하세요.
실전 팁
💡 - robots.txt는 웹사이트의 정책을 담은 파일이니 반드시 확인하세요
- 요청 헤더에 User-Agent와 연락처를 포함하여 신뢰를 주세요
- API가 있다면 스크래핑보다 API 사용을 우선 검토하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.