파이썬으로 간단한 크롤링 프로그램 짜기

PYTHON PRACTICE GUIDE

웹페이지의 필요한 정보를 파이썬으로 가져오는 가장 쉬운 흐름

요청 → HTML 확인 → 파싱 → 선택 → 저장

웹 크롤링을 처음 배울 때는 복잡한 자동화부터 시작하기보다 공개 웹페이지의 HTML을 요청하고 필요한 요소를 추출하는 흐름부터 이해하는 것이 좋습니다. 파이썬에서는 requests로 페이지를 가져오고 BeautifulSoup으로 HTML을 분석하는 조합이 입문용으로 이해하기 쉽습니다. 다만 사이트의 이용약관과 접근 정책, robots.txt, 개인정보와 저작권을 확인하고 서버에 부담을 주지 않는 범위에서 사용하는 것이 기본입니다.

🐍 Python
🌐 requests
🍲 BeautifulSoup

🌐
REQUEST
페이지 가져오기 requests로 웹 서버에 HTTP 요청을 보내 HTML 응답을 받습니다.
🔎
PARSE
HTML 분석하기 BeautifulSoup으로 태그와 속성을 탐색할 수 있는 구조로 바꿉니다.
🎯
SELECT
필요한 정보 선택 CSS 선택자 등을 이용해 제목과 링크처럼 필요한 요소만 추출합니다.
💾
SAVE
결과 저장하기 수집한 데이터를 리스트나 CSV 파일 등 원하는 형태로 정리합니다.

웹 크롤링의 기본 원리 이해하기

웹 크롤링을 처음 접하면 화면에 보이는 글자를 프로그램이 그대로 읽어오는 기술이라고 생각하기 쉽습니다. 실제로는 웹 서버가 전달한 HTML 문서를 프로그램이 받아 구조를 분석하고, 그 안에서 필요한 태그나 속성을 찾아 데이터를 추출하는 과정으로 이해하는 편이 정확합니다.

 

브라우저에서 웹주소를 입력하면 브라우저는 서버에 요청을 보냅니다. 서버는 HTML을 비롯한 여러 자원을 돌려주고 브라우저는 이를 해석해 화면을 구성합니다. 파이썬 크롤링 프로그램도 기본 원리는 비슷하지만 화면을 예쁘게 표시하는 대신 HTML 안에서 필요한 데이터를 찾아내는 데 목적이 있습니다.

 

예를 들어 연습용 페이지에 여러 상품 제목이 <h2> 태그로 들어 있다면 프로그램은 해당 태그를 모두 찾아 텍스트만 추출할 수 있습니다. 링크가 <a> 태그의 href 속성에 들어 있다면 주소도 가져올 수 있습니다. 결국 초급 크롤링의 핵심은 HTML 구조를 읽고 원하는 요소를 정확히 지정하는 능력입니다.

 

제가 초보자에게 크롤링을 설명할 때 가장 먼저 강조하는 부분도 선택자보다 HTML 구조입니다. 원하는 정보가 어느 태그에 있고 어떤 class나 id를 갖는지 먼저 파악하면 코드는 오히려 단순해집니다. 반대로 페이지 구조를 확인하지 않고 예제 코드를 그대로 붙여 넣으면 대상 사이트가 달라지는 순간 결과가 나오지 않는 경우가 많습니다.

단계 하는 일
요청 웹 서버에 페이지를 요청합니다.
응답 서버가 전달한 HTML과 상태 코드를 확인합니다.
파싱 HTML을 탐색하기 쉬운 구조로 분석합니다.
추출 태그와 선택자를 이용해 필요한 텍스트나 링크를 찾습니다.
저장 리스트나 CSV 등 필요한 형태로 데이터를 정리합니다.

💡 처음 연습할 때: 로그인이나 복잡한 동적 페이지보다 크롤링 연습을 허용하는 공개 테스트 페이지나 자신이 관리하는 HTML에서 시작하는 것이 좋습니다. 구조가 단순해야 요청과 파싱, 선택자의 관계를 명확하게 익힐 수 있습니다.

