본문 바로가기

Python 코딩 모음

공공데이터포털 API 활용을 위한 왕초보용 코드

왕초보 코더 텅스텐화살입니다.

오래간만에 포스팅하네요. 

공공데이터포털의 API를 활용하기 위한 수많은 비IT 전공자가 있을 것 같은데,

그 분들에게 작은 도움을 드리고자 작성하게 되었습니다.

 

xml 형태로 결과를 보여주는 공공데이터포털 API는 거의 그대로 가져다 쓰실 수 있을 것입니다.

쓰시기 전에 주석을 잘 보시면 활용하시는 데 도움이 되실 겁니다.

 

초간단 설명 : 

반환(return) 값 중 returnerrMsg가 None 값이면 정상적으로 조회된 결과가 response 안에 있을 것이며,

제대로 조회되지 않으면 오류 결과 xmldl response안에 있고 returnerrMsg에 오류 메세지가 들어가 있게 됩니다.

제일 아래에 해당 함수에 대한 코드가 있습니다.

 

주저리주저리 설명 :

 

우선, 해당 함수를 쓰기에 앞서, 해당 함수의 입력값으로 필요한 url과 parameter 값은 아래와 같습니다.

 

1. URL

url은 2개의 주소(End point + GET 주소)를 연결한 문자열(str)입니다.

 

첫번째 주소(End point) 확인

오픈API 활용 신청이 완료되면, 마이페이지에 들어가면 'API 신청 N 건'이라고 적힌 곳을 들어가면 하단에 사용 가능한 API들 리스트가 죽 뜹니다.

원하는 API를 클릭해서 보면 아래와 같은 페이지가 뜨는데 여기서 End Point(아래 그림에서 까만 칸)에 적힌 주소가 첫번째 주소입니다.

 

두번째 주소(GET 주소) 확인

위에 화면에서 '상세설명'을 클릭하여 해당 API의 상세 설명으로 들어가서 화면을 내려가면 아래와 같은 화면이 나오는데, 'GET' 옆에 적힌 부분(아래 그림에서 까만 칸)에 주소가 두 번째 주소입니다.

 

이제, 첫번째 주소와 두번쨰 주소를 이어붙이면 url 값이 완성됩니다.

 

2. Parameter

파라미터는 원하는 결과를 얻기 위해 넣는 값입니다.

위에 화면 캡쳐에 보이는 GET 부분을 클릭하면 아래와 같은 화면이 나옵니다.

 

위에서처럼 필요한 조건을 적어야 하는데, 파이썬 코딩에서는 다음과 같이 적으면 됩니다. 적는 순서는 상관없습니다.

params = {'serviceKey':본인의 서비스키,'strtYymm':'201901',
          'endYymm':'201912','sidoCd':'44'}

위에서 '본인의 서비스키' 부분은 마이페이지에 들어가시면 '개인 API인증키'에서 확인할 수 있으며, 제 기준으로 '인증키 복사(Decoding)'을 하면 사용이 되었습니다. 경우에 따라서 '인증키 복사(Encoding)'을 넣어야 하실 수도 있습니다.

 

파라미터는 꼭 API에서 요구하는 양식을 꼭 맞춰줘야하니 예시를 참고하여 잘 작성해야 합니다.

 

3. 조회하여 xml 결과를 받는 함수 :

위와 같이 url과 params를 모두 설정하고 나서 아래의 함수를 사용하시면 조회 결과가 나옵니다.

(사용 전 requests 패키지 설치 여부 확인하시기 바랍니다.)

 

반환(return) 값 중 returnerrMsg가 None 값이면 정상적으로 조회된 결과가 response 안에 있을 것이며,

제대로 조회되지 않으면 오류 결과 xmldl response안에 있고 returnerrMsg에 오류 메세지가 들어가 있게 됩니다.

# requests 패키지 설치 후 사용하세요.

