[Web] Web Crawling Fundamentals
Summary
| 영역 | 핵심 한 줄 |
|---|---|
| 웹 구조 | HTML은 구조, CSS는 꾸밈, JS는 동작 |
| 크롤링 본질 | HTML에서 원하는 위치를 정확히 집어내는 기술 |
| 핵심 도구 | requests(요청) + BeautifulSoup(파싱) |
| 동적 페이지 | Selenium 필요 |
| 선택자 | CSS 선택자로 위치 지정 |
| 텍스트 추출 | find / find_all + 정규표현식 |
| 페이징 | URL 파라미터 증가 |
| 실전 전략 | 포레스트 이론: 큰 틀 → 세부 추출 |
1. 웹 크롤링
웹크롤링은 사람 대신 웹페이지를 읽는 로봇을 만드는 일
사람은 화면을 보고 복사하지만,
크롤러는 HTML을 읽고 코드를 통해 위치를 찾고 데이터를 자동으로 저장한다.
✔️결국 크롤링의 핵심은
웹페이지의 구조를 이해하고, 필요한 정보의 위치를 정확히 찾아내는것.
2. 웹 페이지의 구조
2-1. 웹의 3요소
| 요소 | 역할 | 비유 |
|---|---|---|
| HTML | 구조 | 집의 뼈대 |
| CSS | 디자인 | 벽지, 색깔 |
| JavaScript | 동작 | 자동문, 버튼 |
크롤러는 이 중 HTML만 읽는다. (겉모습은 필요 없고, 뼈대만 보면 되니까!)
3. 크롤링의 핵심 기술: “선택자”
3-1. 선택자가 중요한 이유
웹페이지는 수많은 데이터가 섞여 있는 데이터 창고다. 그래서 크롤러에게 가장 중요한 능력은
“이 많은 데이터 중, 바로 이 부분만 가져와라” 라고 정확히 지시하는 것.
이를 가능하게 하는 것이 CSS 선택자.
크롤러는 CSS를 읽는 것이 아니라,
HTML을 읽고 CSS 선택자 문법을 ‘주소 체계’로 빌려 쓰는 것
(CSS 선택자는 CSS에서는 디자인 적용, 크롤러에서는 데이터 추출 위치 지정으로 쓰이는 것)
3-2. 선택자 종류
(1) 기본 선택자
| 종류 | 문법 | 의미 |
|---|---|---|
| 태그 | h1 | 모든 h1 |
| 클래스 | .title | class=”title” |
| 아이디 | #main | id=”main” |
(2) 관계 선택자
| 문법 | 의미 |
|---|---|
A > B | A의 자식 B |
A + B | A 바로 뒤 형제 |
A ~ B | A 뒤의 모든 형제 |
(3) 고급 선택자
| 문법 | 의미 |
|---|---|
:nth-of-type(n) | 같은 태그 중 n번째 |
:not(X) | X 제외 |
[attr] | 속성 존재 |
[attr*="x"] | 값에 x 포함 |
4. HTML을 데이터로 바꾸는 도구: BeautifulSoup
BeautifulSoup은 HTML을 사람이 다루기 쉬운 구조로 바꿔주는 번역기
4-1. 핵심 메서드
| 메서드 | 역할 | 언제 사용? |
|---|---|---|
find() | 하나 찾기 | 유일한 요소 |
find_all() | 여러 개 | 반복 요소 |
select() | CSS 선택자 | 복잡한 구조 |
select_one() | CSS + 하나 | 첫 번째만 |
5. 텍스트 기반 추출 전략
5-1. 정확히 일치하는 텍스트
1
soup.find("h4", string="news")
5-2. 포함된 텍스트 찾기 (정규표현식)
1
2
3
import re
soup.find_all("h4", string=re.compile("news"))
5-3. 실무에서 꼭 알아야 할 함정!! ⭐
❗ 문제
BeautifulSoup에서 find_all(..., string=...)는 태그 안에 텍스트가 한 덩어리로 있을 때만 안정적으로 동작한다.
1
2
3
<h4 class="product-price">
<span>10,000</span>Won
</h4>
이처럼 태그 내부에 다른 태그가 섞이면
문자열이 분리되어 string= 매칭이 실패할 수 있다.
1
soup.find_all("h4", string=re.compile("Won")) # 누락 가능
✅ 해결: “위치 먼저 → 텍스트로 검사”
1
2
3
4
5
6
result = []
tags = soup.select(".product-price") # 먼저 위치(요소) 선택
for tag in tags:
if "Won" in tag.get_text(strip=True): # 태그 내부 텍스트를 합쳐서 확인
result.append(tag)
이 방식은
select()로 위치를 먼저 정하고get_text()로 실제 내용을 검사하는 구조
즉, “주소 기반 접근 + 텍스트 필터링” 조합이
실문에서 가장 안정적인 패턴
6. 정적 페이지 vs 동적 페이지
6-1. 구조적 차이
| 구분 | 특징 | 해결책 |
|---|---|---|
| 정적 페이지 | HTML에 데이터 있음 | requests + BS |
| 동적 페이지 | JS 실행 후 생성 | Selenium |
6-2. 도구 역할 분담
| 도구 | 역할 |
|---|---|
| requests | 웹 요청 |
| BeautifulSoup | HTML 파싱 |
| Selenium | 브라우저 자동화 |
| pandas | 데이터 저장/정리 |
7. URL과 페이징의 원리
7-1. URL 구조
Protocol / Domain / Path ? Parameter
7-2. 페이징 알고리즘 사고방식
- 페이지 넘길 때 URL 변화 관찰
- 변하는 파라미터 찾기
- 값 증가시키며 반복 요청
8. 실전 크롤링 전략: Forest 이론
데이터를 찾을 때 곧바로 세부 요소부터 접근하면 전체 구조를 놓치기 쉽다.
그래서 크롤링에서는 Forest 전략이 효과적.
- 숲 찾기: 전체 상품 영역
- 나무 찾기: 상품 하나
- 잎 찾기: 가격, 제목, 링크
이 순서를 지키면 확장 가능하고 유지보수하기 쉬운 크롤러 구조를 만들 수 있다.
9. 크롤러 제작 흐름
웹페이지 → HTML 구조 이해 → CSS 선택자로 위치 지정 → BeautifulSoup으로 파싱 → 텍스트/속성 추출 → 페이징 처리 → 정적이면 requests / 동적이면 Selenium → pandas로 저장