파이썬 크롤링 환경 준비하기

정적인 HTML을 읽는 간단한 프로그램이라면 처음부터 무거운 도구가 필요하지 않습니다. 파이썬과 코드 편집기를 준비한 뒤 HTTP 요청을 담당하는 requests와 HTML 분석을 담당하는 BeautifulSoup을 설치하면 기본 실습을 시작할 수 있습니다.

 

pip install requests beautifulsoup4

설치가 끝났다면 파이썬 파일에서 두 라이브러리를 불러옵니다. requests는 웹 서버와 통신하고 BeautifulSoup은 응답으로 받은 HTML 문자열을 태그 단위로 탐색할 수 있도록 분석합니다. 두 도구의 역할을 구분해서 이해하면 오류가 발생했을 때 어느 단계에서 문제가 생겼는지도 찾기 쉬워집니다.

 

import requests
from bs4 import BeautifulSoup

프로젝트마다 별도의 가상환경을 사용하는 습관도 도움이 됩니다. 여러 프로젝트를 만들다 보면 라이브러리 버전이 달라질 수 있는데 가상환경을 분리하면 프로젝트별 의존성을 관리하기 편합니다. 다만 첫 실습에서는 requests와 BeautifulSoup이 어떤 역할을 하는지 익히는 데 집중해도 충분합니다.

도구 주요 역할 초보자 포인트
Python 프로그램 실행 기본 문법과 반복문 이해
requests HTTP 요청과 응답 처리 상태 코드와 타임아웃 확인
BeautifulSoup HTML 구조 분석 find와 select 익히기
개발자 도구 HTML 구조 확인 태그·class·id 위치 확인
처음 준비할 때 확인할 순서
🐍파이썬 확인: 터미널에서 파이썬이 정상적으로 실행되는지 확인합니다.
📦라이브러리 설치: requests와 beautifulsoup4 패키지를 준비합니다.
🧪테스트: 간단한 페이지에 요청을 보내 상태 코드가 정상인지 확인합니다.

💡 실무 습관: 네트워크 요청에는 타임아웃을 설정하는 편이 좋습니다. 상대 서버가 응답하지 않을 때 프로그램이 오랫동안 대기하는 상황을 줄일 수 있고 예외 처리를 추가하기도 쉬워집니다.

requests와 BeautifulSoup 사용하기

가장 기본적인 요청은 requests.get()으로 만들 수 있습니다. URL을 전달하면 서버의 응답 객체를 받을 수 있고 status_code로 HTTP 상태 코드를 확인할 수 있습니다. 응답이 성공했다고 판단된 뒤 HTML을 파싱하는 순서로 코드를 작성하면 문제를 구분하기 쉽습니다.

 

import requests
from bs4 import BeautifulSoup

url = “https://example.com”

try:
response = requests.get(url, timeout=10)
response.raise_for_status()

soup = BeautifulSoup(response.text, “html.parser”)
print(soup.title.get_text(strip=True))

except requests.RequestException as error:
print(“요청 오류:”, error)

이 코드에서 중요한 부분은 response.text와 BeautifulSoup입니다. response.text에는 서버가 돌려준 텍스트 응답이 들어 있고 BeautifulSoup은 이 문자열을 HTML 구조로 분석합니다. 이후 soup.title처럼 특정 태그에 접근하거나 find(), find_all(), select(), select_one() 등을 사용해 원하는 요소를 찾을 수 있습니다.

 

실습하면서 특히 유용한 것은 CSS 선택자를 사용할 수 있는 select()입니다. 예를 들어 class가 product인 요소 안의 h2를 찾는다면 .product h2처럼 표현할 수 있습니다. 브라우저 개발자 도구에서 HTML 구조를 살펴본 뒤 선택자를 짧게 만들어 테스트하면 유지보수하기도 편합니다.

BeautifulSoup에서 자주 쓰는 방법
1️⃣find(): 조건에 맞는 첫 번째 요소를 찾을 때 사용합니다.
2️⃣find_all(): 조건에 맞는 여러 요소를 한꺼번에 찾습니다.
3️⃣select(): CSS 선택자로 여러 요소를 선택합니다.
4️⃣get_text(): 태그를 제외하고 사람이 읽는 텍스트 부분을 추출합니다.
코드 의미 활용
soup.find(“h1”) 첫 h1 탐색 대표 제목 추출
soup.find_all(“a”) 모든 a 탐색 링크 목록 확인
soup.select(“.item”) item 클래스 탐색 반복 데이터 추출

💡 디버깅 팁: 원하는 데이터가 나오지 않으면 선택자부터 계속 바꾸기보다 먼저 response.status_code와 응답 HTML 일부를 확인합니다. 브라우저에서 보는 화면과 requests가 받은 HTML이 다르다면 자바스크립트 렌더링이나 접근 정책 등 다른 원인을 살펴봐야 합니다.

간단한 크롤링 프로그램 직접 만들기

이제 연습용 페이지의 제목과 링크를 수집하는 형태로 코드를 조합해보겠습니다. 실제 사이트마다 HTML 구조는 다르기 때문에 아래 선택자는 대상 페이지 구조에 맞게 변경해야 합니다. 핵심은 요청과 상태 확인, 파싱, 요소 선택, 반복 처리라는 전체 흐름을 익히는 것입니다.

 

import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

url = “https://example.com”

headers = {
“User-Agent”: “LearningCrawler/1.0”
}

try:
response = requests.get(
url,
headers=headers,
timeout=10
)
response.raise_for_status()

soup = BeautifulSoup(
response.text,
“html.parser”
)

items = soup.select(“a”)

for item in items:
title = item.get_text(
” “,
strip=True
)
href = item.get(“href”)

if not title or not href:
continue

full_url = urljoin(url, href)

print(“제목:”, title)
print(“링크:”, full_url)
print(“-” * 30)

time.sleep(1)

except requests.RequestException as error:
print(“페이지 요청 실패:”, error)

이 예제에서는 a 태그를 대상으로 했기 때문에 페이지에 있는 링크가 폭넓게 선택됩니다. 실제로는 .article-list a처럼 필요한 영역을 좁히는 선택자를 사용하는 편이 좋습니다. 선택 범위가 정확할수록 메뉴나 광고, 푸터처럼 원하지 않는 데이터가 결과에 섞이는 문제를 줄일 수 있습니다.

 

urljoin()도 알아두면 편리합니다. HTML 링크가 /news/123처럼 상대 경로로 작성되어 있으면 그대로 저장했을 때 완전한 주소가 아닙니다. urljoin()은 기준 URL과 상대 경로를 조합해 완전한 주소로 만드는 데 도움을 줍니다.

좋은 크롤링 코드의 기본 습관
✅상태 코드 확인: 요청이 정상적으로 처리됐는지 확인한 뒤 파싱합니다.
⏱️타임아웃: 응답이 없는 서버를 무기한 기다리지 않도록 제한을 둡니다.
🐢요청 간격: 반복 수집에서는 대상 서버에 부담을 주지 않도록 충분한 간격을 둡니다.
🎯선택자 최소화: 필요한 콘텐츠 영역만 구체적으로 선택합니다.
🧯예외 처리: 네트워크 오류가 발생해도 원인을 확인할 수 있도록 처리합니다.
피해야 할 크롤링 습관
❌사이트의 이용약관이나 접근 정책을 확인하지 않고 자동 수집부터 시작하지 않습니다.
❌짧은 시간에 과도한 요청을 반복해 상대 서버에 부담을 주지 않습니다.
❌로그인이나 접근 제한을 임의로 우회하는 방식으로 데이터를 수집하지 않습니다.
❌개인정보나 민감한 데이터를 무분별하게 수집하고 저장하지 않습니다.
❌수집 가능 여부와 재사용 권한을 같은 개념으로 생각하지 않습니다.

