티스토리 뷰
목차
BeautifulSoup은 웹페이지의 HTML 구조를 읽고 원하는 태그와 텍스트를 찾아내는 파이썬 웹 데이터 수집의 대표적인 입문 도구입니다
requests로 HTML을 가져오고 BeautifulSoup으로 파싱한 뒤 find·select로 원하는 요소를 추출하는 흐름을 이해하면 뉴스 제목·상품명·링크 같은 공개 웹 데이터를 구조적으로 다룰 수 있습니다
웹 크롤링을 처음 배우면 라이브러리 사용법보다 HTML이 어떻게 구성되는지를 이해하는 것이 먼저입니다. BeautifulSoup은 브라우저를 직접 조작하는 프로그램이라기보다 이미 가져온 HTML 문서를 분석하고 탐색하기 쉽게 바꿔주는 파서 도구에 가깝습니다. 따라서 HTTP 요청, HTML 구조, CSS 선택자, 반복문까지 하나의 흐름으로 익히는 것이 중요합니다.
🐍 Python 기초 🍲 BeautifulSoup 🔎 HTML 파싱BeautifulSoup의 역할과 크롤링 구조
웹 크롤링은 웹페이지에서 필요한 정보를 프로그램으로 읽어 구조화하는 작업을 의미합니다. 초보 단계에서는 먼저 웹 서버에 페이지를 요청하고 응답으로 받은 HTML에서 원하는 요소를 찾는 흐름을 이해하면 됩니다. 파이썬에서는 requests와 BeautifulSoup을 조합하는 방식이 정적인 HTML 페이지를 연습하기에 비교적 이해하기 쉽습니다.
여기서 requests와 BeautifulSoup의 역할은 다릅니다. requests는 특정 주소로 HTTP 요청을 보내 HTML 등의 응답을 가져오는 역할을 합니다. BeautifulSoup은 그렇게 확보한 HTML 문자열을 태그와 속성의 구조로 분석해 원하는 데이터를 쉽게 찾을 수 있도록 도와줍니다.
예를 들어 웹페이지에 여러 개의 기사 제목이 h2 태그 안에 들어 있다고 가정할 수 있습니다. BeautifulSoup을 사용하면 모든 h2를 찾거나 특정 class를 가진 h2만 골라낼 수 있습니다. 링크가 a 태그의 href 속성에 있다면 제목 텍스트와 주소를 각각 분리해 저장하는 것도 가능합니다.
다만 브라우저 화면에 보이는 모든 정보가 처음 내려받은 HTML에 포함되는 것은 아닙니다. 페이지를 연 뒤 자바스크립트가 추가 데이터를 불러와 화면을 만드는 사이트도 많습니다. 이런 페이지에서는 requests와 BeautifulSoup만으로 원하는 데이터가 보이지 않을 수 있으며 데이터 제공 방식이나 공식 API 여부를 먼저 확인하는 것이 좋습니다.
크롤링 가능 여부도 기술적으로 접근할 수 있다는 사실만으로 판단하면 안 됩니다. 사이트의 이용약관과 robots.txt, 저작권, 개인정보, 요청 빈도, 접근 제한을 함께 확인해야 합니다. 공개된 정보를 학습 목적으로 소량 수집하는 경우에도 서버에 불필요한 부하를 주지 않는 방식으로 연습하는 것이 기본입니다.
| 단계 | 주요 역할 |
|---|---|
| 웹페이지 확인 | 수집할 데이터와 HTML 구조 파악 |
| HTTP 요청 | requests로 페이지 응답 가져오기 |
| HTML 파싱 | BeautifulSoup 객체로 변환 |
| 요소 탐색 | 태그·class·CSS 선택자로 필요한 영역 검색 |
| 데이터 정리 | 텍스트·링크 등을 리스트나 파일 형태로 정리 |
💡 핵심: BeautifulSoup 자체가 인터넷에서 페이지를 가져오는 도구는 아닙니다. 입문 단계에서는 requests가 HTML을 가져오고 BeautifulSoup이 HTML을 분석한다고 역할을 분리해 이해하면 코드 구조가 훨씬 명확해집니다.
설치와 첫 HTML 파싱 방법
파이썬 환경이 준비돼 있다면 BeautifulSoup을 사용하기 위해 beautifulsoup4 패키지를 설치합니다. 웹 요청을 함께 연습하려면 requests도 설치하면 됩니다. 가상환경을 사용하는 프로젝트라면 해당 환경을 활성화한 상태에서 설치해야 다른 파이썬 환경과 패키지가 섞이는 문제를 줄일 수 있습니다.
설치 후에는 requests와 bs4 패키지의 BeautifulSoup 클래스를 불러옵니다. 아래 예시는 학습용 주소를 요청한 뒤 상태 코드를 확인하고 HTML을 파싱하는 가장 기본적인 형태입니다. 실제 크롤링에서는 요청이 실패했을 때를 고려해 timeout과 예외 처리를 함께 사용하는 습관이 좋습니다.
response에는 서버에서 받은 응답 정보가 들어 있습니다. raise_for_status()를 사용하면 4xx나 5xx 계열의 HTTP 오류 응답을 정상 데이터처럼 처리하는 실수를 줄일 수 있습니다. timeout도 지정해 두면 서버 응답이 없을 때 프로그램이 지나치게 오래 기다리는 상황을 방지하는 데 도움이 됩니다.
BeautifulSoup의 두 번째 인자인 html.parser는 HTML을 해석할 파서를 지정합니다. 파이썬에 기본 포함된 html.parser를 사용할 수 있고 필요에 따라 lxml 같은 별도 파서를 선택하기도 합니다. 입문 단계에서는 html.parser로 구조를 익힌 뒤 성능이나 파싱 특성이 필요한 시점에 다른 파서를 비교해도 충분합니다.
응답의 문자 인코딩이 잘못 해석되면 한글이 깨질 수 있습니다. 사이트가 제공하는 헤더와 HTML의 문자셋 정보가 정확하지 않은 경우도 있으므로 실제 응답의 인코딩을 점검해야 합니다. 무조건 특정 인코딩으로 강제하기보다 대상 사이트가 어떤 문자 인코딩을 제공하는지 먼저 확인하는 편이 좋습니다.
| 코드 | 역할 | 확인 포인트 |
|---|---|---|
| requests.get() | HTTP GET 요청 | timeout과 응답 상태 |
| raise_for_status() | HTTP 오류 확인 | 예외 처리와 함께 활용 |
| response.text | 텍스트 형태 응답 | 문자 인코딩 확인 |
| BeautifulSoup() | HTML 파싱 | 사용할 파서 지정 |
💡 입문 팁: 처음부터 복잡한 쇼핑몰이나 로그인 사이트를 대상으로 연습하지 않는 것이 좋습니다. HTML에 데이터가 직접 포함된 단순한 공개 페이지에서 태그 찾기와 반복문을 충분히 익힌 뒤 동적 페이지로 넘어가면 오류 원인을 구분하기 쉬워집니다.
find와 select로 원하는 요소 찾기
BeautifulSoup을 사용하는 목적은 전체 HTML을 출력하는 것이 아니라 필요한 요소를 정확하게 선택하는 데 있습니다. 가장 기본적인 방법으로 find()와 find_all()을 사용할 수 있습니다. find()는 조건에 맞는 첫 번째 요소를 찾고 find_all()은 조건에 맞는 여러 요소를 목록 형태로 가져올 때 사용합니다.
특정 class를 가진 요소도 찾을 수 있습니다. 파이썬에서 class는 예약어이므로 BeautifulSoup의 find 계열에서 HTML class 속성을 지정할 때는 class_ 형태를 사용합니다. 페이지에서 같은 태그가 반복될 때는 태그 이름만 찾기보다 class나 id 같은 속성을 함께 확인하는 것이 정확합니다.
CSS 선택자에 익숙하다면 select()와 select_one()도 편리합니다. select_one()은 첫 번째 일치 요소를 찾고 select()는 일치하는 모든 요소를 반환합니다. class는 점 기호, id는 샵 기호를 사용하며 부모와 자식 관계를 포함한 CSS 선택자도 활용할 수 있습니다.
실전에서는 find 방식과 select 방식 중 하나만 고집할 필요가 없습니다. 단순한 태그와 속성 검색은 find 계열이 읽기 쉬울 수 있고 복잡한 계층 구조를 지정할 때는 CSS 선택자가 편할 수 있습니다. 중요한 것은 개발자 도구에서 실제 HTML 구조를 확인한 뒤 가능한 한 안정적인 선택 조건을 만드는 것입니다.
화면 디자인을 위해 자동 생성되는 길고 복잡한 class 이름은 사이트 개편 때 쉽게 달라질 수 있습니다. 가능하다면 의미가 명확하고 비교적 안정적인 id나 class, 데이터 속성, 구조를 선택하는 것이 유지보수에 유리합니다. 선택자가 지나치게 구체적이어도 HTML 구조가 조금만 바뀌면 코드가 작동하지 않을 수 있습니다.
| 목적 | 예시 | 결과 특징 |
|---|---|---|
| 첫 태그 | find("h1") | 첫 일치 요소 |
| 여러 태그 | find_all("a") | 여러 요소 목록 |
| CSS 구조 | select(".item h2") | 선택자와 일치하는 목록 |
💡 디버깅 팁: 선택자가 작동하지 않을 때는 코드를 계속 수정하기 전에 print(response.text[:1000])처럼 실제로 내려받은 HTML 일부를 확인하는 것이 좋습니다. 브라우저 화면과 requests가 받은 HTML이 다르다면 선택자 문제가 아니라 동적 렌더링이나 접근 방식의 문제일 수 있습니다.
텍스트와 링크 데이터 추출하기
원하는 태그를 찾았다면 다음 단계는 실제 데이터를 꺼내는 것입니다. 태그 안의 사람이 읽는 텍스트는 get_text()를 이용해 가져올 수 있습니다. get_text(strip=True)를 사용하면 앞뒤의 불필요한 공백을 정리하기 편하지만 서로 다른 하위 태그의 텍스트가 붙을 수 있으므로 실제 결과를 확인해야 합니다.
링크 주소는 a 태그의 href 속성에 저장되는 경우가 일반적입니다. 속성은 딕셔너리처럼 접근할 수도 있지만 해당 속성이 없는 요소가 섞일 가능성이 있다면 get()을 사용하는 편이 안전합니다. 링크 텍스트와 href를 함께 추출하면 제목과 주소를 한 쌍의 데이터로 만들 수 있습니다.
href가 항상 완전한 인터넷 주소로 들어 있는 것은 아닙니다. /news/123처럼 도메인이 빠진 상대경로가 사용될 수 있습니다. 이런 주소는 urllib.parse의 urljoin()을 사용해 기준 URL과 결합하면 문자열을 임의로 이어 붙이는 것보다 안전하게 절대주소를 만들 수 있습니다.
실전 데이터에서는 값이 없는 요소를 반드시 고려해야 합니다. 모든 상품 카드에 가격이 존재한다고 가정하거나 모든 a 태그에 href가 있다고 가정하면 AttributeError나 KeyError 같은 오류가 발생할 수 있습니다. 요소가 None인지 확인하고 속성은 get()으로 읽는 습관을 들이면 크롤러가 작은 HTML 변화 때문에 즉시 중단되는 일을 줄일 수 있습니다.
수집한 결과는 리스트와 딕셔너리로 먼저 정리하면 활용하기 쉽습니다. 예를 들어 제목과 링크를 각각 따로 저장하기보다 하나의 딕셔너리로 묶어 리스트에 추가할 수 있습니다. 이후 CSV나 데이터 분석 도구로 넘길 때도 열의 의미가 명확해져 유지보수가 쉬워집니다.
🚨 주의: 로그인 우회, 접근제어 회피, 과도한 자동 요청처럼 사이트가 의도한 접근 제한을 무력화하는 방식은 피해야 합니다. 공개 웹페이지라도 이용약관과 robots.txt, 개인정보·저작권, 공식 API 제공 여부와 서버 부담을 확인한 뒤 허용되는 범위에서 수집하는 것이 기본입니다.
실전 크롤링 작성 순서
실전에서는 코드를 먼저 작성하기보다 수집하려는 데이터가 HTML 어디에 있는지 확인하는 작업부터 시작합니다. 브라우저의 개발자 도구에서 제목과 가격, 링크 같은 목표 요소를 선택하고 어떤 태그와 class에 들어 있는지 살펴봅니다. 같은 구조가 여러 항목에서 반복되는지도 확인하면 반복문을 설계하기 쉬워집니다.
그다음 requests로 페이지 하나만 요청해 정상적인 HTML을 받을 수 있는지 확인합니다. 처음부터 여러 페이지를 반복 요청하면 문제가 발생했을 때 원인을 찾기 어렵습니다. 상태 코드와 최종 URL, HTML 일부를 출력해 원하는 데이터가 응답에 실제로 들어 있는지 먼저 확인하는 과정이 중요합니다.
HTML을 정상적으로 받았다면 BeautifulSoup 객체를 만들고 가장 바깥쪽의 반복 단위를 선택합니다. 예를 들어 상품 하나가 div.product 안에 들어 있다면 먼저 모든 product 요소를 찾고 각각의 요소 내부에서 상품명과 가격을 다시 찾는 방식이 안정적입니다. 전체 문서에서 제목과 가격을 따로 수집해 순서대로 결합하는 방식은 누락 항목이 있을 때 데이터가 어긋날 수 있습니다.
각 항목에서 필요한 데이터를 추출한 뒤에는 바로 저장하기보다 몇 개의 결과를 화면에 출력해 확인하는 것이 좋습니다. 제목에 메뉴 문구가 섞이지 않았는지, 가격에 불필요한 공백이 없는지, 링크가 정상적인 절대주소인지 확인합니다. 소량 검증이 끝난 뒤에 저장과 페이지 반복 기능을 추가하면 오류가 대량 데이터로 확산되는 일을 줄일 수 있습니다.
페이지를 여러 번 요청해야 한다면 요청 간격과 실패 처리를 고려해야 합니다. 빠른 속도로 반복 요청하는 것이 좋은 크롤러를 의미하지는 않습니다. 대상 서비스가 허용하는 범위와 요청 정책을 확인하고 필요한 데이터만 최소한으로 요청하는 것이 서버 부담과 오류를 줄이는 데 도움이 됩니다.
🚨 실전 주의: 처음부터 반복문으로 수백 페이지를 요청하지 않는 것이 좋습니다. 페이지 하나에서 요청 → 파싱 → 선택 → 추출 → 결과 검증을 완성한 뒤 사이트 정책에 맞는 범위에서 확장해야 잘못된 데이터를 대량으로 수집하거나 불필요한 서버 부하를 만드는 문제를 줄일 수 있습니다.
오류와 동적 페이지 대처 방법
BeautifulSoup 입문 과정에서 가장 흔한 문제는 브라우저에서는 보이는 데이터가 코드에서는 나오지 않는 상황입니다. 먼저 response.text에서 해당 문구를 직접 검색해 보는 것이 좋습니다. 데이터가 없다면 BeautifulSoup 선택자 문제가 아니라 브라우저에서 자바스크립트가 실행된 이후에 데이터가 추가되는 구조일 가능성을 확인해야 합니다.
동적 페이지라고 해서 바로 브라우저 자동화부터 적용할 필요는 없습니다. 개발자 도구의 네트워크 영역을 통해 데이터가 공개 API나 JSON 형태로 제공되는지 확인하고 해당 서비스가 공식 API를 제공하는지도 살펴보는 것이 좋습니다. 공식적인 데이터 접근 방법이 있다면 HTML 화면을 자동 조작하는 것보다 구조가 명확하고 유지보수도 쉬울 수 있습니다.
find()나 select_one()의 결과가 None인데 곧바로 get_text()를 호출하는 것도 흔한 오류 원인입니다. HTML이 변경되거나 특정 항목에만 해당 요소가 없다면 AttributeError가 발생할 수 있습니다. 데이터를 추출하기 전에 요소의 존재를 확인하고 누락된 값은 None이나 빈 문자열처럼 일관된 방식으로 처리하는 것이 좋습니다.
HTTP 요청 자체도 항상 성공하는 것은 아닙니다. 네트워크 장애와 서버 오류, 잘못된 주소, 접근 정책 등 다양한 이유로 실패할 수 있습니다. requests의 예외를 처리하고 timeout을 설정하며 실패한 요청을 기록하면 어느 단계에서 문제가 생겼는지 찾기 쉬워집니다.
웹페이지 구조는 운영자가 언제든 변경할 수 있다는 점도 고려해야 합니다. 오늘 정상 작동한 class 선택자가 사이트 개편 이후 사라질 수 있습니다. 실제 운영용 수집 프로그램이라면 데이터 개수와 필수 필드 누락 여부를 검사해 구조 변화가 발생했을 때 조용히 잘못된 데이터를 저장하지 않도록 만드는 것이 중요합니다.
| 문제 상황 | 가능한 원인 | 우선 확인 |
|---|---|---|
| 요소가 None | 선택자 불일치 | 실제 HTML 구조 확인 |
| 화면 데이터 없음 | 동적 렌더링 | response.text와 공식 API 확인 |
| 한글 깨짐 | 인코딩 해석 문제 | 응답 인코딩 정보 확인 |
| 갑자기 수집 실패 | 페이지 구조·정책 변경 | HTML과 접근 조건 재확인 |
💡 오류 해결 순서: 데이터가 나오지 않는다면 HTTP 요청 성공 여부 → response.text에 데이터가 있는지 → BeautifulSoup 파싱 결과 → 선택자 정확성 → 동적 렌더링 여부 순서로 확인하면 원인을 빠르게 좁힐 수 있습니다.
BeautifulSoup 자주 묻는 질문
파이썬 크롤링 기초 최종 정리
| 핵심 항목 | 기억할 내용 |
|---|---|
| requests | 웹 서버에 HTTP 요청을 보내 응답을 가져오는 역할 |
| BeautifulSoup | 받아온 HTML을 파싱하고 원하는 요소를 탐색 |
| find 계열 | 태그와 속성 조건으로 첫 요소 또는 여러 요소 검색 |
| select 계열 | CSS 선택자를 이용해 HTML 구조를 탐색 |
| 텍스트 추출 | get_text()를 사용하고 실제 출력 형태를 확인 |
| 속성 추출 | get("href") 등으로 링크와 속성을 안전하게 확인 |
| 동적 페이지 | response.text에 데이터가 있는지 먼저 확인하고 공식 API 검토 |
| 오류 처리 | timeout·HTTP 오류·None·HTML 구조 변경에 대비 |
| 수집 원칙 | 사이트 정책과 접근 허용 범위, 저작권·개인정보·서버 부담 확인 |
BeautifulSoup을 이용한 파이썬 크롤링은 복잡한 코드보다 웹 요청 → HTML 확인 → 파싱 → 요소 선택 → 데이터 추출 → 결과 검증의 흐름을 이해하는 것이 먼저입니다. requests는 웹페이지의 응답을 가져오고 BeautifulSoup은 그 HTML을 탐색하기 쉬운 구조로 바꿉니다. 필요한 요소는 find와 find_all 또는 select와 select_one으로 찾을 수 있으며 텍스트는 get_text(), 링크와 같은 속성은 get()으로 추출할 수 있습니다. 상대주소는 urljoin()을 활용하면 안정적으로 절대주소로 변환할 수 있습니다. 원하는 값이 나오지 않을 때는 선택자부터 무작정 바꾸기보다 response.text에 데이터가 실제로 포함돼 있는지 먼저 확인해야 합니다. 브라우저에서만 값이 나타난다면 자바스크립트 기반 동적 페이지인지 살펴보고 공식 API나 허용된 데이터 제공 방식이 있는지도 확인합니다. 또한 실전 프로그램에서는 timeout과 HTTP 오류, 누락된 요소, 페이지 구조 변경을 고려해야 안정적으로 동작합니다. 무엇보다 기술적으로 데이터를 읽을 수 있다는 사실이 자동으로 수집 허용을 의미하지는 않으므로 사이트의 이용조건과 robots.txt, 개인정보와 저작권, 서버 부담을 함께 고려해야 합니다. 이 기본기를 익힌 뒤 정적 페이지 한 개 수집 → 반복 요소 추출 → 데이터 구조화 → 저장 → 허용 범위의 다중 페이지 처리 순서로 확장하면 파이썬 웹 데이터 수집의 전체 구조를 체계적으로 익힐 수 있습니다.
'생활 관련 정보' 카테고리의 다른 글
| 티스토리 블로그 검색엔진 등록 방법 (서치콘솔, 네이버) (0) | 2026.10.02 |
|---|---|
| 깃허브(GitHub) 잔디 심기 및 기본 명령어 가이드 (0) | 2026.10.02 |
| 워드프레스 초기 설정 및 필수 플러그인 추천 (0) | 2026.10.02 |
| 인스타그램 알고리즘 이해하고 도달률 높이는 방법 (0) | 2026.10.02 |
| 네이버 애드포스트 수익 구조 및 등록 조건 달성 가이드 (0) | 2026.10.02 |