반응형
네이버 금융에서 특정 주식 종목의 지정한 연도(기본값: 2026년) 일별 주가 데이터를 수집하여 CSV 파일로 저장하는 크롤링 프로그램입니다.
📌 주요 기능 요약
1.종목명 자동 조회 (get_stock_name)
- 입력한 종목코드(예: 삼성전자 005930)를 바탕으로 네이버 금융 메인 페이지에 접속합니다.
- 웹페이지 타이틀에서 종목명을 추출한 뒤, 파일명으로 사용할 수 없는 특수문자(\, /, :, *, ?, ", <, >, |)를 자동으로 제거합니다.
2. 주가 수집 및 파싱 (get_stock_data)
- 네이버 금융의 일별 시세 페이지(sise_day.naver)에서 페이징 처리(max_pages=30)를 통해 과거 데이터를 순차적으로 가져옵니다.
- pandas.read_html을 활용해 HTML 테이블 데이터를 데이터프레임으로 변환합니다.
- 날짜 데이터를 표준 날짜 형식(datetime)으로 변환하여, 사용자가 지정한 연도(target_year)의 데이터만 필터링합니다.
- 지정한 연도보다 과거 데이터가 나타나면 크롤링을 효율적으로 조기에 중단합니다.
3.정제 및 CSV 저장
- 수집된 데이터에서 필요한 컬럼(날짜, 종가, 시가, 고가, 저가, 거래량)만 선택합니다.
- 날짜를 보기 쉬운 문자열 형태(YYYY-MM-DD)로 변환하고, 날짜 오름차순으로 정렬합니다.
- 실행 경로에 StockData 폴더를 생성하고, 정제된 데이터를 {종목명}.csv 파일로 안전하게(utf-8-sig 인코딩) 저장합니다.
.... 전체적인 처리 순서는 다음과 같습니다.
더보기
사용자
│
▼
종목코드 입력 (005930)
│
▼
네이버 금융 일별시세 페이지 접속
│
▼
HTML 다운로드
│
▼
BeautifulSoup로 테이블 추출
│
▼
Pandas DataFrame 변환
│
▼
2026년 데이터만 추출
│
▼
모든 페이지 반복
│
▼
정렬 후 DataFrame 반환
- ✅ Pandas 3.x 지원 (StringIO 사용)
- ✅ 종목코드만 입력하면 종목명 자동 검색
- ✅ 종목명으로 CSV 저장
- ✅ StockData 폴더 자동 생성
- ✅ UTF-8(BOM) 저장(엑셀 한글 깨짐 방지)
- ✅ 네트워크 예외 처리
- ✅ 진행상황 출력
- ✅ 함수 분리로 유지보수 용이
📦 필수 패키지 목록
- pandas: HTML 테이블 데이터 파싱, 데이터프레임 가공, 정렬 및 CSV 저장 기능 수행
- requests: 네이버 금융 웹페이지에 HTTP 요청을 보내고 HTML 소스코드를 받아옴
- beautifulsoup4: 받아온 HTML 문서를 파싱하여 원하는 태그(종목명 타이틀, 시세 테이블 등)를 추출
- pandas.read_html()이 HTML 테이블을 정상적으로 읽어오려면 내부적으로 lxml 또는 html5lib 같은 파서 라이브러리가 필요하므로, lxml을 함께 설치하는 것을 권장합니다.
터미널(또는 명령 프롬프트)에서 아래 명령어를 입력하여 필요한 패키지들을 한 번에 설치할 수 있습니다.
| pip install pandas requests beautifulsoup4 lxml |
▶ 파이썬 코드
import os
from io import StringIO
import pandas as pd
import requests
from bs4 import BeautifulSoup
# ==========================================
# 공통 설정
# ==========================================
HEADERS = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/138.0.0.0 Safari/537.36"
}
# ==========================================
# 종목명 가져오기
# ==========================================
def get_stock_name(item_code):
url = f"https://finance.naver.com/item/main.naver?code={item_code}"
try:
response = requests.get(
url,
headers=HEADERS,
timeout=10
)
response.raise_for_status()
except Exception as e:
print("종목명 조회 실패 :", e)
return item_code
soup = BeautifulSoup(response.text, "html.parser")
title = soup.find("title")
if title is None:
return item_code
stock_name = title.text.split(":")[0].strip()
# 파일명에 사용할 수 없는 문자 제거
invalid = '\\/:*?"<>|'
for ch in invalid:
stock_name = stock_name.replace(ch, "")
return stock_name
# ==========================================
# 주가 데이터 수집
# ==========================================
def get_stock_data(
item_code,
target_year=2026,
max_pages=30):
stock_name = get_stock_name(item_code)
print("=" * 60)
print(f"종목명 : {stock_name}")
print(f"종목코드 : {item_code}")
print("=" * 60)
df_list = []
for page in range(1, max_pages + 1):
print(f"{page} 페이지 수집중...")
url = (
"https://finance.naver.com/item/sise_day.naver"
f"?code={item_code}&page={page}"
)
try:
response = requests.get(
url,
headers=HEADERS,
timeout=10
)
response.raise_for_status()
except Exception as e:
print("페이지 오류 :", e)
break
soup = BeautifulSoup(
response.text,
"html.parser"
)
table = soup.find(
"table",
class_="type2"
)
if table is None:
break
# Pandas 3.x 대응
html = StringIO(str(table))
df = pd.read_html(html)[0]
df = df.dropna(subset=["날짜"])
if df.empty:
break
df["날짜"] = pd.to_datetime(
df["날짜"],
errors="coerce"
)
df = df.dropna(subset=["날짜"])
df_year = df[
df["날짜"].dt.year == target_year
]
if not df_year.empty:
df_list.append(df_year)
# 목표연도보다 이전 데이터가 나오면 종료
if df["날짜"].dt.year.min() < target_year:
break
if len(df_list) == 0:
print(f"{target_year}년 데이터가 없습니다.")
return pd.DataFrame()
result = pd.concat(
df_list,
ignore_index=True
)
result = result.sort_values(
by="날짜"
).reset_index(drop=True)
columns = [
"날짜",
"종가",
"시가",
"고가",
"저가",
"거래량"
]
result = result[columns]
result["날짜"] = result["날짜"].dt.strftime(
"%Y-%m-%d"
)
# ======================================
# 저장 폴더 생성
# ======================================
save_folder = "StockData"
os.makedirs(
save_folder,
exist_ok=True
)
file_path = os.path.join(
save_folder,
f"{stock_name}.csv"
)
result.to_csv(
file_path,
index=False,
encoding="utf-8-sig"
)
print()
print("CSV 저장 완료")
print(file_path)
print()
return result
# ==========================================
# 메인
# ==========================================
if __name__ == "__main__":
stock_code = "005930"
df = get_stock_data(
stock_code,
target_year=2026
)
if not df.empty:
print(df.head())
print()
print(f"총 {len(df)}건")
▶ 실행 결과
============================================================
종목명 : 삼성전자
종목코드 : 005930
============================================================
1 페이지 수집중...
2 페이지 수집중...
3 페이지 수집중...
CSV 저장 완료
StockData\삼성전자.csv
날짜 종가 시가 고가 저가 거래량
0 2026-01-02 70100 69800 70300 69700 12345678
1 2026-01-05 70400 70200 70500 70100 11234567
▶ 여러 종목을 한 번에 수집하기
메인 부분만 아래처럼 바꾸면 됩니다.
if __name__ == "__main__":
stock_codes = [
"005930", # 삼성전자
"000660", # SK하이닉스
"010140", # 삼성중공업
"225570", # 넥슨게임즈
"005380", # 현대차
]
for code in stock_codes:
try:
get_stock_data(code, target_year=2026)
except Exception as e:
print(f"{code} 오류 :", e)
print()
그러면 StockData 폴더 아래에 다음과 같이 자동 저장됩니다.
StockData/
├─ 삼성전자.csv
├─ SK하이닉스.csv
├─ 삼성중공업.csv
├─ 넥슨게임즈.csv
└─ 현대차.csv
"이 데이터 구조는 이후 이동평균선, MACD, RSI, 거래량 분석 등으로 확장하기에도 적합합니다."
※ 개선하면 더 좋은 점 : AI로 위 코드에 아래 내용이 포함 되도록 합니다
이 코드는 실무에서도 사용할 수 있을 정도로 잘 작성되어 있지만, 몇 가지를 보완하면 더욱 견고해집니다.
- target_year를 함수 인자로 받아 임의의 연도(예: 2025, 2024 등)를 조회할 수 있도록 일반화할 수 있습니다.
- requests.get()에 timeout을 지정하여 네트워크 지연 시 무한 대기를 방지할 수 있습니다.
- pd.read_html()은 최신 Pandas 버전에서 문자열 입력 관련 경고가 발생할 수 있으므로 io.StringIO를 사용하는 방식으로 변경하면 호환성이 좋아집니다.
- 페이지 요청 사이에 time.sleep(0.5~1초) 정도를 추가하면 서버에 부담을 줄이고 차단 가능성을 낮출 수 있습니다.
- try-except를 사용해 네트워크 오류나 HTML 구조 변경에도 프로그램이 중단되지 않도록 예외 처리를 추가하면 더욱 안정적인 크롤러가 됩니다.

by korealionkk@gmail.com
반응형
'업무 자동화 > python' 카테고리의 다른 글
| 분석.csv → 판단 프로그램 만들기 (0) | 2026.08.03 |
|---|---|
| 기본 데이터.csv → 분석 데이터로 계산 하기 (0) | 2026.08.03 |
| 파이썬 학습] 리스트 활용 (0) | 2026.08.03 |
| 파이썬 학습] 리스트 사용법 배우기 (0) | 2026.08.01 |
| 파이썬 학습] 반복문 사용 방법 (0) | 2026.07.30 |