웹 스크래핑 기초: 서브페이지에서 데이터 추출하는 방법

서브페이지 데이터 스크래핑 프로세스

웹 스크래핑 작업을 수행할 때, 단일 페이지에서 모든 필요한 데이터를 얻을 수 없는 경우가 많습니다. 이러한 상황에서는 메인 페이지에서 서브페이지의 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에 명시된 크롤링 정책을 존중해야 합니다. 개인정보 보호와 저작권 관련 법규도 반드시 확인하여 합법적인 범위 내에서 스크래핑을 수행하시기 바랍니다.

태그: python requests 정규표현식 웹스크래핑 데이터추출

9월 8일 07:27에 게시됨