[웹 스크랩핑] 국민건강보험 병(의)원 정보 수집
연습 2 - 여러 페이지의 JSON 데이터 순차적으로 조회해서 수집하기
Jan 26, 2023
Contents
[국민건강보험]에서 병(의)원 정보 수집하기[국민건강보험]에서 병(의)원 정보 수집하기
- 국민건강보험 홈페이지에서 지역별 병(의)원 정보를 조회할 수 있는 페이지를 제공한다.
- 병원별로 제공하는 정보가 다르고, 중복되는 변수도 있다.
- 웹에서는 한 페이지에 10개의 병원만 조회가 가능하고, 다음 페이지로 이동하는 데 시간이 꽤 많이 소요된다.
- 지도가 포함된 페이지에서는 병원 이름, 전화번호 정도만 확인이 가능하다. 정말 필요한 정보를 확인하려면 (ex. 주말에 진료를 하는지) 상세 버튼을 눌러서 팝업 페이지에서만 확인이 가능하다는 단점이 있다.
- 지금까지 연습해본 페이지 중에서는 찾는 과정이 가장 어려웠다.
- 페이지를 이동할 때마다 요청을 보내는 Request URL을 찾아서 페이지 번호를 params로 전달해서 JSON 데이터를 직접 받아오는 방식으로 수집했다.
- JSON에 나타나는 변수명에 대한 정보가 없어서 검색하거나 비교해가면서 알아냈다. (요양기관 고유번호를 나타내는 이름 처럼 전문적인 용어가 섞여 있었음)
0. 라이브러리 불러오기
import time import pandas as pd import numpy as np import requests from bs4 import BeautifulSoup as bs from tqdm import tqdm import re
1. 총 페이지수(마지막 페이지) 찾기
1) 브라우저로 웹페이지에서 조회 시에는 마지막 페이지를 찾을 수 없음.
2) 병(의)원찾기 retrieveMdcAdminInq.do 페이지 url에 page번호=1 를 params로 전달.
3) requests.post로 요청 > json 받아오기 > ["pagination"] 선택
4) html 써있는 부분에서 a.last 의 onclick goPage(10025) 부분에서 숫자만 가져오기
url = "https://www.nhis.or.kr/nhis/healthin/retrieveMdcAdminInq.do" last_onclick = bs(pd.read_json(url)["pagination"][0]).select("a.last")[0]["onclick"] last_page_no = int(re.sub(r'[^0-9]', '', last_onclick)) last_page_no
2. get_page() : 페이지 단위로 정보 가져오기
def get_page(page_no) : """ 1. 병(의)원찾기 retrieveMdcAdminInq.do 페이지 url에 page번호를 params로 전달. 2. requests.post로 요청 > json 받아오기 > ["list"] 선택 3. 필요한 컬럼만 선택 (ykiho 포함) > 컬럼 이름 변경 (보건의료빅데이터시스템에 ykiho 검색결과 : 요양기관기호 > 각 의료기관별 전산체크번호 의미) """ try : url = "https://www.nhis.or.kr/nhis/healthin/retrieveMdcAdminInq.do" params = {"pageNum" : page_no} response = requests.post(url=url, params=params) hp_json = response.json() df_page = pd.DataFrame(hp_json["list"]) df_page = df_page[["hpName", "hpAddr", "lat", "lng", "ykiho"]] df_page.columns = ["병원명", "위치", "위도", "경도", "요양기관기호"] return df_page except Exception as e : print(f"페이지 {page_no} : {e}")
함수 작동 확인
result = get_page(2) result.head(4)
3. get_pages() : 여러 페이지의 정보 가져와서 합치기
def get_pages(max_page) : """ 1. get_page를 1 ~ max_page까지 여러 페이지 가져오기 2. 오류 발생시 page_no와 오류내용 출력 3. "nhis_search_마지막페이지번호_오늘날짜"로 csv파일 저장 4. 저장된 csv파일 읽어오기 """ temp_list = [] for page in tqdm(range(1, max_page+1)) : temp_list.append(get_page(page)) time.sleep(0.02) df = pd.concat(temp_list, ignore_index=True) df = df.drop_duplicates() today_date = time.strftime('%Y-%m-%d') file_name = f"nhis_search_{last_page_no}_{today_date}" df.to_csv(file_name, index=False, encoding='utf-8') return pd.read_csv(file_name)
df = get_pages(last_page_no) display(df.head(10)) display(df.tail(10))
4. get_content() : 요양기관기호(ykiho)를 받아서 세부정보 가져오기
1) 의료기관별 상세정보 클릭시 url은 변경 없음.
Network 탭에서 조회시 Request URL이 페이지를 이동할 때와 달라짐
ykiho : 요양기관기호 (기관 고유번호) > params로 전달 > requests 요청
# 4. 요양기관기호(hp_no) > 세부정보 가져오기 def get_content (ykiho) : """ 1. content_url에서 요양기관기호(ykiho)를 params로 requests.post 요청 2. 오류 발생시 content_no와 오류내용 출력 """ try : content_url = "https://www.nhis.or.kr/nhis/healthin/retrieveMdcAdminDtlSknsClinicInq.do" response = requests.post(url=content_url, params={"ykiho" : ykiho}) table = pd.read_html(response.text) tb_1 = table[0].set_index(0).T.reset_index(drop=True) # tb_2 = table[-6].set_index("구분").T.reset_index(drop=True) # tb_3 = table[-4].set_index("구분").T.reset_index(drop=True) # display(tb_1, tb_2, tb_3) # content = pd.concat([tb_1, tb_2, tb_3], axis=1) content = tb_1 return content except Exception as e : print(f"요양기관기호 {ykiho} : {e}")
get_content 함수 작동 확인
get_content(31563104)
5. progress_map : get_content 적용해서 기관별 세부정보 df에 추가하기
tqdm.pandas() df_detail = df["요양기관기호"].progress_map(get_content)
기관별 테이블이 달라서 오류 발생 >
Columns must be same length as key
6. 파일 저장
Share article