1. 스크립트에서 오류 처리
웹 스크래핑의 문제점
상상해보세요: 여러분의 스크립트가 멋지게 준비된 상태로 있다가 갑자기 바나나 껍질에서 미끄러지듯 문제가 발생한다면 어떨까요? 오류와 장애로 인해 곤란할 수 있겠죠. 인터넷이라는 험난한 환경에서 스크립트를 살아남게 하려면 어떻게 해야 할까요? 오늘은 스크립트에 두 가지 중요한 기술, 즉 인내와 재시도를 가르쳐 줄 거예요. 네, 바로 재시도와 타임아웃을 설정하는 방법을 배우는 겁니다.
웹 스크래핑은 즐겁지만, 스크립트가 다음과 같은 이유로 갑자기 종료될 수 있어요:
- 연결 장애.
- 서버의 일시적 불가.
- HTML 구조의 예기치 못한 변경.
여러분의 스크립트는 제다이처럼 예기치 않은 상황에 대처할 준비가 되어 있어야 해요. 때로는 단순히 잠시 기다렸다가 요청을 다시 시도하면 문제를 해결할 수 있습니다. 이럴 때 등장하는 멋진 주인공이 바로 재시도와 타임아웃이에요!
오류 처리 메커니즘 소개
먼저 기본적인 것을 복습해볼까요? Python의 오류 처리입니다. try-except
블록을 사용해서 스크립트의 작업을 방해하지 않도록 오류를 관리할 수 있습니다.
import requests
try:
response = requests.get('https://example.com')
response.raise_for_status() # 요청 성공 여부 확인
except requests.exceptions.RequestException as e:
print(f'오류가 발생했습니다: {e}')
2. 재시도 설정
왜 재시도를 사용해야 하나요?
한번의 실패로 바로 포기하는 스크립트는 갑작스러운 비를 두려워하는 고양이와 같아요. 하지만 여러분은 몇 가지 불편함을 잘 극복하는 스크립트를 원하겠죠. 그래서 우리는 재시도를 설정해서 스크립트가 더 자신감 있게 동작하도록 합니다.
재시도 설정 방법
이제 재시도를 어떻게 설정할 수 있는지 알아볼게요. 가장 간단한 방법 중 하나는 urllib3
라이브러리를 사용하는 것이에요. 이 라이브러리는 오류 발생 시 요청을 자동으로 다시 보낼 수 있는 기능을 제공합니다.
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
import requests
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
try:
response = session.get('https://example.com')
response.raise_for_status()
print(response.content)
except requests.exceptions.RequestException as e:
print(f'오류가 발생했습니다: {e}')
이 예제에서 우리는 session
을 생성하고 재시도 메커니즘(Retry
)을 적용했습니다. 최대 5번의 재시도를 하도록 설정했고, 실패 코드가 500, 502, 503, 504일 때만 재시도하겠다고 지정했어요.
backoff_factor=1
은 재시도 사이의 시간이 지수 형태로 증가할 것이라는 의미에요 (1, 2, 4, 8... 초).
3. 타임아웃: 멈춰있는 상태 방지
지루한 기다림에 종지부를 찍자
타임아웃은 알람 시계와 같아요: 서버 응답을 기다리다가 멈추지 않도록 도와줍니다. 타임아웃을 설정하면 여러분의 스크립트에게 "이제 그만 기다려! 서버가 정해진 시간 안에 응답하지 않으면 다른 작업을 하러 가자!"라고 말하는 겁니다.
try:
response = requests.get('https://example.com', timeout=10)
response.raise_for_status()
print(response.content)
except requests.exceptions.Timeout:
print('요청이 대기 시간을 초과했습니다')
except requests.exceptions.RequestException as e:
print(f'오류가 발생했습니다: {e}')
왜 필요한가요?
여러분의 스크립트가 서버의 응답을 기다리느라 멈춰버린 적이 있나요? 타임아웃은 불필요한 대기를 방지하고 코드가 빠르게 복구하여 작업을 계속하도록 합니다. 여러분의 스크립트를 "그 시간 동안 몇 번의 휴식을 다녀올 수 있었을 것 같은데!"라고 느끼게 만들지 마세요!
4. 설정 예제
재시도를 적용한 안정적인 스크립트 구현
이제 아이언맨의 갑옷처럼 안정적인 스크립트를 만들어 봅시다. 타임아웃과 재시도를 둘 다 사용할 거예요.
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
import requests
def fetch_url(url):
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
try:
response = session.get(url, timeout=10)
response.raise_for_status()
return response.content
except requests.exceptions.Timeout:
print('요청이 대기 시간을 초과했습니다')
except requests.exceptions.RequestException as e:
print(f'오류가 발생했습니다: {e}')
return None
content = fetch_url('https://example.com')
if content:
print('데이터를 성공적으로 다운로드했습니다!')
스크립트 멈춤 방지를 위한 타임아웃 사용
우리는 이미 타임아웃을 설정하는 방법을 보여줬어요. 이제 스크립트가 안정적일 뿐만 아니라 긴 대기에 합리적으로 대처하는지도 확인해봅시다. "서버가 너무 오래 생각하고 있어, 나는 더 이상 기다릴 수 없어!"라고 말하며 여러분에게 경고를 보낼 겁니다.
이렇게 간단하고 명확한 접근 방식을 통해 여러분의 코드는 인터넷에서 발생할 수 있는 여러 가지 예기치 못한 상황에 잘 대비한 신뢰할 수 있는 스크립트가 될 거예요.
실용적인 응용
실제 스크래핑 프로젝트를 개발할 때 서버의 여러 제한에 자주 직면하게 됩니다. 재시도와 타임아웃은 장애 위험을 최소화하는 데 있어 가장 좋은 친구가 될 것입니다. 이러한 기술을 통해 데이터를 자동으로 처리하고 정확한 결과를 제시간에 얻는 것이 중요한 경우, 여러분의 코드의 안정성을 높이고 고객 신뢰도를 향상시킬 수 있습니다.
GO TO FULL VERSION