💡 중요: 기술적으로 읽을 수 있는 페이지라고 해서 자동 수집과 데이터 재사용이 항상 허용되는 것은 아닙니다. 실제 프로그램을 운영하기 전에는 해당 서비스의 이용약관과 robots.txt, 제공되는 공식 API 여부, 저작권과 개인정보 관련 조건을 목적에 맞게 확인하는 습관이 필요합니다.

수집한 데이터를 CSV로 저장하기

화면에 print()로 출력하는 단계까지 성공했다면 다음에는 결과를 파일로 저장해보는 것이 좋습니다. 데이터를 리스트에 차곡차곡 담은 뒤 CSV 파일로 기록하면 스프레드시트 프로그램이나 다른 파이썬 프로그램에서 다시 활용하기 편합니다. 파이썬 기본 라이브러리인 csv만으로도 간단한 저장 기능을 만들 수 있습니다.

 

import csv
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

url = “https://example.com”

response = requests.get(
url,
timeout=10
)
response.raise_for_status()

soup = BeautifulSoup(
response.text,
“html.parser”
)

results = []

for item in soup.select(“a”):
title = item.get_text(
” “,
strip=True
)
href = item.get(“href”)

if not title or not href:
continue

results.append({
“title”: title,
“url”: urljoin(url, href)
})

with open(
“result.csv”,
“w”,
newline=””,
encoding=”utf-8-sig”
) as file:
writer = csv.DictWriter(
file,
fieldnames=[“title”, “url”]
)

writer.writeheader()
writer.writerows(results)

print(
f”{len(results)}개 항목을 저장했습니다.”
)

여기서는 수집 결과 하나를 딕셔너리 형태로 만들고 results 리스트에 추가했습니다. 수집이 끝나면 DictWriter를 이용해 title과 url이라는 열을 가진 CSV를 생성합니다. 데이터 구조와 저장 과정을 분리하면 나중에 날짜나 카테고리 같은 필드를 추가할 때도 코드를 수정하기 편합니다.

 

제가 작은 수집 프로그램을 구성할 때도 처음부터 데이터베이스를 붙이기보다 리스트와 CSV로 데이터 모양을 먼저 확인하는 방식을 자주 씁니다. 선택자가 틀려 메뉴 이름까지 들어오거나 제목이 비어 있는 경우를 파일에서 쉽게 발견할 수 있기 때문입니다. 추출 결과가 안정된 뒤 저장 구조를 확장하면 디버깅할 범위가 줄어듭니다.

 

문자 인코딩도 초보자가 자주 만나는 문제입니다. 한글 데이터를 저장했는데 특정 스프레드시트 프로그램에서 글자가 깨진다면 파일을 기록할 때 사용하는 인코딩을 확인해야 합니다. 위 예제에서는 한글 호환성을 고려해 utf-8-sig를 사용했지만 이후 데이터를 사용하는 환경에 따라 일반 UTF-8 등 적절한 방식을 선택하면 됩니다.

수집 프로그램을 만드는 순서
1

HTML 구조부터 확인합니다

제목과 링크가 들어 있는 태그와 class, id를 확인하고 필요한 데이터 범위를 정합니다.

2

한 페이지부터 테스트합니다

처음부터 수백 페이지를 반복하지 말고 한 번의 요청으로 원하는 정보가 정확하게 나오는지 검증합니다.

3

데이터를 정리합니다

공백과 빈 데이터, 중복 항목을 확인하고 제목과 URL 같은 필드 구조를 통일합니다.

4

파일로 저장합니다

결과가 정확한 것을 확인한 다음 CSV나 필요한 저장소에 기록하고 이후 반복 범위를 확장합니다.

🚨 반복 요청 주의: 페이지 번호만 바꿔 짧은 시간에 대량 요청을 보내는 코드는 상대 서버에 부담을 줄 수 있습니다. 실제 사이트를 대상으로 할 때는 자동 접근 정책과 요청 빈도 제한을 확인하고 필요한 최소 범위만 수집해야 합니다.

