학습 기록
Python 공부 기록 #9 - 여러 페이지 자동으로 긁어오기 (페이지네이션 크롤링)
- 목차
인트로: 1페이지만 긁으면 뭔가 아쉽다
URL 패턴 분석: 페이지 번호가 어디 숨어있나?
실습: 여러 페이지 크롤링하기
예의 바른 크롤러 되기: time.sleep()
실전: 명언 사이트 전체 페이지 수집
삽질했던 부분들
아웃트로: 이제 진짜 자동화 느낌이 난다 목차
- 인트로: 1페이지만 긁으면 뭔가 아쉽다
지난 포스팅에서 크롤링한 데이터를 Excel로 저장하는 데 성공했습니다.
근데 뿌듯한 것도 잠시였어요. 명언 사이트에 들어가 보니까 페이지가 10개나 있더라고요.
지금까지는 1페이지만 긁어왔는데, 이걸 10번 반복하려니 너무 귀찮았습니다.
“파이썬이 반복문 잘하잖아. 이것도 자동화되지 않을까?”
오늘은 여러 페이지를 자동으로 넘기면서 크롤링하는 방법을 정리합니다.
이걸 페이지네이션(Pagination) 크롤링이라고 부른다네요.
- URL 패턴 분석: 페이지 번호가 어디 숨어있나?
여러 페이지를 크롤링하려면 먼저 URL의 규칙을 찾아야 합니다.
명언 사이트 URL 분석
직접 페이지를 넘겨보면서 주소창을 확인해 봤습니다:
1페이지: http://quotes.toscrape.com/
2페이지: http://quotes.toscrape.com/page/2/
3페이지: http://quotes.toscrape.com/page/3/
…
10페이지: http://quotes.toscrape.com/page/10/
패턴 발견! 뒤에 /page/숫자/만 바꾸면 되는 구조네요.
흔한 URL 패턴들
찾아보니까 사이트마다 방식이 조금씩 달랐습니다:
타입 1: 경로에 페이지 번호
타입 2: 쿼리 파라미터 (?page=숫자)
http://example.com/search?page=2
타입 3: 오프셋 방식 (시작 위치)
http://example.com/list?offset=20
http://example.com/items?start=30
크롤링하기 전에 꼭 직접 페이지를 넘겨보면서 URL 변화를 확인해야 합니다. 저도 처음엔 이걸 안 하고 코드부터 짜다가 삽질했어요.
- 실습: 여러 페이지 크롤링하기
#python
1~5페이지 URL 만들기
for page_num in range(1, 6): # 1, 2, 3, 4, 5
url = f“http://quotes.toscrape.com/page/{page_num}/”
print(url)
기본 구조: for문으로 URL 바꾸기
출력:
http://quotes.toscrape.com/page/1/
http://quotes.toscrape.com/page/2/
http://quotes.toscrape.com/page/3/
http://quotes.toscrape.com/page/4/
http://quotes.toscrape.com/page/5/
f-string으로 {page_num} 부분만 바꿔주면 됩니다. 생각보다 간단하네요!
실제 크롤링 코드
#python
from bs4 import BeautifulSoup
import requests
all_quotes = [] # 전체 데이터를 담을 리스트
for page_num in range(1, 6): # 1~5페이지
url = f“http://quotes.toscrape.com/page/{page_num}/”
print(f“{page_num}페이지 크롤링 중…“)
response = requests.get(url, timeout=5)
if response.status_code == 200:
soup = BeautifulSoup(response.text, ‘lxml’)
quotes = soup.find_all(‘span’, class_=‘text’)
authors = soup.find_all(‘small’, class_=‘author’)
for i in range(len(quotes)):
all_quotes.append({
‘page’: page_num,
‘quote’: quotes[i].text.strip(‘“’),
‘author’: authors[i].text
})
else:
print(f“{page_num}페이지 실패: {response.status_code}“)
print(f“\n총 {len(all_quotes)}개의 명언을 수집했습니다!“)
출력:
1페이지 크롤링 중…
2페이지 크롤링 중…
3페이지 크롤링 중…
4페이지 크롤링 중…
5페이지 크롤링 중…
총 50개의 명언을 수집했습니다!
5페이지에서 50개가 나왔습니다. 한 페이지에 10개씩 있으니까 맞네요!
- 예의 바른 크롤러 되기: time.sleep()
왜 쉬어야 하나요?
처음에 코드 짜고 실행했더니 순식간에 5페이지를 다 긁어왔습니다. 근데 찾아보니까 이게 문제가 될 수 있다고 하더라고요.
서버 입장에서는 1초에 수십 번 요청이 들어오는 거라 부담됨
너무 빠르면 IP 차단당할 수 있음
법적으로도 “업무방해”로 문제될 수 있음
그래서 페이지마다 잠깐 쉬는 게 매너라고 합니다.
time.sleep() 쓰기
#python
import time
for page_num in range(1, 6):
url = f“http://quotes.toscrape.com/page/{page_num}/”
print(f“{page_num}페이지 크롤링 중…“)
response = requests.get(url, timeout=5)
… 크롤링 코드 …
time.sleep(1) # 1초 대기 후 다음 페이지로
time.sleep(0.5) # 0.5초도 괜찮음
실무 팁: 보통 0.5초에서 2초 정도 쉬는 게 적당하다고 합니다. 급하지 않으면 1초 정도 쉬는 게 안전해요.
랜덤하게 쉬기 (더 자연스럽게)
사람이 직접 클릭하는 것처럼 보이려면 쉬는 시간도 랜덤하게 하면 좋다고 합니다:
#python
import time
import random
for page_num in range(1, 6):
… 크롤링 코드 …
0.5~1.5초 사이 랜덤하게 대기
wait_time = random.uniform(0.5, 1.5)
time.sleep(wait_time)
- 실전: 명언 사이트 전체 페이지 수집
이제 배운 걸 다 합쳐서, 전체 페이지를 크롤링하고 Excel로 저장하는 코드를 만들어 봤습니다.
#python
from bs4 import BeautifulSoup
import requests
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
import time
import random
def crawl_all_pages(max_page=10):
“”“여러 페이지를 크롤링하는 함수”“”
all_quotes = []
for page_num in range(1, max_page + 1):
url = f“http://quotes.toscrape.com/page/{page_num}/”
print(f“[{page_num}/{max_page}] 크롤링 중…“)
try:
response = requests.get(url, timeout=5)
if response.status_code == 200:
soup = BeautifulSoup(response.text, ‘lxml’)
quotes = soup.find_all(‘span’, class_=‘text’)
authors = soup.find_all(‘small’, class_=‘author’)
데이터가 없으면 마지막 페이지로 판단
if not quotes:
print(f“ → {page_num}페이지에 데이터 없음. 종료.“)
break
for i in range(len(quotes)):
all_quotes.append({
‘page’: page_num,
‘quote’: quotes[i].text.strip(‘“”’),
‘author’: authors[i].text
})
print(f“ → {len(quotes)}개 수집 완료“)
else:
print(f“ → 실패: {response.status_code}“)
except requests.exceptions.RequestException as e:
print(f“ → 에러: {e}“)
예의 바르게 대기 (마지막 페이지는 제외)
if page_num < max_page:
wait = random.uniform(0.5, 1.5)
time.sleep(wait)
return all_quotes
def save_to_excel(data, filename=‘명언_전체.xlsx’):
“”“데이터를 Excel로 저장하는 함수”“”
wb = Workbook()
ws = wb.active
ws.title = “명언 데이터”
헤더
ws.append([‘번호’, ‘페이지’, ‘명언’, ‘작가’])
헤더 서식
for cell in ws[1]:
cell.font = Font(bold=True, color=“FFFFFF”)
cell.fill = PatternFill(start_color=“4472C4”, end_color=“4472C4”, fill_type=“solid”)
cell.alignment = Alignment(horizontal=‘center’)
데이터
for i, item in enumerate(data, 1):
ws.append([i, item[‘page’], item[‘quote’], item[‘author’]])
열 너비
ws.column_dimensions[‘A’].width = 8
ws.column_dimensions[‘B’].width = 8
ws.column_dimensions[‘C’].width = 80
ws.column_dimensions[‘D’].width = 20
wb.save(filename)
print(f“\n’{filename}’ 저장 완료!“)
실행
if name == “main”:
print(“=== 명언 크롤링 시작 ===\n”)
1. 크롤링
quotes_data = crawl_all_pages(max_page=10)
2. 저장
if quotes_data:
save_to_excel(quotes_data)
print(f“\n총 {len(quotes_data)}개의 명언을 수집했습니다!“)
else:
print(“수집된 데이터가 없습니다.”)
실행 결과:
=== 명언 크롤링 시작 ===
[1/10] 크롤링 중…
→ 10개 수집 완료
[2/10] 크롤링 중…
→ 10개 수집 완료
…
[10/10] 크롤링 중…
→ 10개 수집 완료
‘명언_전체.xlsx’ 저장 완료!
총 100개의 명언을 수집했습니다!
10페이지에서 100개 명언을 다 긁어왔습니다! Excel 파일도 예쁘게 저장됐고요.
코드 구조 설명
함수로 나눠서 만들어 봤습니다:
crawl_all_pages(): 크롤링만 담당
save_to_excel(): Excel 저장만 담당
이렇게 나누니까 나중에 크롤링 대상만 바꾸거나, 저장 형식만 바꾸기 편하더라고요.
지난번에 배운 함수의 장점이 여기서 나오네요!
- 삽질했던 부분들
① 1페이지 URL이 다른 경우
명언 사이트는 1페이지가 http://quotes.toscrape.com/인데, 코드에서는 /page/1/로 요청했거든요. 다행히 둘 다 작동했지만, 어떤 사이트는 안 될 수도 있습니다.
#python
안전하게 처리하는 방법
if page_num == 1:
url = “http://quotes.toscrape.com/”
else:
url = f“http://quotes.toscrape.com/page/{page_num}/”
② 마지막 페이지 판단하기
페이지가 몇 개인지 모를 때가 있습니다. 그럴 땐:
#python
방법 1: 데이터가 비어있으면 종료
if not quotes:
break
방법 2: “다음” 버튼이 있는지 확인
next_btn = soup.find(‘li’, class_=‘next’)
if not next_btn:
print(“마지막 페이지입니다.”)
break
저는 방법 1을 주로 쓰는데, 사이트마다 다르니까 직접 확인해 봐야 합니다.
③ 중간에 에러나면 데이터 날아감
10페이지 중 7페이지에서 에러가 나면 그동안 모은 데이터가 다 날아갑니다. 그래서 중간중간 저장하는 게 좋다고 합니다:
#python
5페이지마다 중간 저장
if page_num % 5 == 0:
save_to_excel(all_quotes, f’중간저장_{page_num}페이지.xlsx’)
print(f“ → 중간 저장 완료“)
- 아웃트로: 이제 진짜 자동화 느낌이 난다
오늘은 여러 페이지를 자동으로 크롤링하는 방법을 정리했습니다.
핵심 정리:
URL 패턴 분석: 페이지 번호가 어디 있는지 찾기
for문으로 반복: 숫자만 바꿔가며 요청
time.sleep(): 예의 바르게 쉬어주기
에러 처리: try-except로 안전하게
이제 할 수 있는 것들:
뉴스 사이트에서 기사 100개 수집
쇼핑몰에서 상품 정보 전체 긁어오기
커뮤니티에서 인기글 모아보기
다음 포스팅에서는 이 크롤러를 매일 자동으로 실행하는 방법(스케줄링)을 알아보겠습니다.
그러면 진짜 “출근하면 데이터가 모여있는” 자동화가 완성되겠죠!
혹시 설명 중에 틀린 부분이나 더 좋은 방법 있으면 알려주세요! 😊