네이버 finance 환율 웹 화면에서 데이터를 가져오는 법을 알아보겠습니다.
(네이버님들 혹시 트래픽이 너무 많이 잡혀 문제가 되면 글을 숨김처리하겠습니다. 근데 보러 오는 사람이 별로 없어서 그럴 일은 없을 것 같습니다.... ㅠ)
데이터 분석이나 자동화 프로젝트를 진행하다 보면, 필요한 데이터를 항상 깔끔한 형태의 Open API로 얻을 수 있는 것은 아닙니다. 때로는 우리가 직접 웹사이트에 접속해서 화면에 보이는 정보를 긁어와야(Scraping) 하는 경우가 발생하죠.
오늘은 Open API가 제공되지 않는 환경에서 BeautifulSoup(BS4)를 활용하여 웹 데이터를 추출(Extract)하고 변환(Transform)하는 ETL 파이프라인 구축 방법을 알아보겠습니다.
1. 웹 스크래핑(Scraping) 워크플로우
웹 브라우저가 화면을 보여주는 원리를 이해하면 데이터를 추출하는 과정도 쉽게 이해할 수 있습니다.
스크래핑은 크게 두 파트로 나뉩니다.
Part 1. 사이트 접속 및 응답 획득
- HTTP 요청: 우리가 브라우저 주소창에 URL을 입력하고 엔터를 치듯, 파이썬 코드로 타겟 사이트에 GET 방식으로 접속을 요청합니다.
- 서버 응답: 타겟 서버는 화면을 구성하는 코드들을 텍스트 형태로 묶어서 응답합니다.
- HTML: 웹 페이지의 뼈대와 구조, 핵심 콘텐츠를 담고 있습니다. (우리의 타깃!)
- CSS: 레이아웃과 디자인 요소입니다.
- JavaScript (JS): 사용자와의 인터렉션이나 비동기 통신을 담당합니다.
Part 2. 파싱(Parsing)과 데이터 추출
- 파싱(Parsing): 텍스트로 이루어진 HTML 코드를 프로그램이 이해하고 탐색할 수 있도록 메모리 상에 DOM(Document Object Model) Tree 형태로 재구성하는 작업입니다.
- 이를 위해 html5lib, html.parser, lxml 등의 파서(Parser) 도구가 필요합니다.
- 데이터 특정 및 추출: 트리가 구성되면 특정 요소를 콕 집어낼 수 있는 탐색 도구가 필요합니다. 주로 CSS Selector나 XPath가 사용됩니다.
- 이 모든 파싱과 탐색 과정을 파이썬에서 가장 쉽고 직관적으로 할 수 있게 도와주는 포괄적인 라이브러리가 바로 BeautifulSoup(BS4)입니다.
💡 Tip - 파서(Parser) 선택하기: 파이썬 내장 파서인 html.parser도 좋지만, 실무에서는 html5lib나 lxml을 자주 사용합니다. 특히 html5lib는 웹 브라우저와 동일한 방식으로 HTML을 해석하기 때문에, 태그가 깨져있거나 구조가 엉망인 웹페이지도 아주 유연하게 잘 처리해 줍니다.
2. BeautifulSoup (BS4) 란?
BeautifulSoup4는 파이썬에서 HTML 및 XML 문서를 파싱 하여 데이터를 추출할 수 있게 해주는 강력하고 편리한 라이브러리입니다. 복잡한 웹 문서 내에서 우리가 원하는 데이터만 정확하고 빠르게 뽑아내는 데 최적화되어 있습니다.
- 공식 문서: Beautiful Soup Documentation
3. [실전 실습] 네이버 금융 환율 정보 ETL 파이프라인
이제 실전입니다! 하나은행에서 제공하는 네이버 금융의 '국가별 환율 정보'를 추출하여 우리가 원하는 데이터 구조로 변환해 보겠습니다.

🎯 요구사항
- 타깃 사이트:
- 수집 주기: 회차별로 갱신되므로 스케줄링을 통해 정기적으로 수집 (이건 다음에 설명하겠습니다.)
- 수집 데이터: 국가명, 통화코드, 매매기준율, 미화환산율, 현찰 살 때의 환율
Step 1. 데이터 추출 (Extract)
먼저 urllib.request를 이용하여 타겟 URL의 HTML 데이터를 가져옵니다.
import urllib.request as req
from bs4 import BeautifulSoup
# 환율 상세 정보 타겟 URL
TARGET_SITE_EXCHANGE = "https://finance.naver.com/marketindex/exchangeList.naver"
# 타겟 사이트에 HTTP 요청을 보내고 응답(HTML)을 받음
res = req.urlopen(TARGET_SITE_EXCHANGE)
Step 2. 파싱 및 DOM Tree 구성
받아온 응답 데이터를 BS4와 html5lib 파서를 이용해 요리(DOM Tree 구성)합니다.
# 응답받은 HTML 데이터를 html5lib 파서를 통해 DOM Tree 객체인 'soup'으로 만듭니다.
soup = BeautifulSoup(res, "html5lib")
Step 3. CSS Selector로 데이터 특정하기
데이터는 HTML의 엘리먼트(Element) 내부에 존재합니다.
엘리먼트는 <시작태그 속성="값">컨텐츠</종료태그>의 구조를 가집니다.
여기서 우리가 원하는 요소를 특정하려면 CSS Selector를 사용합니다.
- 자주 쓰이는 CSS Selector 규칙:
- 태그 검색: div, a, td (태그명 그대로 사용)
- id 속성: #아이디값 (예: #content)
- class 속성: .클래스값 (예: .tit)
- 자식/후손 관계: 부모 > 자식 (직계 자식), 조상 후손 (띄어쓰기, 하위의 모든 요소)
- 순서 특정: :nth-child(n) (형제 요소 중 n번째)
가장 먼저 국가명과 통화 코드를 가져오기 위해 .tit 클래스를 가진 요소를 찾아보겠습니다.
크롬브라우저에서 F12를 누르고 element 탭을 가면 확인 가능합니다.
혹은 네이버 금융이 켜진 브라우저에서 Ctrl + Shif + C를 누르고 확인하고 싶은 요소를 클릭하면 해당 html을 볼 수 있습니다.

