개발 slecs

크롤러 파싱 노이즈 제거와 공통 클렌징 모듈 정비

목차

크롤러 파싱 결과물에 JS 잔재물과 빈 spacer가 계속 섞여 나오던 걸 정규식으로 잘라냈다.

왜 이게 문제였나

크롤러로 수집한 HTML을 텍스트로 변환하다 보면 생각보다 별의별 노이즈가 붙어 나온다. 특히 공공기관이나 스타트업 지원 사이트들은 레거시 WYSIWYG 에디터로 만들어진 페이지가 많아서, 내용 안에 인라인 onclick 핸들러나 javascript:void(0) 같은 JS 잔재가 고스란히 남아 있는 경우가 흔하다. 단순히 HTML 태그를 벗겨내는 것만으로는 이런 것들이 다 제거되지 않는다. 태그 속성에 박혀 있거나, 아예 텍스트 노드처럼 흘러 들어와 있기 때문이다.

빈 spacer 문제도 마찬가지다. <td>&nbsp;</td> 하나짜리 셀이 수십 개 반복되거나, 레이아웃용 투명 GIF 이미지 자리가 줄바꿈 여러 개로 치환되어 남는 경우가 있다. 사람 눈에는 아무것도 없어 보이는 영역이지만, 파싱된 텍스트로 보면 공백과 개행이 덕지덕지 붙은 쓰레기 데이터가 되는 것이다.

이번에 수정된 파일이 bizinfo_crawler.py, crawler_common.py, kstartup_crawler.py, migrate_content_absolutize.py 이렇게 네 개인데, 공통 유틸인 crawler_common.py에 정규식 패턴을 정리하고, 각 크롤러와 마이그레이션 스크립트가 그걸 가져다 쓰는 구조로 정비한 것으로 보인다. 크롤러가 두 개 이상 물려 있는 상황에서 동일한 노이즈 제거 로직을 각자 파일에 복붙하면 나중에 패턴 하나 고칠 때 다 뒤져야 하므로, 공통 레이어로 올리는 게 맞다.

정규식 패턴, 어떻게 잡나

JS 버튼이나 onclick 잔재를 텍스트 레벨에서 제거하는 건 생각보다 까다롭다. 태그 파싱 이후 단계에서 처리한다면 대략 이런 패턴들이 대상이 된다.

import re

# onclick 속성 잔재 (태그 파서가 놓친 경우)
RE_ONCLICK = re.compile(r'onclick=["\'][^"\']*["\']', re.IGNORECASE)

# javascript: 링크 텍스트
RE_JS_LINK = re.compile(r'javascript\s*:[^\s"\'<>]+', re.IGNORECASE)

# 빈 spacer — &nbsp; 단독 반복, 공백+개행 과잉
RE_SPACER = re.compile(r'(\s*\xa0\s*){2,}')

# 버튼 태그 전체 (텍스트 없는 경우만)
RE_EMPTY_BUTTON = re.compile(r'<button[^>]*>\s*</button>', re.IGNORECASE)

물론 실제 코드는 이보다 훨씬 촘촘할 것이다. 페이지마다 에디터가 다르고 노이즈 패턴도 미묘하게 달라서, 운영 중에 계속 케이스를 추가하게 된다.

migrate_content_absolutize.py가 함께 수정된 점도 흥미롭다. 이 스크립트는 이미 수집된 콘텐츠의 상대 URL을 절대 경로로 바꾸는 역할을 할 텐데, 같은 파이프라인 안에서 JS 잔재 제거도 함께 돌려야 하는 상황이었거나, 마이그레이션 과정에서 기존 데이터에도 동일한 클렌징을 소급 적용한 것으로 보인다. 신규 수집분만 깨끗하게 만들고 기존 데이터는 그냥 두면 DB에 두 종류의 품질이 섞이게 되므로, 마이그레이션 스크립트까지 같이 건드린 판단은 맞다.

이런 류 수정이 팀에 주는 영향

항목 수정 전 수정 후
JS 잔재 포함 여부 파싱 결과에 혼재 정규식으로 제거
spacer 노이즈 과잉 공백/개행 잔존 클렌징 후 정규화
로직 위치 각 크롤러 개별 처리 (추정) crawler_common.py 공통화
기존 데이터 노이즈 있는 상태 유지 마이그레이션 스크립트로 소급 적용

크롤러 코드는 "일단 돌아가면 OK" 인식으로 방치되다가 데이터를 소비하는 쪽(검색, 요약, 분류 등)에서 이상한 결과가 나올 때 비로소 문제가 불거지는 경우가 많다. 이번처럼 파싱 레이어에서 일찍 잘라주는 게 훨씬 낫다. 나중에 ML 모델이나 텍스트 처리 로직에서 onclick= 같은 문자열을 만나면 디버깅 비용이 배로 늘어난다.

팀원들한테도 공통 유틸에 패턴 추가하는 방식을 PR로 보여줬다. 크롤러 담당 작업이다 보니 혼자 처리하는 경향이 생기기 쉬운데, 패턴이 crawler_common.py 한 곳에 모이면 리뷰도 쉽고 케이스 추가도 부담이 줄어든다. 다음 번에 새 사이트 붙일 때는 공통 클렌저를 먼저 점검하는 흐름이 자리 잡으면 된다.

끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.