학원 프로젝트

간호사 업무 해소 환자 위치 찾기 프로젝트 (2. 공공데이터 활용 )

hojomu 2023. 5. 30. 10:25

1. 개요

사용자가 병원의 이름을 입력 했을 때, 해당 키워드가 포함된 병원의 리스트와 병원의 위치 데이터를 활용하고 싶었다.

 

2. 공공데이터 이용하기

이용하려고 하는 공공데이터에는 약 78000개의 병원 데이터가 있었다. 이 병원들 중 사용자가 입력한 키워드가 병원 이름에 포함되어 있는 경우에, 배열에 저장하고 list로 나타내는 script를 작성했다.

$.ajax({
            type:'GET',
            dataType:'JSON',
            url:`${apiUrl}?ServiceKey=${serviceKey}&numOfRows=${numOfRows}&pageNo=1&sidoCd=${cityData}`,
            error: function(err){
                console.log(err);
            },
            success: function(data){
                console.log(data);
                var items = data.response.body.items.item;
                console.log(items[0].yadmNm)

                for (let i = 0; i < items.length; i++){
                    if (items[i].yadmNm.includes(hospital)){
                        hosLi += "<li class='hospitalName' data-x='"+items[i].XPos+"' data-y='"+items[i].YPos+"' data-key='"+items[i].yadmNm+"'>"+items[i].yadmNm+" : "+items[i].addr+"</li>"
                    }
                }
            
            $("#hospitalList").html(hosLi);

            // li에 이벤트 부여하기
		    $(document).on("click",".hospitalName",hospitalClick);
            }
        })

 - 위의 코드는 공공 데이터를 JSON 타입으로 받아오고, .includes() 함수를 사용해서 사용자가 입력한 키워드가 포함된 병원만 li로 만들어서 나타내도록 검색 기능을 구현했다.

 

보통 대량의 정보를 가져오는 공공데이터는 한 번에 가져올 수 있는 데이터의 양에 한도가 있기 때문에

78000개의 병원 데이터를 모두 가져와서 키워드와 비교할 때는 100개 정도의 rows 를 780개의 page로 나눠서 불러오는 작업을 수행해야한다.

하지만 이 작업을 매번 수행하면 시간이 너무 오래걸린다. 그래서 병원 수가 1500개 정도 되는 울산으로만 한정해서 이번 과제를 수행했다.

 

공공데이터를 일정 주기마다 JSON형태로 저장하는 python파일을 만들고, JSON으로 미리 저장되있는 데이터를 활용하는 방법이 더 좋다. 다음에 대량의 공공데이터를 이용할 필요가 있다면 이 방법을 시도해 보자.

 

3. python 파일 예시

 : 이 코드는 공공데이터를 30개 씩 약 2500개의 page로 불러오고 필요한 데이터를 JSON형태로 변환한 후

DB에 저장하는 코드이다. 하지만 이 방법은 시간이 너무 오래 걸리고 DB에 접속할 때도 무거워질 것을 고려해서 실행하지는 않았다.

 

다음번에는 이런 방식으로 데이터를 불러와서, json 형태의 파일로 저장해서 활용할 수 있도록 하자.

또한 json형태로 저장한 파일을 공공데이터가 갱신되는 주기에 맞춰서 자동으로 갱신되는 기능도 만들어보자.

import requests
import xml.etree.ElementTree as ET
import mysql.connector

# MySQL 연결 정보
MYSQL_HOST = '192.168.30.13'
MYSQL_PORT = 3306
MYSQL_USER = 'jht0725'
MYSQL_PASSWORD = '1234'
MYSQL_DB = 'mydb'

# API 호출 및 데이터 수신
url = 'https://apis.data.go.kr/B551182/hospInfoServicev2/getHospBasisList'
service_key = ''

params = {
    'ServiceKey': service_key,
    'numOfRows': 30
}

total_data = []
page = 1
while len(total_data) < 76642:
    params['pageNo'] = page
    response = requests.get(url, params=params)

    print(response)

    # XML 형식의 응답을 파싱하여 데이터 추출
    root = ET.fromstring(response.content)
    print(root)
    items = root.findall('.//item')
    print(items)
    for item in items:
        # 필요한 데이터 추출
        hospital_name = item.findtext('yadmNm')
        sido_cd_nm = item.findtext('sidoCdNm')
        telno = item.findtext('telno')
        x = item.findtext('XPos')
        y = item.findtext('YPos')
        address = item.findtext('addr')

        if x is not None:
            x = float(x)
        else:
            x = 0.0

        if y is not None:
            y = float(y)
        else:
            y = 0.0

        print('hospital_name: {}, sido_cd_nm: {}, telno: {}, x: {}, y: {}, address: {}'.format(hospital_name, sido_cd_nm, telno, x, y, address))

        total_data.append({'hospital_name': hospital_name, 'sido_cd_nm': sido_cd_nm, 'telno': telno, 'x': x, 'y': y, 'address': address})

    page += 1

# MySQL에 데이터 저장
conn = mysql.connector.connect(
    host=MYSQL_HOST,
    port=MYSQL_PORT,
    user=MYSQL_USER,
    password=MYSQL_PASSWORD,
    database=MYSQL_DB
)

cursor = conn.cursor()

for data in total_data:
    hospital_name = data['hospital_name']
    sido_cd_nm = data['sido_cd_nm']
    telno = data['telno']
    x = data['x']
    y = data['y']
    address = data['address']

    # INSERT 쿼리 실행
    query = "INSERT INTO hospital (hospitalName, sidoCdNm, telno, X, y, addr) VALUES (%s, %s, %s, %s, %s, %s)"
    values = (hospital_name, sido_cd_nm, telno, x, y, address)
    cursor.execute(query, values)

conn.commit()
conn.close()

 

4. 결과

'피부' 를 검색하면 울산에 있는 병원들 중 이름에 피부가 들어가는 병원들을 확인할 수 있다.