문제 상황: 크롤링은 되지만 파일이 저장되지 않는 현상
많은 크롤링 프로젝트에서 흔히 발생하는 문제 중 하나는 웹페이지 탐색과 데이터 추출은 성공적으로 이루어지지만, 추출한 데이터(JSON)나 이미지 파일이 실제로 저장되지 않는 현상입니다.
특히 다음과 같은 증상이 나타날 수 있습니다:
- 코드 실행 중 오류 메시지는 없지만 파일이 생성되지 않음
- 디렉토리 경로 문제로 인한 파일 저장 실패
- 권한 문제로 인한 파일 쓰기 실패
- 상대 경로와 절대 경로의 혼용으로 인한 문제
문제 해결을 위한 핵심 접근 방법
1. 디버깅 코드 추가
파일 저장 문제를 해결하기 위한 첫 번째 단계는 상세한 디버깅 정보를 추가하는 것입니다. 다음과 같은 정보를 로깅하면 문제 진단에 도움이 됩니다:
# 디렉토리 경로 확인
print(f"DEBUG - 이미지 저장 디렉토리: {os.path.dirname(filepath)}")
print(f"DEBUG - 디렉토리 존재 여부: {os.path.exists(os.path.dirname(filepath))}")
# 파일 저장 시도 전후 상태 확인
print(f"DEBUG - 파일 쓰기 시작: {filepath}")
# 파일 쓰기 작업
print(f"DEBUG - 파일 쓰기 완료")
# 파일 생성 확인
if os.path.exists(filepath):
print(f"파일 저장 성공: {filepath} (크기: {os.path.getsize(filepath)} 바이트)")
else:
print(f"파일이 생성되지 않음: {filepath}")
2. 다중 저장 경로 전략
단일 경로에만 의존하지 않고, 여러 단계의 대체 경로를 준비하는 것이 좋습니다:
try:
# 기본 경로에 저장 시도
with open(filepath, 'wb') as file:
file.write(response.content)
print(f"파일 쓰기 완료: {filepath}")
except Exception as file_err:
print(f"파일 쓰기 오류: {file_err}")
# 대체 경로 시도
alt_filepath = os.path.join('./images', os.path.basename(filepath))
try:
os.makedirs('./images', exist_ok=True)
with open(alt_filepath, 'wb') as file:
file.write(response.content)
print(f"대체 경로에 파일 쓰기 완료: {alt_filepath}")
filepath = alt_filepath # 경로 업데이트
except Exception as alt_err:
print(f"대체 경로 파일 쓰기 오류: {alt_err}")
3. 디렉토리 생성 확인 강화
파일을 저장하기 전에 디렉토리가 확실히 존재하는지 확인하고, 권한 테스트를 수행합니다:
dir_path = os.path.dirname(filepath)
if not os.path.exists(dir_path):
print(f"디렉토리 생성 시도: {dir_path}")
os.makedirs(dir_path, exist_ok=True)
# 폴더 권한 테스트
test_file = os.path.join(dir_path, 'test_write.txt')
try:
with open(test_file, 'w') as f:
f.write('test')
os.remove(test_file)
print(f"쓰기 권한 확인 완료")
except Exception as e:
print(f"쓰기 권한 문제 발생: {e}")
실제 적용 사례: 크롤러 개선
위의 방법론을 적용하여 크롤러의 파일 저장 문제를 해결한 코드 중 핵심 부분을 살펴보겠습니다.
이미지 다운로드 함수 개선
def download_image(url, filepath, max_retries=3):
"""이미지 다운로드 함수 - 재시도 로직 추가 및 디버깅 개선"""
if not url:
print("이미지 URL이 없습니다.")
return False
# URL 유효성 검사
try:
parsed_url = urlparse(url)
if not parsed_url.scheme or not parsed_url.netloc:
print(f"잘못된 URL 형식: {url}")
return False
except Exception as e:
print(f"URL 파싱 오류: {url}, 에러: {e}")
return False
# 파일 저장 전 디렉토리 명시적 확인
try:
dir_path = os.path.dirname(filepath)
if not os.path.exists(dir_path):
print(f"디렉토리 생성 시도: {dir_path}")
os.makedirs(dir_path, exist_ok=True)
except Exception as dir_err:
print(f"디렉토리 생성 오류: {dir_err}")
# 재시도 로직
for attempt in range(max_retries):
# 다운로드 시도 코드
# ...
# 파일이 실제로 생성되었는지 확인
if os.path.exists(filepath) and os.path.getsize(filepath) > 0:
print(f"이미지 다운로드 성공: {filepath} (크기: {os.path.getsize(filepath)} 바이트)")
return True
JSON 파일 저장 함수 개선
def save_json(data, filepath):
"""JSON 파일 저장 함수 - 예외 처리 및 디버깅 개선"""
try:
# 디렉토리 확인 및 생성
dir_path = os.path.dirname(filepath)
if not os.path.exists(dir_path):
os.makedirs(dir_path, exist_ok=True)
# 파일 쓰기
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 파일 생성 확인
if os.path.exists(filepath):
print(f"JSON 파일 저장 성공: {filepath} (크기: {os.path.getsize(filepath)} 바이트)")
return True
else:
print(f"JSON 파일이 생성되지 않음: {filepath}")
return False
except Exception as e:
print(f"JSON 파일 저장 중 오류: {filepath}, 에러: {e}")
# 대체 경로 시도
alt_filepath = f"./backup_{os.path.basename(filepath)}"
try:
with open(alt_filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except:
return False
추가 개선 사항: 크롤링 안정성 향상
파일 저장 외에도 크롤링의 전반적인 안정성을 높이기 위한 몇 가지 추가 개선 사항을 적용했습니다:
1. 다양한 선택자 시도
웹사이트 구조가 변경될 수 있으므로, 여러 가능한 선택자를 순차적으로 시도합니다:
product_selectors = [
'div.c_listing > ul > li', # 기본 리스트 뷰
'div.c_prd_list > ul > li', # 대체 리스트 뷰
'div.search_product_wrap li', # 다른 가능한 선택자
# 더 넓은 선택자들...
]
for selector in product_selectors:
products = page.query_selector_all(selector)
if products:
used_selector = selector
print(f"제품 선택자 발견: {selector}, {len(products)}개")
break
2. 예외 처리 강화
각 상품 처리 과정을 개별적인 try-except 블록으로 감싸 한 상품의 처리 실패가 전체 프로세스에 영향을 미치지 않도록 합니다:
for i, product in enumerate(products):
try:
# 상품 처리 코드
# ...
except Exception as e:
print(f"상품 #{i + 1} 처리 중 에러: {e}")
continue
3. 진행 상태 모니터링
정기적으로 중간 결과를 저장하고 진행 상황을 출력합니다:
print(f"{page_num} 페이지 수집 완료, 이 페이지에서 {len(page_results)}개 수집됨, 현재까지 총 {len(all_results)}개 수집됨.")
# 중간 저장
if page_results:
if save_json(all_results, json_path):
print(f"중간 저장 완료: {json_path}")
else:
print(f"중간 저장 실패. 대체 경로에 저장 시도...")
결론: 견고한 크롤러 설계 원칙
웹 크롤링 프로젝트에서 파일 저장 문제를 해결하고 안정성을 높이기 위한 핵심 원칙을 정리하면 다음과 같습니다:
- 상세한 디버깅 정보 – 각 단계마다 충분한 로그를 남깁니다
- 다중 저장 전략 – 여러 경로에 저장을 시도합니다
- 명시적 경로 확인 – 모든 파일 작업 전에 경로와 권한을 확인합니다
- 다양한 선택자 대응 – 웹사이트 구조 변경에 대비합니다
- 강력한 예외 처리 – 부분적 실패가 전체 프로세스를 중단시키지 않도록 합니다
- 정기적 중간 저장 – 진행 중인 작업 결과를 안전하게 보존합니다
이러한 원칙을 적용하면 더 견고하고 신뢰할 수 있는 웹 크롤러를 개발할 수 있습니다. 특히 대규모 데이터 수집 프로젝트에서는 이러한 안정성 확보가 프로젝트 성공의 핵심 요소가 됩니다.
답글 남기기