국내 데이터 Open API 4개

KOSIS Open API (국가통계포털)

  • API Key 발급: 1개의 Key로 KOSIS 전체 통계자료 접근 가능.
  • 데이터 범위: 통계청 및 통계작성기관이 제출한 공식 집계 통계 (예: 인구, 고용, GDP, 물가지수, 주택가격지수).
  • 강점: 하나의 키로 다양한 공식 통계 접근, 안정적이고 장기 시계열 제공.
  • 한계: 원시 데이터 없음, 집계된 통계 수치만 가능.

한국은행 경제통계시스템 API (ECOS)

  • API Key 발급: 한국은행 ECOS에서 Key 발급, 하나로 모든 통계 접근 가능.
  • 데이터 범위: 한국은행이 작성·관리하는 거시경제·금융 통계 (예: 통화량, 금리, 환율, 국민계정, 국제수지).
  • 강점: 신뢰성 높은 중앙은행 통계, 긴 시계열, 다양한 주기(월/분기/연간) 지원.
  • 한계: 통계코드(stat_code) 숙지 필요, 제공 범위는 집계 통계에 한정됨.

금융위원회 전자공시 DART API

  • API Key 발급: 금융감독원 Open DART 시스템에서 Key 신청 후 사용.
  • 데이터 범위: 상장·비상장 법인의 전자공시 자료 (사업보고서, 반기·분기보고서, 주요사항보고 등).
  • 강점: 기업 단위의 재무·공시 데이터에 직접 접근 가능, 상장사 과거 실적분석에 유용함.
  • 한계: 기업코드(corp_code) 매핑 필요, 요청 건수 제한 존재.

공공데이터포털 API (data.go.kr)

  • API Key 발급: 데이터셋(기관·서비스)별로 별도 Key 신청·승인 필요.
  • 데이터 범위: 개별 부처·기관이 제공하는 원시 행정 데이터 (예: 국토교통부 아파트 실거래가, 기상청 날씨 관측자료).
  • 강점: 실제 현장 일부에서 발생한 원시자료(raw data) 확보 가능.
  • 한계: 기관별 승인 필요, 품질·갱신 주기 불균등.

오픈 API 4개의 Python 호출 예제

각 예제는 최소 의존성(requests, pandas 옵션)과 기본 페이지네이션, 오류 처리 포함. 키는 환경변수로 읽는다.

Public Data Portal (공공데이터포털, data.go.kr/ODcloud)

python
import os, requests, pandas as pd

SERVICE_KEY = os.environ["DATA_GO_KR_KEY"]  # URL-encoded key 권장

BASE = "https://api.odcloud.kr/api/15077586/v1/centers"  # 예시: 예방접종센터 공개API
# 문서: page, perPage 지원

def fetch_odcloud(page=1, per_page=1000):
    params = {"page": page, "perPage": per_page, "serviceKey": SERVICE_KEY}
    r = requests.get(BASE, params=params, timeout=20)
    r.raise_for_status()
    return r.json()

# 전체 페이지 수집
def fetch_all_odcloud(per_page=1000):
    first = fetch_odcloud(1, per_page)
    total = first.get("totalCount", len(first.get("data", [])))
    pages = (total + per_page - 1) // per_page
    data = first["data"]
    for p in range(2, pages + 1):
        data.extend(fetch_odcloud(p, per_page)["data"])
    return pd.DataFrame(data)

df_od = fetch_all_odcloud()
print(df_od.head())

KOSIS Open API (국가통계포털, KOSIS)

python
import os, requests, pandas as pd

KOSIS_KEY = os.environ["KOSIS_KEY"]
# 편의: '사용자 통계식별자(userStatsId)'로 호출. 응답 JSON 권장.
# 예시 userStatsId는 본인 계정에서 생성한 식별자로 교체 필요.

def fetch_kosis_by_user_stats(user_stats_id, prdSe="A", start_prd="2010", end_prd="2024"):
    url = "https://kosis.kr/openapi/statisticsData.do"
    params = {
        "method": "getList",
        "apiKey": KOSIS_KEY,
        "format": "json",
        "jsonVD": "Y",          # 가변 명칭 포함
        "userStatsId": user_stats_id,
        "prdSe": prdSe,         # A=연간, Q=분기, M=월간
        "startPrdDe": start_prd,
        "endPrdDe": end_prd,
    }
    r = requests.get(url, params=params, timeout=30)
    r.raise_for_status()
    data = r.json()
    if isinstance(data, dict) and data.get("errMsg"):
        raise RuntimeError(data["errMsg"])
    return pd.DataFrame(data)

# 사용 예: 본인 userStatsId로 교체
# df_kosis = fetch_kosis_by_user_stats("사용자ID/폴더명/통계명")
# print(df_kosis.head())

파라미터식 호출이 필요할 때(기관+표ID 방식):

