서브페이지 데이터 스크래핑 프로세스
웹 스크래핑 작업을 수행할 때, 단일 페이지에서 모든 필요한 데이터를 얻을 수 없는 경우가 많습니다. 이러한 상황에서는 메인 페이지에서 서브페이지의 URL을 추출한 후, 각 서브페이지에 개별적으로 요청을 보내 원하는 데이터를 수집해야 합니다. 본 글에서는 Python의 requests 라이브러리와 정규식을 활용하여 서브페이지에서 데이터를 효과적으로 추출하는 방법을 단계별로 살펴보겠습니다.
1. 웹 요청 기본 설정
먼저 웹 서버에 요청을 보내고 응답을 받아오는 기본 코드를 작성합니다. 요청 시Headers 정보를 적절히 설정하는 것이 중요하며, SSL 인증서 검증 옵션도 상황에 따라 조정할 수 있습니다.
import requests
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
# SSL 경고 메시지 비활성화
disable_warnings(InsecureRequestWarning)
target_url = "https://example-crawler-site.com"
http_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7"
}
try:
response = requests.get(target_url, headers=http_headers, verify=False, timeout=10)
response.encoding = 'utf-8'
if response.status_code == 200:
print("페이지 응답 성공:")
print(response.text[:500])
else:
print(f"요청 실패: 상태 코드 {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"네트워크 오류 발생: {e}")
finally:
response.close()
2. 서브페이지 URL 추출하기
메인 페이지에서 원하는 섹션을 먼저 특정하고, 해당 섹션 내의 링크들을 정규식으로 추출합니다. 이 과정에서는 두 단계의 정규식 매칭을 사용하여 원하는 데이터만 정확하게 걸러낼 수 있습니다.
import requests
import re
target_url = "https://example-crawler-site.com"
http_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
try:
response = requests.get(target_url, headers=http_headers, verify=False, timeout=10)
response.encoding = 'utf-8'
# 첫 번째 정규식: 특정 섹션范围内的 HTML 추출
section_pattern = re.compile(r'추출할대상\s*:(?P.*?)정규식종료', re.DOTALL)
# 두 번째 정규식: 섹션 내의 링크 주소 추출
link_pattern = re.compile(r'href=["\'](?P[^"\']+)["\']', re.DOTALL)
section_match = section_pattern.search(response.text)
if section_match:
section_html = section_match.group('section_content')
link_matches = link_pattern.finditer(section_html)
extracted_links = []
for match in link_matches:
full_url = target_url + match.group('link_path')
extracted_links.append(full_url)
print(f"추출된 URL: {full_url}")
print(f"\n총 {len(extracted_links)}개의 서브페이지 URL을 찾았습니다.")
except requests.exceptions.RequestException as e:
print(f"오류 발생: {e}")
finally:
response.close()
3. 서브페이지에서 상세 데이터 수집
추출한 서브페이지 URL 목록을 순회하면서 각 페이지에 요청을 보내고, 필요한 정보를 정규식으로 추출합니다. 이 단계에서는 요청 간 적절한 대기 시간을 두거나, 에러 처리를 통해 안정적인 스크래핑 시스템을 구축할 수 있습니다.
import requests
import re
import time
target_url = "https://example-crawler-site.com"
http_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
# 섹션 추출 정규식
section_pattern = re.compile(r'추출할대상\s*:(?P.*?)정규식종료', re.DOTALL)
# 링크 추출 정규식
link_pattern = re.compile(r'href=["\'](?P[^"\']+)["\']', re.DOTALL)
# 상세 페이지에서 데이터 추출 정규식
detail_pattern = re.compile(
r'데이터명칭\s*:\s*(?P[^<]+)<br.*?'
r'연결주소\s*:\s*(?P[^&]+)&',
re.DOTALL
)
try:
# 메인 페이지 요청
response = requests.get(target_url, headers=http_headers, verify=False, timeout=10)
response.encoding = 'utf-8'
# 서브페이지 URL 목록 생성
page_urls = []
section_match = section_pattern.search(response.text)
if section_match:
section_html = section_match.group('section_content')
for link_match in link_pattern.finditer(section_html):
full_url = target_url + link_match.group('link_path')
page_urls.append(full_url)
print(f"총 {len(page_urls)}개의 서브페이지 처리 시작\n{'='*50}")
# 각 서브페이지에서 데이터 추출
collected_data = []
for index, page_url in enumerate(page_urls, 1):
try:
sub_response = requests.get(page_url, headers=http_headers, verify=False, timeout=10)
sub_response.encoding = 'utf-8'
data_match = detail_pattern.search(sub_response.text)
if data_match:
item_name = data_match.group('item_name').strip()
item_link = data_match.group('item_link').strip()
record = {"순번": index, "이름": item_name, "주소": item_link}
collected_data.append(record)
print(f"[{index}] {item_name}")
print(f" 연결: {item_link}")
else:
print(f"[{index}] 데이터를 찾을 수 없습니다: {page_url}")
sub_response.close()
time.sleep(1) # 서버 부하 방지를 위한 대기
except requests.exceptions.RequestException as e:
print(f"[{index}] 페이지 처리 중 오류: {e}")
continue
print(f"\n{'='*50}")
print(f"총 {len(collected_data)}개의 데이터 수집 완료")
except requests.exceptions.RequestException as e:
print(f"메인 페이지 요청 오류: {e}")
finally:
response.close()
중요한 고려사항
웹 스크래핑 작업을 진행할 때는 반드시 웹사이트의 robots.txt 파일을 확인하고, 서비스 약관을 준수해야 합니다. 또한 과도한 요청은 서버에 부하를 줄 수 있으므로 적절한 대기 시간을 설정하고,robots.txt에 명시된 크롤링 정책을 존중해야 합니다. 개인정보 보호와 저작권 관련 법규도 반드시 확인하여 합법적인 범위 내에서 스크래핑을 수행하시기 바랍니다.