크롤링이 안 될 때 확인할 부분

예제 코드는 정상인데 실제 페이지에서는 원하는 정보가 나오지 않는 경우가 있습니다. 가장 먼저 확인할 것은 응답 상태와 실제로 받은 HTML입니다. 브라우저 화면에 제목이 보인다고 해서 서버가 처음 전달하는 HTML 안에도 그 제목이 반드시 포함되어 있는 것은 아닙니다. 자바스크립트가 실행된 뒤 별도의 데이터 요청을 통해 화면이 만들어지는 사이트도 있기 때문입니다.

 

이런 페이지에서 requests로 받은 HTML을 검색해보면 원하는 텍스트가 아예 없을 수 있습니다. 이 상황에서는 BeautifulSoup 선택자를 아무리 바꿔도 데이터가 나오지 않습니다. 먼저 HTML에 데이터가 실제 존재하는지를 확인하고 동적으로 생성되는 구조라면 해당 서비스가 공식 API나 적절한 데이터 제공 방법을 제공하는지 확인하는 것이 우선입니다.

 

선택자 변경도 흔한 원인입니다. 웹사이트 운영자가 디자인을 개편하면서 article-title이라는 class를 post-title로 바꾸면 기존 크롤러는 더 이상 데이터를 찾지 못합니다. 그래서 운영용 프로그램이라면 수집 건수가 갑자기 0이 되거나 평소보다 크게 줄었을 때 알 수 있도록 로그와 검증 절차를 두는 편이 좋습니다.

 

응답 코드도 중요한 단서입니다. 정상 응답과 리디렉션, 접근 제한, 서버 오류는 원인이 서로 다릅니다. 무조건 response.text부터 파싱하기보다 상태 코드를 기록하고 raise_for_status()나 명시적인 조건문으로 오류를 구분하면 원인을 찾는 시간이 크게 줄어듭니다.

 

한글이 깨지는 경우에는 응답 인코딩도 살펴봐야 합니다. requests가 추정한 문자 인코딩과 실제 문서 인코딩이 다르면 텍스트가 깨져 보일 수 있습니다. 다만 인코딩 문제와 선택자 문제를 동시에 수정하려고 하면 원인 파악이 어려워지므로 요청 성공 여부, HTML 존재 여부, 선택자, 문자 처리 순으로 하나씩 점검하는 것이 좋습니다.

증상 가능한 원인 먼저 확인할 것
요청 자체가 실패 주소·네트워크·접근 정책 상태 코드와 예외 메시지
결과가 빈 목록 선택자 불일치 실제 응답 HTML 구조
브라우저와 내용이 다름 동적 렌더링 가능성 response.text에 데이터 존재 여부
한글이 깨짐 문자 인코딩 불일치 응답 헤더와 문서 인코딩

💡 문제 해결 순서: 요청 성공 여부 → 실제 응답 HTML → 원하는 데이터 존재 여부 → 선택자 → 텍스트 정제 → 저장 결과 순서로 확인하면 좋습니다. 크롤링 오류는 한꺼번에 수정하려 하기보다 데이터가 어느 단계까지 정상적으로 전달되는지를 추적하는 방식이 훨씬 효율적입니다.

자주 묻는 질문 Q&A

Q 파이썬 초보자도 크롤링을 만들 수 있나요?

가능합니다. 변수와 리스트, 반복문, 조건문, 함수 정도의 기본 문법을 알고 있다면 정적인 HTML 페이지를 대상으로 하는 간단한 프로그램은 충분히 연습할 수 있습니다. 처음에는 복잡한 사이트보다 HTML 구조가 단순한 테스트 페이지에서 제목 하나를 추출하는 것부터 시작하는 것이 좋습니다.

Q requests만 사용하면 모든 웹페이지를 수집할 수 있나요?

그렇지 않습니다. requests는 HTTP 통신에 유용하지만 브라우저에서 자바스크립트가 실행된 뒤 데이터가 만들어지는 페이지에서는 처음 받은 HTML에 원하는 내용이 없을 수 있습니다. 이런 경우에는 먼저 공식 API나 제공되는 데이터 접근 방법이 있는지 확인하고 사이트의 접근 정책에 맞는 방식을 선택해야 합니다.

