본문으로 바로가기
TaeyoungKim.dev

BeautifulSoup select_one이 None일 때: 크롤링 선택자를 안전하게 점검하는 법

파이썬작성 약 2분 읽기TaeyoungKim
LinkedInX

soup.select_one(...).text에서 AttributeError가 나면 .text가 문제라기보다 선택자가 요소를 찾지 못했을 가능성이 크다. select_one은 첫 요소를 찾지 못하면 None을 반환한다. 작은 HTML로 이 경계를 먼저 확인하자.

python
from bs4 import BeautifulSoup

def read_title(html: str) -> str:
    soup = BeautifulSoup(html, "html.parser")
    title = soup.select_one("h1.article-title")
    if title is None:
        raise ValueError("제목 요소를 찾지 못했습니다")
    return title.get_text(strip=True)

assert read_title('<article><h1 class="article-title">새 글</h1></article>') == "새 글"

h1.article-title은 h1 태그이면서 article-title 클래스를 가진 요소를 뜻한다. .text나 get_text()는 선택된 요소에서만 호출해야 한다. 다음처럼 클래스가 바뀐 입력은 실패해야 한다.

python
try:
    read_title('<article><h1 class="headline">새 글</h1></article>')
except ValueError as error:
    assert "제목 요소" in str(error)
else:
    raise AssertionError("필수 제목 누락을 감지하지 못했습니다")

soup = BeautifulSoup('<article><h1 class="article-title">새 글</h1></article>', "html.parser")
assert soup.select_one("h2.subtitle") is None  # 선택 항목은 없어도 정상

HTML을 먼저 확인한다

브라우저에서 보이는 화면과 HTTP 요청으로 받은 HTML은 다를 수 있다. JavaScript가 나중에 렌더링한 콘텐츠라면 선택자가 맞아도 응답 본문에는 제목이 없다. 우선 상태 코드와 실제 받은 HTML에 article-title이 있는지 소량만 확인한다. 값이 있는데도 못 찾는다면 선택자의 태그·클래스가 실제 구조와 같은지 살핀다. 원본 응답 전체를 로그에 남기면 개인정보나 세션 정보가 섞일 수 있다.

누락은 오류인지 정상인지 정한다

목록의 일부 항목에 부제목이 없는 것이 정상이라면 그 필드는 None으로 남기고 누락 수를 기록할 수 있다. 반면 필수 제목이 없다면 위처럼 명시적으로 실패시켜야 구조 변경을 알아차린다. 모든 필드를 빈 문자열로 바꾸면 정상적인 빈 값과 수집 실패를 구분할 수 없다.

실제 사이트를 대상으로 실행하기 전에는 수집 허용 범위와 요청 빈도를 확인한다. 이 글의 예제는 네트워크 요청을 하지 않는 문자열 HTML 테스트이므로 선택자 동작만 분리해서 확인할 수 있다. 데이터의 출처·수집 시각이 중요한 경우에는 추출 결과와 함께 보존해야 나중에 구조 변경을 추적하기 쉽다.

핵심 요약

select_one은 결과가 없으면 None을 반환한다. .text를 바로 호출하기 전에 필수·선택 필드를 구분하고, 실제로 받은 HTML과 선택자를 함께 확인하자. 화면 구조가 바뀔 수 있다는 전제로 누락을 관찰하면 크롤러가 조용히 잘못된 데이터를 모으는 일을 막을 수 있다.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#Python#BeautifulSoup#Web Crawling#CSS Selector

함께 읽으면 좋은 글