Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 애플
- 코스피
- Python
- matter
- homebridge
- 오블완
- 나스닥
- 공모주
- 해외주식
- 매터
- MQTT
- RS-485
- 월패드
- Bestin
- Home Assistant
- 국내주식
- 홈네트워크
- esp32
- 티스토리챌린지
- ConnectedHomeIP
- SK텔레콤
- 힐스테이트 광교산
- Espressif
- 미국주식
- 배당
- 현대통신
- cluster
- raspberry pi
- 파이썬
- Apple
Archives
- Today
- Total
YOGYUI
Python::BeautifulSoup - 기상청 '도시별 현재날씨' 크롤링 본문
반응형
[ Web Crawling (Python) ]
기상청 날씨누리 사이트의 '도시별 현재날씨' 정보를 pandas DataFrame 객체로 저장해보자
www.weather.go.kr/weather/observation/currentweather.jsp
1. HTML GET
requests 라이브러리를 사용해 해당 url의 html을 가져온다
import requests
from bs4 import BeautifulSoup
url = "https://www.weather.go.kr/weather/observation/currentweather.jsp"
html = requests.get(url).text
soup = BeautifulSoup(html, "html.parser")
print(soup)
html parser를 이용해 파싱한 soup 객체를 print해보면 다음과 같은 도입부를 확인할 수 있다
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>도시별 현재날씨 > 지상관측자료 > 관측자료 > 날씨 > 기상청 </title>
<link rel="shortcut icon" href="https://www.kma.go.kr/iphone-shortcut.png" />
<link rel='apple-touch-icon-precomposed' href='https://www.kma.go.kr/iphone-shortcut.png'/>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />
<link rel="stylesheet" type="text/css" href="/share/css/base.css?ver=20210128" />
<link rel="stylesheet" type="text/css" href="/share/css/common.css?ver=20210128" />
<link rel="stylesheet" type="text/css" href="/share/css/weather-layout.css?ver=20210128" />
<link rel="stylesheet" type="text/css" href="/share/css/component.css?ver=20210128" />
<link rel="stylesheet" type="text/css" href="/share/css/add_2018.css?ver=20210128" />
<!-- 후략 -->
우리과 관심있는 것은 현재 날씨 정보가 담긴 테이블이다
테이블은 caption tag가 "기상실황표"인 <table>을 찾으면 된다
(class 이름이 "table_develop3"이다...웹개발자들이 개발 완료 후에 딱히 코드 정리는 안하는듯? ㅎㅎ)
<table class="table_develop3" summary="기상실황표로 지점, 날씨, 기온, 강수, 바람, 기압등을 안내한 표입니다.">
<caption>기상실황표</caption>
<colgroup>
<col style="width:14%"/>
<col style="width:12%"/>
<col style="width:7%"/>
<col style="width:5%"/>
<col style="width:8%"/>
<col style="width:5%"/>
<col style="width:6%"/>
<col style="width:5%"/>
<col style="width:8%"/>
<col style="width:5%"/>
<col style="width:5%"/>
<col style="width:8%"/>
<col style="width:6%"/>
<col />
</colgroup>
<thead>
<tr id="table_header1" class="table_header">
<th scope="col" rowspan="2" class="top_line">지점</th>
<th scope="col" colspan="4" class="top_line" id="headers-weather">날씨</th>
<th scope="col" colspan="3" class="top_line" id="headers-temp">기온(℃)</th>
<th scope="col" colspan="3" class="top_line" id="headers-rain">강수</th>
<th scope="col" colspan="2" class="top_line" id="headers-wind">바람</th>
<th scope="col" class="top_line" id="headers-press">기압(hPa)</th>
</tr>
<tr id="table_header2" class="table_header">
<th scope="col" class="nm" headers="headers-weather">현재일기 </th>
<th scope="col" class="nm" headers="headers-weather">시정<br/>km</th>
<th scope="col" class="nm" headers="headers-weather">운량<br/>1/10</th>
<th scope="col" class="nm" headers="headers-weather">중하운량</th>
<th scope="col" class="nm" headers="headers-temp">현재<br/>기온</th>
<th scope="col" class="nm" headers="headers-temp">이슬점<br/>온도</th>
<th scope="col" class="nm" headers="headers-temp">체감<br/>온도</th>
<th scope="col" class="nm" headers="headers-rain">일강수<br/>mm</th>
<th scope="col" class="nm" headers="headers-rain">적설<br/>cm</th>
<th scope="col" class="nm" headers="headers-rain">습도<br/>%</th>
<th scope="col" class="nm" headers="headers-wind">풍향 </th>
<th scope="col" class="nm" headers="headers-wind">풍속<br/><script>writeWindSpeedUnit();</script></th>
<th scope="col" class="nm" headers="headers-press">해면<br/>기압</th>
</tr>
</thead>
<tbody>
<!-- 후략 -->
각 지점들의 기상 정보에 해당하는 테이블 행 태그 <tr>들은 다음과 같이 구성된다
<tr>
<td>
<a href="/weather/observation/currentweather.jsp?tm=2021.2.7.14:00&type=t99&mode=0&reg=100&auto_man=m&stn=105" >
강릉
</a>
</td>
<td> </td>
<td>9.9</td>
<td> </td>
<td> </td>
<td>9.1</td>
<td>2.1</td>
<td>7.4</td>
<td> </td>
<td> </td>
<td>62</td>
<td>북동</td>
<td><script>writeWindSpeed('3.0', false, '', '', 1);</script></td>
<td>1017.9</td>
</tr>
<tr>
<td>
<a href="/weather/observation/currentweather.jsp?tm=2021.2.7.14:00&type=t99&mode=0&reg=100&auto_man=m&stn=259" >
강진군
</a>
</td>
<td> </td
<td>7.2</td>
<td> </td>
<td> </td>
<td>13.8</td>
<td>0.4</td>
<td>12.8</td>
<td> </td>
<td> </td>
<td>40</td>
<td>북서</td>
<td><script>writeWindSpeed('3.7', false, '', '', 1);</script></td>
<td>1020.2</td>
</tr>
<!-- 후략 -->
데이터가 없는 (빈) 항목의 태그값은   (non-breaking space)로 공백으로 구성되어 있다
2. Make DataFrame
위 정보를 토대로, 테이블 내 모든 <tr> 태그들에 대해 <td>들의 텍스트 리스트를 생성해 데이터프레임을 만들 수 있다
import requests
import pandas as pd
from bs4 import BeautifulSoup
url = "https://www.weather.go.kr/weather/observation/currentweather.jsp"
html = requests.get(url).text
soup = BeautifulSoup(html, "html.parser")
table = soup("table", "table_develop3")[0]
# 테이블 내 모든 <tr> 태그 리스트업
table_rows = table.find_all("tr")
# 최초 두 태그는 테이블 헤더로 사용됨, 이후는 모두 데이터 항목
table_headers = table_rows[:2]
table_data = table_rows[2:]
# 모든 데이터 행에 대해 <td> 항목 추출
table_data_elements = [x.find_all("td") for x in table_data]
# 리스트 만든 후 DataFrame 생성
data = []
for elem in table_data_elements:
if len(elem) > 0:
data.append([x.text for x in elem])
df = pd.DataFrame(data)
# 헤더 데이터 추출
header_text0 = [x.text for x in table_headers[0].find_all("th")]
header_text1 = [x.text for x in table_headers[1].find_all("th")]
header = [header_text0[0].replace('\r\n\t\t', '')] + header_text1
df.columns = header
df.head(5)
[결과]
지점 현재일기 시정km ... 풍향 풍속writeWindSpeedUnit(); 해면기압
0 강릉 6.6 ... 북서 writeWindSpeed('3.5', false, '', '', 1); 1018.9
1 강진군 4.0 ... 북서 writeWindSpeed('3.3', false, '', '', 1); 1020.4
2 강화 맑음 20 이상 ... 서남서 writeWindSpeed('2.4', false, '', '', 1); 1022.5
3 거제 5.6 ... 북북서 writeWindSpeed('1.5', false, '', '', 1); 1018.8
4 거창 9.3 ... 북서 writeWindSpeed('3.4', false, '', '', 1); 1018.1
[5 rows x 14 columns]
풍속의 경우 javascript 코드가 들어있는데 (writeWindSpeedUnit, writeWindSpeed), 해당 스크립트는 기상청 서버 내부에 정보가 들어있는 것 같아 대체할 수가 없다
<script src="/share/js/weather-common.js?ver=20210128"></script>
지점에 원하는 지역 이름을 매칭하여 필터링하면 해당 지역의 기상 정보를 가져올 수 있다
df[df['지점'] == '수원'].values
>> array([['수원', '연무', '8.2', '0', '0', '5.8', '0.0', '2.2', '\xa0', '\xa0',
'66', '서', "writeWindSpeed('5.2', false, '', '', 1);", '1021.5']],
dtype=object)
끝~!
반응형
'Data Analysis > Data Engineering' 카테고리의 다른 글
공공데이터포털::공휴일 데이터 조회 (REST API) (10) | 2021.04.03 |
---|---|
Python::folium - 빅데이터분석기사 필기시험 고사장 위치 지도시각화 (0) | 2021.02.26 |
공공데이터포털::코로나19 감염현황 데이터 조회 (REST API) (0) | 2021.02.22 |
Python::BeautifulSoup - 동행복권 연금복권720+ 당첨번호 크롤링 (0) | 2021.02.21 |
Python::BeautifulSoup - 동행복권 로또 6/45 당첨번호 크롤링 (0) | 2021.02.19 |