Table of contents
데이터 스크래핑은 정보 수집의 핵심 도구입니다. 하지만 때로는 예상치 못한 문제가 발생합니다. 오늘은 제가 데이터 스크래핑 프로젝트에서 마주한 문제들과 그 해결 과정을 공유하려고 합니다.
문제 1: 데이터베이스 락 문제
상황: MySQL 데이터베이스에 뉴스 데이터를 저장할 때, 여러 스크래퍼가 동시에 작동하면서 락 문제가 발생했습니다. 상상해보세요, 마치 많은 사람들이 동시에 하나의 문을 통과하려는 것처럼 혼란스러웠죠.
데이터베이스 락(Lock) 문제
데이터베이스에서 "락"은 동시에 여러 트랜잭션이 같은 데이터에 접근할 때 발생하는 일종의 충돌 방지 메커니즘입니다. 예를 들어, 여러 스크래퍼가 동시에 데이터베이스에 데이터를 쓰려고 할 때, 이들 간의 충돌을 방지하기 위해 데이터베이스는 특정 데이터나 테이블에 "락"을 걸어 다른 트랜잭션이 해당 부분을 사용하지 못하게 합니다. 이는 데이터의 일관성과 정확성을 유지하기 위해 필요하지만, 동시에 많은 요청이 발생할 경우 성능 저하나 대기 시간 증가의 원인이 될 수 있습니다.
해결 방법: 저는 문제를 해결하기 위해 "대량 삽입" 기법을 적용했습니다. 즉, 여러 개의 데이터를 모아 한 번에 데이터베이스에 저장하는 방식이죠.
대량 삽입 기법을 이용한 해결 방법
문제 해결을 위해 데이터를 개별적으로 저장하는 대신, 여러 뉴스 데이터를 모아 한 번에 데이터베이스에 저장하는 "대량 삽입(Bulk Insert)" 기법을 적용했습니다. 이 방법은 데이터베이스에 대한 요청 횟수를 줄여 락 경합을 감소시키고, 전체적인 성능을 향상시킵니다.
코드 예시:
def save_news_data_bulk(self, news_data_list):
with self.database_session() as session:
# 여러 개의 뉴스 데이터를 한 번에 데이터베이스에 저장
try:
session.bulk_save_objects(news_data_list)
session.commit()
print(f"{len(news_data_list)}개의 뉴스 데이터가 성공적으로 저장되었습니다.")
except Exception as e:
print(f"데이터 저장 중 오류 발생: {e}")
session.rollback()
위의 코드 예시에서 save_news_data_bulk
함수는 news_data_list
에 저장된 여러 뉴스 데이터를 한 번에 데이터베이스에 저장합니다. bulk_save_objects
메서드를 사용하여 성능을 최적화하고, 만약 오류가 발생하면 rollback
을 통해 트랜잭션을 되돌립니다. 이 방식은 데이터베이스의 락 문제를 상당 부분 완화시켜 줍니다.
문제 2: 중복 스크래핑 문제
상황: 같은 뉴스를 여러 번 스크래핑하는 문제가 있었습니다. 이는 마치 같은 신문을 여러 번 구매하는 것과 같아 비효율적이었죠.
해결 방법: 해결책으로, 최근 스크래핑한 URL의 MD5 해시를 deque
를 사용해 저장했습니다. 이렇게 함으로써, 이미 처리된 URL은 건너뛰어 시간과 자원을 절약할 수 있었습니다.
코드 예시:
from collections import deque
class NewsScraper:
def __init__(self):
self.scraped_md5s = deque(maxlen=10000)
def generate_md5(self, url):
# URL의 MD5 생성
# ...
def is_already_scraped(self, url):
# 중복 스크래핑 방지 로직
# ...
결과 및 이점
이러한 변경을 통해, 데이터베이스의 락 문제는 감소했고, 중복 스크래핑 문제도 해결되었습니다. 이는 전체적인 프로세스의 효율성을 크게 향상시켰습니다.
결론 및 교훈
데이터 스크래핑은 도전적이지만, 적절한 해결 방법을 찾는 것이 중요합니다. 이번 경험을 통해, 성능 최적화와 효율성 향상을 위해 문제를 근본적으로 해결하는 것의 중요성을 다시 한번 깨닫게 되었습니다.