python | 공공데이터 활용하기

yeonk·2023년 7월 24일
0

python

목록 보기
23/23
post-thumbnail

시작하기 전에


우아한테크코스 팀 프로젝트를 진행하면서 공공데이터를 활용하여 그 과정을 기록해보고자 한다.

우리가 사용한 데이터는 농촌 진흥청의 실내정원 식물 데이터 이고, 응답 데이터 형식은 xml이다.

데이터 파싱을 위해 python , beautifulsoup 를 사용하였다.
그리고 환경설정 및 pandas 사용이 편리하기 때문에 구글에서 제공해주는 코랩(jupyter notebook)을 사용하였다.










사전 준비


  • 공공데이터를 사용하기 위해 데이터 사용 신청을 진행하고, 승인 후에 작업을 진행한다.
  • 데이터의 이용 허락 범위를 확인하고 적절한 범위 내에서 사용한다.
  • open api 사용 매뉴얼을 숙지한다.
  • 제공되는 데이터의 형태나 종류를 파악한다.










설정


구글 코랩을 사용한다면 아래와 같은 설정을 통해, 개인 드라이브에 접근하여 파일을 저장하고 불러올 수 있다.
만약 구글 코랩을 사용하지 않는다면 이 설정은 하지 않아도 무방하다.

from google.colab import drive
drive.mount('/content/drive')





사용할 모듈을 import 해준다.
아래 모듈들은 각각 요청, 데이터 파싱, 전처리 및 CSV 파일 저장을 위해 imort 하였다.

import requests
from bs4 import BeautifulSoup
import pandas as pd





공통적으로 사용되는 값들도 미리 설정하였다.
각각의 변수에 들어갈 값은 아래와 같다.

  1. 승인과 함께 받은 api key를 적는다.
  2. request 시 api key를 보낼 때 사용되는 포맷이다.
  3. 모든 요청에서 사용되는 공통 URI를 적는다.
api_key = "발급 받은 api key" # 1
request_key_format = "apiKey=" +  api_key # 2
base_url = "http://api.nongsaro.go.kr/service/garden/" # 3










식물 리스트


요청

아래 값들을 미리 설정해줍니다.

(1)요청 url에 사용될 keyword
(2)한 페이지에 몇 개의 데이터를 받아올지에 대한 값

garden_list_keyword = "gardenList" # 1
rows = "217" # 2





요청을 편하게 보낼 수 있도록 함수를 작성하였습니다.
인자 값으로는 요청 url에 사용될 keyword와 한 페이지에 받을 데이터 수가 들어가게 됩니다.

  1. item 태그를 가진 값들을 모두 가져옵니다(find_all).
def request_with_num_of_rows(keyword, rows):
    request_url = base_url + keyword +  "?" + request_key_format + "&numOfRows=" + rows
    response = requests.get(request_url)
    response_xml = BeautifulSoup(response.text,'lxml-xml')
    return response_xml.find_all("item") # 1





위에서 설정한 변수들과 메서드를 조합하여 요청을 보냅니다.

garden_list_items = request_with_num_of_rows(garden_list_keyword, rows)





파싱

데이터 파싱을 위한 함수를 만들어줬습니다.
아래 함수를 하나씩 확인해보겠습니다.

  1. item에서 cntntsNo 태그에 대한 값을 찾고 text를 추출합니다. 이 때 item은 item 태그를 가진 데이터 입니다. cntnts_no 는 원하는 임의의 변수로 지정하시면 됩니다.

  2. return 값은 코드에 나타낸 것과 같이 딕셔너리 이고, 키:밸류 형태를 가지고 있습니다.

  3. 이 때 딕셔너리의 키 값은 원하는 컬럼명을 적고, 그 뒤에는 1번에서 정한 임의의 변수를 적어줍니다. value 값으로 cntnts_no 로 작성하시면 됩니다.
    하지만 결과 값이 (데이터,) 형태를 가지는 튜플 타입이기 때문에 저는 cntnts_no[0] 으로 작성하였습니다.

  4. rtn_file_url[0].split('|')[0] 부분을 보면 split을 사용했습니다. | 를 기준으로 여러 데이터가 들어있는 스트링이기 때문에 사용한 것입니다. 저는 여러 데이터 중 첫번째 데이터만 사용할 것이므로 0번째 인덱스의 값만 사용하도록 작성하였습니다.

def parse_garden_list(item):
    cntnts_no = item.find("cntntsNo").get_text(), # 1
    cntnts_sj = item.find("cntntsSj").get_text(),
    rtn_file_url = item.find("rtnFileUrl").get_text(),

    return { # 2
        "컨텐츠번호": cntnts_no[0], # 3
        "식물명": cntnts_sj[0],
        "저장파일url": rtn_file_url[0].split('|')[0] # 4
    }





item 태그를 가진 값들의 목록들을 인자로 받고, for문을 돌면서 item을 하나씩 파싱한 후 데이터 프레임화를 할 수 있는 함수를 만들었습니다.

def make_dataframe_for_garden_list(items):
    row = []
    for item in items:
        row.append(parse_garden_list(item))
    return pd.DataFrame(row)





(1) 앞서 만든 함수를 적용해서 파싱 및 데이터프레임화를 완료합니다.
(2) 변수를 셀 마지막에 찍으면 print(garden_list_df)를 한 것과 같은 결과를 볼 수 있습니다.

garden_list_df = make_dataframe_for_garden_list(garden_list_items) # 1

garden_list_df #2





csv 파일 저장하기

원하는 경로와 파일이름을 적고 저장하면 파일 생성을 할 수 있습니다.

garden_list_df.to_csv("경로/원하는 이름.csv")

1개의 댓글

comment-user-thumbnail
2023년 7월 24일

많은 도움이 되었습니다, 감사합니다.

답글 달기