Python

Python 챌린지반 과제: API구현하고 출력하기

sawo11 2025. 1. 20. 21:07

마음대로 안되는게 너무 많아서 하루종일 붙잡고 있던 과제...🥲

이 길이 내 길이 아닌가 했지만.....결국엔 해결했다. 다 좋은 경험이겠지~


1) 기본 라이브러리 불러오기

import pandas as pd
import requests
  • pandas: 데이터를 DataFrame 형태로 관리하고 분석하는 데 사용
  • requests: HTTP 요청을 보내 API로부터 데이터를 가져오는 데 사용

2) API 요청

  • colab 환경에서 작업을 수행했는데 여기서부터 오류....🤢
  • 사실 이전 데이터도 오류가 나서 다른 데이터로 바꿨기 때문에 슬슬 힘들기 시작했다
  • 여기서 오류가 왜 나...? 라는 마음에 멘붕, 다른 방법도 시도해 봤지만 여기서 다른 방법이 필요할 리가..
  • API에 대한 지식이 있는 개발자에게 조언을 들은 바로는 API에서 colab이 차단당한 것 같다고! 
  • 그래서 vs code로 작업 환경을 바꿔 보았고 오류 없이 잘 실행되었다 🥺 (컴맹은 이걸로 하루를 날려먹어....)
💡 오류가 날 상황이 아닌 것 같은데 오류가 난다면? 다른 작업환경에서 실행해보자‼️
url = 'http://api.gwangju.go.kr/xml/stationInfo'
params = {'serviceKey' : '서비스키' }
response = requests.get(url, params=params)

 

  • url: API 엔드포인트 URL. 광주 API의 stationInfo 정보를 가져오는 URL
  • params: API 호출 시 필요한 인증 키를 포함한 파라미터
    • serviceKey: API 제공자로부터 발급받은 서비스 키
    • params 표현 방식은 아래처럼 두 가지로 가능
params = {'serviceKey' : '서비스키'}
params = {('serviceKey', '서비스키')}
  • requests.get():
    • API에 GET 요청을 보내 데이터를 받아옴
    • 반환된 response 객체는 API의 응답 데이터를 포함

3) XML 데이터 파싱

import xml.etree.ElementTree as ET
root = ET.fromstring(response.text)

 

  • response.text:
    • API 응답 데이터를 XML 형식의 텍스트로 반환
  • ET.fromstring():
    • XML 데이터를 트리(tree) 구조로 변환하여 root 객체로 저장
    • 이제 XML 데이터를 태그 기반으로 순회하거나 특정 데이터를 추출할 수 있게 됨

4) 데이터 저장용 딕셔너리 초기화

row_dict = {
    'BUSSTOP_ID': [], 'BUSSTOP_NAME': [], 'NAME_E': [],
    'LONGITUDE': [], 'LATITUDE': [], 'ARS_ID': [], 'NEXT_BUSSTOP': []
}
  • row_dict:
    • 데이터를 저장하기 위한 딕셔너리
    • 각 키는 XML 데이터에서 추출할 태그 이름과 동일하며, 값은 해당 태그의 데이터를 저장할 빈 리스트로 초기화됨

5) XML 데이터 순회 및 데이터 추출

for station in root.findall('.//STATION_LIST/STATION'):
    for child in station:
        if child.tag in row_dict:  # 딕셔너리에 있는 태그만 처리
            row_dict[child.tag].append(child.text)
  • root.findall('.//STATION_LIST/STATION'):
    • XML에서 <STATION_LIST> 태그 아래의 모든 <STATION> 태그를 찾음
    • 각 <STATION> 태그는 하나의 버스 정류소 정보를 나타냄
  • for child in station:
    • 각 <STATION> 태그의 자식 태그들(<BUSSTOP_ID>, <BUSSTOP_NAME>, 등)을 순회
  • if child.tag in row_dict:
    • 자식 태그 이름이 row_dict에 정의된 키와 일치하는 경우에만 데이터를 처리
    • 해당 태그의 텍스트 값을 딕셔너리의 해당 리스트에 추가

6) 누락된 데이터 처리

  • 누락된 데이터를 처리하지 않아서 또 한번 오류..!😵‍💫
    for key in row_dict:
        if len(row_dict[key]) < len(row_dict['BUSSTOP_ID']):  # 가장 긴 리스트에 맞춰 길이 보정
            row_dict[key].append(None)

 

  • 왜 누락된 데이터를 처리하는가?
    • XML 데이터에서 일부 태그가 누락된 경우, 리스트의 길이가 달라질 수 있음
    • Pandas DataFrame은 각 열(리스트)의 길이가 동일해야 하므로, 누락된 데이터에 대해 None 값을 추가하여 리스트의 길이를 맞춰야함
  • 어떻게 길이를 맞추는가?
    • row_dict['BUSSTOP_ID']의 길이를 기준으로 각 리스트 비교
    • 특정 태그의 리스트가 짧으면 None 값 추가
    • 누락된 데이터가 없는 리스트라면 다른 리스트도 가능

7) DataFrame 생성 및 결과 확인

df = pd.DataFrame(row_dict)

df.head() # print로 출력하면 표 형태로 나오지 않음
  • Pandas DataFrame:
    • row_dict 딕셔너리를 Pandas DataFrame으로 변환
    • 각 키(BUSSTOP_ID, BUSSTOP_NAME, 등)는 DataFrame의 열 이름이 되고, 각 리스트는 열의 데이터로 변환
  • df.head():
    • DataFrame의 상위 5개 데이터를 출력하여 데이터가 올바르게 처리되었는지 확인

8) 최종 코드

# 기본 라이브러리 불러오기
import pandas as pd
import requests

# API 요청
url = 'http://api.gwangju.go.kr/xml/stationInfo'
params ={'serviceKey' : '서비스키' }
response = requests.get(url, params=params)

# XML 데이터 파싱
import xml.etree.ElementTree as ET
root = ET.fromstring(response.text)

# 데이터 저장용 딕셔너리 초기화
row_dict = {
    'BUSSTOP_ID': [], 'BUSSTOP_NAME': [], 'NAME_E': [],
    'LONGITUDE': [], 'LATITUDE': [], 'ARS_ID': [], 'NEXT_BUSSTOP': []
}

#  XML 데이터 순회 및 데이터 추출
for station in root.findall('.//STATION_LIST/STATION'):
    for child in station:
        if child.tag in row_dict:  # 딕셔너리에 있는 태그만 처리
            row_dict[child.tag].append(child.text)
    
    # 누락된 데이터 처리
    for key in row_dict:
        if len(row_dict[key]) < len(row_dict['BUSSTOP_ID']):  # 가장 긴 리스트에 맞춰 길이 보정
            row_dict[key].append(None)

# DataFrame 생성
df = pd.DataFrame(row_dict)

# 결과 확인
df.head()

9) 실행 결과