python
def fetch_kosis_by_table(orgId, tblId, objL1="", objL2="", prdSe="A", start_prd="2010", end_prd="2024"):
    url = "https://kosis.kr/openapi/statisticsData.do"
    params = {
        "method": "getList",
        "apiKey": KOSIS_KEY,
        "format": "json",
        "jsonVD": "Y",
        "orgId": orgId,
        "tblId": tblId,
        "objL1": objL1,   # 분류코드 필요시 지정
        "objL2": objL2,
        "prdSe": prdSe,
        "startPrdDe": start_prd,
        "endPrdDe": end_prd,
    }
    r = requests.get(url, params=params, timeout=30)
    r.raise_for_status()
    data = r.json()
    if isinstance(data, dict) and data.get("errMsg"):
        raise RuntimeError(data["errMsg"])
    return pd.DataFrame(data)

DART (전자공시, 금융감독원 Open DART)

python
import os, requests, pandas as pd

DART_KEY = os.environ["DART_API_KEY"]

# 공시 목록: 기간·종목 필터
def dart_list(bgn="20240101", end="20241231", corp_code=None, page_no=1, page_count=100):
    url = "https://opendart.fss.or.kr/api/list.json"
    params = {
        "crtfc_key": DART_KEY,
        "bgn_de": bgn,
        "end_de": end,
        "corp_code": corp_code,   # None이면 전체
        "page_no": page_no,
        "page_count": page_count,
    }
    r = requests.get(url, params=params, timeout=20)
    r.raise_for_status()
    js = r.json()
    if js.get("status") != "013":  # 013=정상 외 오류 코드 확인
        # DART는 '000'이 정상. (정상코드 확인 후 사용)
        pass
    return js

# 페이지네이션 수집
def dart_list_all(bgn, end, corp_code=None, page_count=100):
    page = 1
    rows = []
    while True:
        js = dart_list(bgn, end, corp_code, page, page_count)
        if js.get("status") != "000":
            raise RuntimeError(f"DART error {js.get('status')}: {js.get('message')}")
        lst = js.get("list", [])
        if not lst:
            break
        rows.extend(lst)
        if len(lst) < page_count:
            break
        page += 1
    return pd.DataFrame(rows)

# 예시 실행
# df_dart = dart_list_all("20240101", "20241231", corp_code=None, page_count=100)
# print(df_dart.head())

참고: 종목별 조회에는 DART의 기업코드 파일(corpCode.xml)을 사전 다운로드·파싱하여 종목명→corp_code 매핑이 필요하다.

python
# 기업코드 파일 갱신 및 파싱 예시
from zipfile import ZipFile
from io import BytesIO
import xml.etree.ElementTree as ET

def get_dart_corp_codes():
    url = "https://opendart.fss.or.kr/api/corpCode.xml"
    params = {"crtfc_key": DART_KEY}
    r = requests.get(url, params=params, timeout=30)
    r.raise_for_status()
    zf = ZipFile(BytesIO(r.content))
    with zf.open(zf.namelist()[0]) as f:
        tree = ET.parse(f)
    root = tree.getroot()
    recs = []
    for el in root.findall("list"):
        recs.append({child.tag: child.text for child in el})
    return pd.DataFrame(recs)  # columns: corp_code, corp_name, stock_code, modify_date

# df_codes = get_dart_corp_codes()
# print(df_codes.query("stock_code == '005930'"))  # 삼성전자 예시

Bank of Korea ECOS API (한국은행 경제통계시스템, ECOS)

python
import os, requests, pandas as pd

BOK_KEY = os.environ["BOK_ECOS_KEY"]

# 통계조회: StatisticSearch
# 형식: /api/StatisticSearch/{Key}/{format}/{lang}/{start}/{end}/{stat_code}/{cycle}/{start_time}/{end_time}/{item_code...}
def ecos_stat_search(stat_code, cycle, start_time, end_time, start_row=1, end_row=1000, lang="kr", fmt="json"):
    base = "https://ecos.bok.or.kr/api/StatisticSearch"
    url = f"{base}/{BOK_KEY}/{fmt}/{lang}/{start_row}/{end_row}/{stat_code}/{cycle}/{start_time}/{end_time}"
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    js = r.json()
    data = js.get("StatisticSearch", [])[1:]  # [0] = header
    return pd.DataFrame(data)

# 예시: 소비자물가 CPI(코드 예시는 사용 전 확인 필요), 월간, 2015-01 ~ 2025-08
# df_bok = ecos_stat_search(stat_code="021Y126", cycle="M", start_time="201501", end_time="202508")
# print(df_bok.head())

추가 메모

  • Authentication(인증, 인증): 모두 단순 키 방식. 요청빈도 제한 존재. 재시도와 지수 백오프 권장.
  • Pagination(페이지네이션): data.go.kr은 page/perPage, DART는 page_no/page_count, ECOS는 start_row/end_row, KOSIS는 데이터량이 많으면 분할 호출.
  • Encoding(인코딩): 공공데이터포털은 서비스키 URL 인코딩 필요. KOSIS 응답은 한글 키가 섞일 수 있어 DataFrame 컬럼 정리 권장.
  • Formats(포맷): ECOS와 KOSIS는 json 권장. DART는 json과 xml 모두 제공.

원하는 통계 코드나 테이블 식별자(userStatsId, orgId+tblId)가 있으면 알려 주면 즉시 맞춤 예제로 바꿔 준다.