# .tit 클래스를 가진 모든 요소를 리스트 형태로 반환 (총 58개국)
tit = soup.select(".tit")
# 국가명과 통화코드 추출 (예외 상황을 방지하기 위한 문자열 정제)
countries = [td.string.strip().split()[0] for td in tit]
print("국가명 리스트:", countries[:5])
# 통화코드 추출 (a 태그 안의 href 속성값에서 뒤의 통화코드만 슬라이싱)
# 예: href="/marketindex/exchangeDetail.naver?marketindexCd=FX_JPYKRW" -> 'JPY'
currencies = [td.select_one('a').get('href')[-6:-3] for td in tit]
print("통화코드 리스트:", currencies[:5])
Step 4. 데이터 변환 (Transform) - ⭐️ 최종 구조화
위의 방식처럼 .tit 태그 하나만 찾아서 기준을 잡으면, 같은 행(Row)에 있는 매매기준율이나 환산율을 가져오기 위해 계층 구조를 오르락내리락(find_next_sibling 등) 해야 해서 코드가 지저분해집니다.
이를 깔끔하게 해결하려면 데이터를 감싸고 있는 가장 큰 단위인 <tr> (테이블의 한 행)을 먼저 잡고,
그 내부에서 각각의 세부 데이터를 찾는 방식으로 구조를 설계하는 것이 좋습니다.
파이썬의 리스트 컴프리헨션(List Comprehension)을 사용하여 코드를 최적화해 보겠습니다.
# .tbl_exchange <table> 안의 <tbody> 내부에 있는 <tr> 태그 58개를 모두 가져옵니다.
# 여기서는 테스트를 위해 [:3]으로 상위 3개만 추출합니다.
exchanges = [
{
# 1. 국가명: 첫 번째 띄어쓰기 기준으로 앞부분만 가져옴
'exchange': tr.select_one('.tit').string.strip().split()[0],
# 2. 통화코드: a태그의 href 링크에서 뒤에서 6번째~3번째 글자 슬라이싱
'code': tr.select_one('.tit').select_one('a').get('href')[-6:-3],
# 3. 매매기준율: 쉼표(,) 제거 후 float(실수) 타입으로 변환
'buy_rate': float(tr.select_one('.sale').string.strip().replace(',', '')),
# 4. 현찰 살 때: 3번째 <td> 태그
'cash_buy': float(tr.select_one('td:nth-child(3)').string.strip().replace(',', '')),
# 5. 미화환산율: 7번째 <td> 태그
'per_rate': float(tr.select_one('td:nth-child(7)').string.strip().replace(',', ''))
}
for tr in soup.select(".tbl_exchange > tbody > tr")[:3]
]
# 최종 결과 확인
import pprint
pprint.pprint(exchanges)
[출력 예상 결과]
[{'buy_rate': 1381.5,
'cash_buy': 1405.67,
'code': 'USD',
'exchange': '미국',
'per_rate': 1.0},
{'buy_rate': 876.12,
'cash_buy': 891.45,
'code': 'JPY',
'exchange': '일본',
'per_rate': 0.634},
{'buy_rate': 1504.66,
'cash_buy': 1534.59,
'code': 'EUR',
'exchange': '유럽연합',
'per_rate': 1.089}]
이렇게 변환된 데이터(Dictionary List 형태)는 Pandas 라이브러리를 통해 DataFrame으로 바로 변환하거나, 데이터베이스(DB), CSV 등에 적재(Load)하기 완벽한 구조가 됩니다.
웹 스크래핑은 처음엔 HTML 구조를 분석하는 것이 낯설 수 있지만, 크롬 개발자 도구의 Copy -> Copy selector 기능을 적극 활용하고 CSS Selector의 규칙만 익히면 어떤 웹페이지의 데이터도 자유자재로 추출해 낼 수 있습니다. 이 기술을 바탕으로 여러분만의 자동화된 데이터 파이프라인을 구축해 보시길 바랍니다!
오늘의 한 마디
오늘은 명언을 보여드리겠습니다.
진정한 등반가는 산을 무서워하는 사람이다
성공이 계속되다 보면 과욕을 부리게 되고 자만하기 쉽다.
처음의 순수한 마음을 유지하기 어렵다.
그럴수록 긴장을 늦추지 않고 겸허해야 하고 자신을 낮춰야 한다.
뭔가 자신이 어떤 것에 전문가가 되었다고 욕심을 부리다가 위험에 빠질 수 있다는 경고를 하시는 것 같습니다. 항상 겸손한 마음을 가지고 살아가겠습니다.
'코딩 개발 > Python' 카테고리의 다른 글
| Python - 데이터수집처리 (적재) 3 (0) | 2026.07.28 |
|---|---|
| Python - 데이터수집처리 (feat. 네이버 finance 환율) 2 (0) | 2026.07.27 |
| Python - 데이터 수집, 처리, 적재 (ETL) (feat. NAVER Developer 어플리케이션 사용 법, Google Colab에서 API 사용) (1) | 2026.07.23 |
| Python - 모듈 (from, import) (0) | 2026.07.22 |
| Python - 함수 지향적 프로그래밍(feat. 숫자 맞추기 게임) (1) | 2026.07.21 |