Q BeautifulSoup과 requests는 같은 역할인가요?

역할이 다릅니다. requests는 웹 서버에 요청을 보내고 응답을 받는 역할을 하며 BeautifulSoup은 받은 HTML을 분석해 태그와 텍스트를 찾는 역할을 합니다. 요청과 분석을 분리해서 생각하면 전체 코드 흐름을 훨씬 쉽게 이해할 수 있습니다.

Q 크롤링과 공식 API 중 무엇을 먼저 사용해야 하나요?

서비스가 목적에 맞는 공식 API를 제공한다면 우선 검토하는 편이 좋습니다. API는 보통 데이터 구조와 호출 규칙이 명확해 HTML 디자인 변경의 영향을 덜 받을 수 있습니다. 반면 HTML 크롤링은 페이지 구조가 바뀌면 선택자를 수정해야 할 수 있으므로 장기 운영에서는 유지보수 비용까지 고려해야 합니다.

Q 웹페이지에 공개된 정보라면 자유롭게 수집해도 되나요?

공개적으로 볼 수 있다는 사실만으로 자동 수집과 저장, 재사용이 모두 허용된다고 단정할 수는 없습니다. 대상 사이트의 이용약관과 자동 접근 정책, robots.txt, 개인정보와 저작권, 데이터 사용 목적을 확인해야 합니다. 특히 상업적 활용이나 대규모 수집은 서비스 정책과 관련 법적 조건을 별도로 검토하는 것이 안전합니다.

핵심 요약 한눈에 보기

항목 핵심 내용
크롤링 웹페이지를 요청하고 HTML에서 필요한 데이터를 프로그램으로 추출하는 과정입니다.
requests HTTP 요청을 보내고 서버의 상태 코드와 HTML 응답을 받습니다.
BeautifulSoup HTML 구조를 분석하고 원하는 태그와 텍스트를 탐색합니다.
선택자 class와 id, 태그 구조를 이용해 필요한 콘텐츠 범위를 구체적으로 지정합니다.
오류 처리 타임아웃과 상태 코드, 예외 처리를 이용해 네트워크 문제를 구분합니다.
CSV 저장 추출한 제목과 링크 등을 일정한 필드로 정리해 파일로 저장할 수 있습니다.
동적 페이지 브라우저 화면과 최초 HTML이 다를 수 있으므로 실제 응답에 데이터가 존재하는지 먼저 확인합니다.
운영 원칙 요청 횟수와 간격을 조절하고 대상 서비스에 불필요한 부담을 주지 않도록 합니다.
이용 조건 자동 접근 정책과 이용약관, robots.txt, 개인정보와 저작권, 공식 API 제공 여부를 확인합니다.

파이썬 크롤링을 처음 배울 때 가장 중요한 것은 복잡한 자동화 기술이 아니라 요청 → 응답 확인 → HTML 파싱 → 요소 선택 → 데이터 정리 → 저장이라는 흐름을 정확하게 이해하는 것입니다. requests와 BeautifulSoup만으로도 정적인 HTML 페이지의 제목과 링크를 추출하는 기본 프로그램을 만들 수 있습니다. 원하는 값이 나오지 않을 때는 선택자를 무작정 수정하기보다 실제 응답 HTML에 데이터가 존재하는지부터 확인하는 습관이 중요합니다. 한 페이지에서 정확한 결과를 만드는 데 성공한 다음 오류 처리와 요청 간격, CSV 저장을 추가하면 훨씬 안정적인 프로그램으로 발전시킬 수 있습니다. 실제 사이트에 적용할 때는 기술적인 구현과 별개로 해당 서비스의 자동 접근 정책과 이용약관, 데이터 이용 조건을 확인하는 것이 크롤링 프로그램을 만드는 과정의 중요한 일부입니다.

댓글 남기기