동적 크롤링 실습
Selenium + 네이버 블로그 크롤링
💡 오늘 한 줄 요약
정적 크롤링으로 안 되는 곳은 Selenium으로 브라우저를 직접 조종해서 데이터를 뽑는다. 그리고 네이버 블로그는 iframe 진입이 핵심!
1. 정적 크롤링 vs 동적 크롤링
크롤링 방식은 크게 두 가지다. 정적 크롤링은 HTML 파일만 다운로드하면 바로 데이터를 얻을 수 있는 경우, 동적 크롤링은 브라우저를 실제로 실행해야 데이터가 보이는 경우에 사용한다.
정적 크롤링과 동적 크롤링 비교
동적 크롤링이 필요한 대표적인 상황
- 🔐 로그인을 해야 데이터가 보이는 경우 (광고 플랫폼, CRM)
- 📜 스크롤을 내려야 데이터가 불러와지는 경우 (무한스크롤)
- 🖱️ 버튼 클릭을 해야 다음 페이지가 나오는 경우
- ⚙️ JavaScript가 실행되어야 데이터가 렌더링되는 경우
💡 크롤링을 할 줄 알면, 수작업으로 며칠 걸리던 데이터 수집을 몇 분 안에 끝낼 수 있다.
2. 그로스 마케터에게 크롤링이 중요한 이유
| 업무 상황 | 크롤링 활용 방법 |
|---|---|
| 경쟁사 가격 모니터링 | 경쟁사 쇼핑몰에서 가격 자동 수집 |
| 키워드 리서치 | 검색 결과 상위 노출 콘텐츠 자동 수집 및 분석 |
| 리뷰 분석 | 앱스토어, 쇼핑몰 리뷰 대량 수집 후 감성 분석 |
| 광고 소재 리서치 | 경쟁사 광고 문구, 랜딩 페이지 자동 수집 |
| 트렌드 파악 | SNS 해시태그, 커뮤니티 인기 게시글 수집 |
3. Selenium이 하는 일
Selenium은 브라우저(크롬 등)를 코드로 조종하는 도구다. 사람이 손으로 하는 모든 브라우저 조작을 자동화할 수 있다.
Selenium 5단계 기본 흐름
| 할 수 있는 일 | 예시 |
|---|---|
| 브라우저 열기 / 닫기 | webdriver.Chrome(...) / driver.quit() |
| 특정 URL로 이동 | driver.get("https://...") |
| 요소 찾기 | find_element(By.CSS_SELECTOR, ...) |
| 클릭하기 | element.click() |
| 텍스트 입력 | element.send_keys("검색어") |
| 데이터 추출 | element.text |
4. 선택자(Selector): CSS Selector를 쓰는 이유
Selenium이 데이터를 수집하려면 HTML에서 원하는 요소의 위치를 알아야 한다. 이때 사용하는 것이 선택자(Selector)다.
CSS Selector 핵심 문법 — 이것만 알면 80%는 해결 가능
| 이유 | 설명 |
|---|---|
| 직관적이다 | HTML 구조와 거의 동일하게 생겨서 읽기 쉽다 |
| 짧고 간결하다 | XPath보다 훨씬 짧게 쓸 수 있다 |
| 범용적이다 | Selenium, BeautifulSoup, JavaScript 모두 지원 |
| 크롬에서 바로 복사 | 개발자도구 → 요소 우클릭 → "Copy selector" 기능 |
📌 선택자 찾는 법 (크롬): F12 → 수집할 요소 위에서 우클릭 → "검사(Inspect)" → 파란색 하이라이트된 HTML에서 class, id 확인
5. 코랩 실습 환경 준비
구글 코랩에서 Selenium을 사용하려면 아래 설치 과정이 필요하다.
🖥️ Shell (Colab 셀 실행)
Bash
!pip install -q selenium
!apt-get update -qq
!apt-get install -y libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libgbm1 libasound2 libnss3 libxss1 libgtk-3-0
!wget -q https://storage.googleapis.com/chrome-for-testing-public/148.0.7766.3/linux64/chrome-linux64.zip
!wget -q https://storage.googleapis.com/chrome-for-testing-public/148.0.7766.3/linux64/chromedriver-linux64.zip
!unzip -qo chrome-linux64.zip
!unzip -qo chromedriver-linux64.zip
!chmod +x /content/chrome-linux64/chrome
!chmod +x /content/chromedriver-linux64/chromedriver
🐍 selenium_setup.py
Python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
options = Options()
options.binary_location = "/content/chrome-linux64/chrome"
options.add_argument("--headless=new") # 창 없이 실행
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
service = Service("/content/chromedriver-linux64/chromedriver")
driver = webdriver.Chrome(service=service, options=options)
6. 실습 코드 — quotes.toscrape.com
실습 사이트: https://quotes.toscrape.com/ — 명언과 저자가 정리된 크롤링 연습용 사이트
🖥️ 실습 1 & 2. 요소 하나 / 여러 개 가져오기
목표: find_element(단수) vs find_elements(복수) 차이 이해
| 메서드 | 반환값 | 없을 때 | 언제 쓰나 |
|---|---|---|---|
find_element | 요소 1개 | ❌ 에러 발생 | 특정 요소 하나를 정확히 찾을 때 |
find_elements | 요소 리스트 | ✅ 빈 리스트 반환 | 여러 개를 한 번에 수집할 때 |
🐍 crawling2.py
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://quotes.toscrape.com/")
# 1페이지 명언 수집
# div.quote 안의 span.text만 타겟팅해서 명언 텍스트 리스트로 가져옴
quote = driver.find_elements(By.CSS_SELECTOR, "div.quote span.text")
for q in quote:
print(q.text)
print("--------------")
# 다음 버튼 찾기
# li.next a = 하단 Next 버튼 링크
next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
# 다음 버튼 누르기 → 2페이지로 이동
next_button.click()
print("<2페이지>")
# 2페이지 명언 수집
# 페이지가 바뀐 후 동일한 셀렉터로 다시 요소를 가져옴
quote = driver.find_elements(By.CSS_SELECTOR, "div.quote span.text")
for q2 in quote:
print(q2.text)
print("--------------")
💡 1페이지 수집 후 Next 버튼을 찾아 .click() → 2페이지로 이동해서 다시 수집
📋 실습 3 & 4. 명언 + 저자 함께 가져오기 (블록 단위 수집)
목표: 부모 블록(div.quote)을 먼저 수집 → 각 블록 안에서 자식 요소 추출 → DataFrame 저장
💡 핵심 패턴: 부모 블록 전체를 리스트로 받은 뒤, 각 블록 안에서 다시
find_element로 자식을 찾는다. 이렇게 해야 명언과 저자가 쌍으로 매칭된다.
🐍 crawling1.py
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://quotes.toscrape.com/")
# div.quote CSS 셀렉터에 해당하는 모든 요소를 리스트로 가져옴
# 각 quote 블록(명언 하나 = div.quote 하나)이 blocks 리스트에 담김
blocks = driver.find_elements(By.CSS_SELECTOR, "div.quote")
# 딕셔너리들을 담을 빈 리스트 초기화
quotes_box = []
# blocks 리스트에서 요소(div.quote)를 하나씩 꺼내 반복
for block in blocks:
# 현재 block 안에서 span.text 요소를 찾아 텍스트(명언) 추출
text = block.find_element(By.CSS_SELECTOR, "span.text").text
# 현재 block 안에서 small.author 요소를 찾아 텍스트(저자명) 추출
author = block.find_element(By.CSS_SELECTOR, "small.author").text
# 추출한 저자, 명언을 딕셔너리로 묶음
quotes_dict = {
"저자": author,
"명언": text
}
# 딕셔너리를 리스트에 추가 (반복마다 한 명언씩 쌓임)
quotes_box.append(quotes_dict)
# 최종적으로 quotes_box = [{"저자": ..., "명언": ...}, {"저자": ..., "명언": ...}, ...]
# pd.DataFrame(quotes_box) 하면 바로 표 형태로 변환 가능
💡 quotes_box 리스트에 딕셔너리를 쌓은 뒤 pd.DataFrame(quotes_box)으로 바로 표 변환 가능
🖱️ 실습 5. Next 버튼 클릭 — 태그 수집 (수동 3페이지)
목표: .click()으로 페이지 이동, 태그를 여러 페이지에서 모으기
🐍 crawling3.py
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://quotes.toscrape.com/")
tag_list = []
#1페이지 태그값 모으기
tags = driver.find_elements(By.CSS_SELECTOR, "div.tags a.tag")
for tag in tags:
print(tag.text)
tag_list.append(tag.text)
#다음으로 넘어가기
next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
next_button.click()
print("<2페이지>")
#2페이지 태그값 모으기
tags = driver.find_elements(By.CSS_SELECTOR, "div.tags a.tag")
for tag in tags:
print(tag.text)
tag_list.append(tag.text)
#다음으로 넘어가기
next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
next_button.click()
print("<3페이지>")
#3페이지 태그값 모으기
tags = driver.find_elements(By.CSS_SELECTOR, "div.tags a.tag")
for tag in tags:
print(tag.text)
tag_list.append(tag.text)
print(tag_list)
#중복 값 제거
print(len(tag_list)) # 중복 제거 전 개수
print(len(set(tag_list))) # 중복 제거 후 개수
💡 중복 제거: set(tag_list)으로 고유값만 남길 수 있다
🔄 실습 6 (심화). for 반복문으로 N페이지 자동 수집
목표: 수동 복붙 대신 for문 + break로 마지막 페이지 처리까지 자동화
🐍 crawling4.py
Python
import time
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://quotes.toscrape.com/")
# 태그값들을 담아둘 빈 바구니(리스트)
all_tages = []
for page in range(1,4): #1,2,3 → 총 3번 반복
print(page, "-----------------")
# 1) 현재 페이지에서 태그값 찾기
# "div.tags 안에 있는 a.tag" 요소들을 전부 가져와서 tags에 저장
tags = driver.find_elements(By.CSS_SELECTOR, "div.tags a.tag")
for tag in tags: # tags 리스트에서 하나씩 꺼내기
print(tag.text) # 태그 텍스트 출력
# 태그값을 바구니에 하나씩 담기
tag_list.append(tag.text)
if page == 3: # page가 3이 되면 (마지막 페이지)
break # 더 이상 next 버튼 누르지 않고 for문 종료
# 2) next 버튼 찾고 누르기 → 다음 페이지로 이동
next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
next_button.click()
print("------------------다음 페이지------------------")
# 페이지가 완전히 로딩될 때까지 2초 기다리기
# (너무 빨리 실행하면 태그를 못 찾을 수 있음)
time.sleep(2)
💡 if page == 3: break — 마지막 페이지에서 Next 버튼이 없는데 클릭하면 에러나므로 break로 미리 탈출
7. 실전 실습 — 네이버 블로그 크롤링
네이버 블로그 크롤링 전체 파이프라인
STEP 1. 네이버 검색 API로 블로그 링크 수집
🐍 crawling5.py
Python
import requests
import pandas as pd
from google.colab import userdata
client_id = userdata.get("NAVER_CLIENT_ID")
client_secret = userdata.get("NAVER_CLIENT_SECRET")
url = "https://openapi.naver.com/v1/search/blog.json"
headers = {
"X-Naver-Client-Id": client_id,
"X-Naver-Client-Secret": client_secret
}
params = {
"query": "방화수류정",
"display": 10
}
response = requests.get(url, headers=headers, params=params)
data = response.json()
links = []
for item in data["items"]:
links.append(item["link"])
df_links = pd.DataFrame(links, columns=["url"])
df_links
💡 네이버 개발자센터에서 Client ID / Secret 발급 필요. 코랩은 userdata.get()으로 안전하게 불러옴
STEP 2. Selenium으로 블로그 본문 크롤링
⚠️ 네이버 블로그 iframe 주의!
네이버 블로그 본문은
네이버 블로그 본문은
<iframe name="mainFrame"> 안에 있다. 반드시 driver.switch_to.frame("mainFrame")으로 진입한 뒤에 요소를 찾아야 하고, 수집 후엔 driver.switch_to.default_content()로 복귀해야 다음 URL을 처리할 수 있다.
🐍 crawling6.py
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
driver = webdriver.Chrome(service=service, options=options)
title_list = []
content_list = []
for url in df_links["url"]:
driver.get(url)
driver.switch_to.frame("mainFrame")
title = driver.find_element(By.CSS_SELECTOR, "div.se-title-text span").text
content = driver.find_element(By.CSS_SELECTOR, "div.se-main-container").text
# print(title, content)
title_list.append(title)
content_list.append(content)
driver.switch_to.default_content()
df_links["title"] = title_list
df_links["content"] = content_list
df_links["content"] = df_links["content"].str.replace("\n", " ")
df_links
💡 switch_to.frame() → 수집 → switch_to.default_content() 세트를 for문 안에서 반복
최종 저장
🐍 save.py
Python
df_links["title"] = title_list
df_links["content"] = content_list
df_links["content"] = df_links["content"].str.replace("\n", " ")
df_links.to_csv("result.csv", index=False, encoding="utf-8-sig")
# utf-8-sig: 한글 깨짐 없이 엑셀에서도 바로 열 수 있음
📋 오늘 배운 것 총정리
| 개념 | 핵심 내용 |
|---|---|
| 동적 크롤링 필요 상황 | 로그인 필요, 무한스크롤, JS 렌더링 |
| Selenium 기본 흐름 | 브라우저 열기 → URL 이동 → 요소 찾기 → 수집 → 종료 |
| CSS Selector | .클래스, #id, 부모 자식 — 개발자도구에서 Copy selector로 바로 복사 |
| find_element vs find_elements | 단수(없으면 에러) vs 복수(없으면 빈 리스트) |
| 페이지 이동 | .click() + time.sleep() 필수 세트 |
| 네이버 블로그 특이사항 | iframe → switch_to.frame("mainFrame") 먼저! |
| 데이터 저장 | df.to_csv("파일명.csv", encoding="utf-8-sig") |
'부트캠프' 카테고리의 다른 글
| 멋쟁이사자처럼 부트캠프 그로스마케팅 4기 30일차_260421 (0) | 2026.04.21 |
|---|---|
| 멋쟁이사자처럼 부트캠프 그로스마케팅 4기 29일차_260420 (0) | 2026.04.20 |
| 멋쟁이사자처럼 부트캠프 그로스마케팅 4기 27일차_260416 (0) | 2026.04.16 |
| 멋쟁이사자처럼 부트캠프 그로스마케팅 4기 26일차_260415 (1) | 2026.04.15 |
| 멋쟁이사자처럼 부트캠프 그로스마케팅 4기 25일차_260414 (2) | 2026.04.14 |