def APIcall_PublicDATA_xml(url,params) :
    '''
    공공데이터포털의 API를 호출하기 위한 함수입니다.
    응답으로 받은 xml 결과값(response)와 에러메세지(returnerrMsg)를 반환(return)합니다.
    정상적으로 조회가 될 때까지 while문이 돌고, 심각한 오류 또는 정상 조회되면 종료됩니다.
    현재는 xml 형태의 결과에 대해 분석이 가능합니다.
    (현재 다른 output 형태에 대해서는 처리 불가)
    API가 정상조회된 경우 status_code가 200이고, 에러메세지는 errMsg로 보여주는 경우
    거의 수정하지 않고 사용이 가능합니다.
    '''
    import xml.etree.ElementTree as ET
    import requests
    import time
    
    while True : # 마이너한 오류가 나는 경우 계속 while문을 돈다.

        # status_code가 200이 될 때까지 호출하기
        '''
        아래 while문은 status_code가 200이 될 때까지 호출하는 함수입니다.
        (status_code 정상을 의미하는 값이 200이 아닌 경우에는 200을 수정해야 합니다.)
        조회 요청 후 응답이 올 때까지 최대 1분(timeout=60)을 기다리며,
        1분동안 응답이 오지 않으면 5분(time.sleep(300)) 이후 재시도합니다.
        그 외 오류인 경우에는 오류를 보여주고 다시 조회를 하되,
        5회(try_count<=5)까지는 3초 간격으로 조회하고,
        이후는 10분(time.sleep(600)) 간격으로 조회합니다.
        '''
        status_info = ''
        try_count = 0
        while status_info != 200 :
            try : # 조회 시도하기, 5회 이내는 3초마다, 5회 넘어가면 10분마다 조회
                response = requests.get(url,params=params,timeout=60)
                status_info = response.status_code
                if try_count <= 5 and status_info != 200 : # 여전히 상태가 비정상이면 3초간 쉬기
                    # print('상태: '+str(status_info)+', 재시도 중...'+str(try_count)+'회차 시도합니다.')    
                    try_count += 1
                    time.sleep(3)
                if try_count > 5 and status_info != 200 :
                    time.sleep(600) # 5회 이상 조회했는데 비정상이면 10분씩 쉬어가면서 조회하기
            except requests.exceptions.Timeout:
                print('요청이 타임아웃 되었습니다. 5분 후 재시도합니다.')
                time.sleep(300)
            except requests.exceptions.RequestException as e:
                print(f"오류 발생: {e}")
                pass
        
        '''
        아래는 응답 결과에서 에러 메세지가 있는 경우에 대처하는 코드입니다.
        (에러메세지를 'errMsg'를 통해 보여주지 않는 API는 수정이 필요합니다.)
        특별히 오류가 없는 경우에는 returnerrMsg가 None 값을 가지게 되며,
        에러메세지(errMsg)가 None인 관계로 while문이 종료, 리턴을 준비하게 됩니다.
        
        심각한 오류가 있는 경우 returnerrMsg에 메세지를 저장하고 while문이 종료,
        리턴을 준비하게 됩니다.
        * 심각한 오류 : API 폐기(12), 접근거부(20), 횟수초과(22), 미등록 서비스키(30),
                      기간만료(31),미등록IP(32)
        
        마이너 오류인 경우에는 while문(while True)을 다시 돌아서 조회하게 됩니다.
        * 마이너 오류 : 에러(1),HTTP에러(4),알수없는에러(99)        
        '''
        xml_data = response.text
        root = ET.fromstring(xml_data)
        
        # 에러 메세지가 있는 경우를 찾기
        returnerrMsg = None # 기본 에러 메세지값은 None
        errMsg  = root.find('.//errMsg') # 에러메세지 유무를 판단하는 기준
        if errMsg is not None :
            errMsgcode = root.find('.//returnReasonCode').text
            if errMsgcode in ['12','20','22','30','31','32'] :
                returnerrMsg = root.find('.//returnAuthMsg').text
                # print('API 호출 중 Error 발생 : '+returnerrMsg)
                break # 심각한 오류가 있는 경우 while문 빠져나옴
        else :
            break # 에러 메세지가 없는 경우(정상 조회인 경우) while 문 빠져나옴
                
            
    return response, returnerrMsg # 튜플 형태로 결과 리턴, 오류가 없을시 returnerrMsg은 None 값임.

 

이상입니다. 코드 자체는 별로 고급적인 요소가 없기 때문에 AI들에게 물어보면 친절하게 분석해주고, 더 좋은 코드를 추천받으실 수도 있을 것입니다.

부디 저처럼 맨땅에 해딩하는 초보 코더들에게 도움이 되길 빕니다.