CodeGym /자바 코스 /Python SELF KO /웹 스크래핑에서 에러 처리하기

웹 스크래핑에서 에러 처리하기

Python SELF KO
레벨 32 , 레슨 4
사용 가능

이 강의에 도달했다면, 이미 웹 스크래핑이 어떻게 작동하는지 그리고 멋진 BeautifulSoup를 사용하여 HTML에서 원하는 데이터를 추출하는 방법을 꽤 잘 알고 있을 거야. 하지만 웹 스크래핑의 세계가 교과서처럼 그렇게 순탄하지만은 않아. 데이터를 모으는 꿈이 에러와의 싸움으로 변하기도 하거든. 그래서 오늘은 어떻게 그 함정을 피하고 우리 스크래퍼를 최대한 견고하게 만들 수 있는지 이야기해볼게.

1. 웹 스크래핑에서 흔한 오류들

404 오류와 다른 HTTP 에러

고전적인 문제야: 페이지를 요청했는데, "404 Not Found"라는 자랑스러운 메시지가 돌아와. 이런 일은 페이지가 삭제되었거나 이동되었을 때 발생할 수 있어. 흔한 HTTP 에러로는 403 (Forbidden), 500 (Internal Server Error), 503 (Service Unavailable)이 있어.

HTML 구조 변경

데이터를 추출하기 위해 엄청난 시간을 들여 코드를 작성했는데, 다음 날 사이트가 "뽐내기" 위해 HTML 구조를 바꿔버렸어. 어, 다시 코드를 전부 써야 하네!

요청 수 제한

어떤 사이트는 하루 종일 웹 스크래퍼가 긁어가면 뭔가 이상하다는 걸 느끼기 시작해. 가장 좋은 경우엔 어느 정도 시간 동안 차단되고, 최악의 경우엔 영구 차단될 수도 있어.

대기 시간과 타임아웃

때로는 페이지 로드가 오래 걸려서, 대기 시간이 표준 타임아웃 시간을 초과하면 스크립트가 멈출 수 있어.

2. 에러 처리 방법

try-except 사용하기

스크립트가 모든 예기치 않은 일로부터 중단되지 않게 해야 해. try-except 블록을 추가하면 에러를 잡아내고 웹 스크래퍼가 중단되지 않고 계속 작동하도록 만들 수 있어.

Python

    import requests
    from bs4 import BeautifulSoup
    
    url = 'http://example.com/some-nonexistent-page'
    
    try:
        response = requests.get(url)
        response.raise_for_status()  # 나쁜 응답에 대해 HTTPError 발생
    except requests.exceptions.HTTPError as errh:
        print("HTTP Error:", errh)
    except requests.exceptions.ConnectionError as errc:
        print("Error Connecting:", errc)
    except requests.exceptions.Timeout as errt:
        print("Timeout Error:", errt)
    except requests.exceptions.RequestException as err:
        print("OOps: Something Else", err)
        

좋은 스크립트는 단순히 예외를 잡는 게 아니라, 에러 유형에 따른 대처 방법을 가지고 있어야 해. IP로 차단되었다면 다음 proxy로 넘어가고, 사이트가 다운되었다면 다른 걸 파싱하면 돼. 페이지에서 필요한 요소가 발견되지 않았다면, 파싱 스크립트를 업데이트하라고 알림을 보내서 이메일로 이를 전달하게 만들 수 있어.

로깅

"로그가 왜 필요해?"라고 생각할 수도 있어. 로그는 너의 두 번째 시야야. 로그를 통해 무엇이 잘못되었는지 파악하고 더 빠르게 문제를 해결할 수 있어.

Python

import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

try:
    # 스크래핑 코드
    pass
except Exception as e:
    logging.error("Exception occurred", exc_info=True)
    

타임아웃과 재시도 사용하기

때로는 기다렸다가 다시 시도하는 것이 필요할 때가 있어. 이런 상황에 타임아웃과 재시도가 적합해.

Python

try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
except requests.exceptions.Timeout:
    print("Timeout occurred. Retrying...")
    # 요청을 다시 시도하거나 다른 동작 수행
    

3. 견고한 스크래핑 사례

에러 처리가 포함된 간단한 스크래퍼

몇 가지 흔한 에러를 처리할 수 있는 작지만 신뢰할 수 있는 스크래퍼를 만들어보자.

Python

import requests
from bs4 import BeautifulSoup
import time
import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

url = 'http://example.com/some-nonexistent-page'

def fetch_html(url):
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()
        return response.text
    except requests.exceptions.HTTPError as errh:
        logging.error("HTTP Error: %s", errh)
    except requests.exceptions.ConnectionError as errc:
        logging.error("Error Connecting: %s", errc)
    except requests.exceptions.Timeout as errt:
        logging.warning("Timeout occurred. Retrying...")
        time.sleep(1)  # 잠시 기다렸다가 다시 시도
        return fetch_html(url)
    except requests.exceptions.RequestException as err:
        logging.error("OOps: Something Else %s", err)
    return None

html_content = fetch_html(url)
if html_content:
    soup = BeautifulSoup(html_content, 'html.parser')
    # 데이터 추출 코드
else:
    print("Failed to retrieve the page content.")
    

데이터 부분 저장하기

스크립트가 멈춰도 이미 추출된 데이터를 잃지 않도록 데이터를 부분적으로 저장해야 해. 예를 들어, 여러 페이지의 정보를 추출하면서 결과를 순차적으로 저장하면 데이터 손실 위험을 최소화할 수 있어.

Python

import csv

def save_to_csv(data, filename='data.csv'):
    with open(filename, mode='a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(data)
    

이렇게 하면 스크립트가 중간에 멈추더라도 데이터를 모두 잃지 않고 마지막 저장 상태에서 작업을 계속할 수 있어.

너가 파싱하는 페이지는 일부만 변경될 수 있고, 여전히 대부분의 데이터를 사용할 수 있어. 데이터를 잃는 것보다 일부만 빠진 상태에서 계속 진행하는 것이 더 나아.

1
Опрос
데이터 추출,  32 уровень,  4 лекция
недоступен
데이터 추출
데이터 추출
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION