작년 한 해 서울의 기온은 어떻게 변했을까요? 이런 작업을 하려면 날씨정보가 어디있는지 알아야 하고, 그 정보를 활용해서 우리가 보고싶은 모습으로 표현할 수 있어야 합니다. Weather Underground에서는 전세계의 날씨 데이터를 일자별, 주별, 월별, 기간별로 제공하고 있습니다.
한 가지 문제가 있습니다. 우리가 원하는 것은 일별 데이터인데 모두 확인하려면 대단한 노가다(?)를 해야한다는 것입니다. 파이썬의 Beautiful Soup 라이브러리를 활용하면 이 작업을 쉽게 처리할 수 있습니다. Beautiful Soup라이브러리는 html과 xml로 부터 데이터를 뽑아내기 위한 라이브러리 입니다. Beautiful Soup Document를 보시면 자세한 내용을 확인 할 수 있습니다.
이 라이브러리를 활용해서 서울의 기온데이터를 뽑아보도록 하겠습니다. 코드는 네이선 야우의 Visualize This를 참고하였습니다. 원래 파이썬 2로 작성된 것을 파이썬 3에서 평균기온, 최고기온, 최저기온을 추가로 표시할 수 있도록 수정한 것입니다.
#!-#-coding: utf8-*- import urllib.request from bs4 import BeautifulSoup # 기온데이터를 저장할 파일을 쓰기모드로 연다 f = open('wunder-data-seoul.txt', 'w') # 1월에서 12월까지 각 날짜의 페이지를 순회하면서 기온정보를 뽑아낸다 for m in range(1, 13): for d in range(1, 32): if (m == 2 and d > 28): #2월이 28일을 넘으면 중단하고 다음 달로 넘어간다 break elif (m in [4, 6, 9, 11] and d > 30): #4, 6, 9, 11월이 30일을 넘으면 중단하고 다음 달로 넘어간다 break if (len(str(m)) == 1) and (len(str(d)) == 1): timestamp = '20130' + str(m) + '0' + str(d) elif (len(str(m)) == 1) and (len(str(d)) == 2): timestamp = '20130' + str(m) + str(d) elif (len(str(m)) == 2) and (len(str(d)) == 1): timestamp = '2013' + str(m) + '0' + str(d) else: timestamp = '2013' + str(m) + str(d) # 뽑아내려는 기온데이터가 들어있는 페이지를 urllib 라이브러리로 불러온다 url = "http://english.wunderground.com/history/airport/RKSS/2013/" \ + str(m) + "/" + str(d) + \ "/DailyHistory.html?req_city=NA&req_state=NA&req_statename=NA" page = urllib.request.urlopen(url) # Beautiful Soup 라이브러리로 기온데이터를 추출한다. # 기온데이터는 nobr 클래스에 span태그로 둘러싸여 있다. soup = BeautifulSoup(page) dayMeanTemp = soup.find_all('span', attrs={"class":"nobr"})[0].span.string dayMaxTemp = soup.find_all('span', attrs={"class":"nobr"})[1].span.string dayMinTemp = soup.find_all('span', attrs={"class":"nobr"})[4].span.string print('date: {0},{1},{2},{3}'.format(timestamp, dayMeanTemp, dayMaxTemp, dayMinTemp)) if len(str(m)) < 2: mStamp = '0' + str(m) else: mStamp = str(m) if len(str(d)) < 2: dStamp = '0' + str(d) else: dStamp = str(d) timestamp = '2013' + mStamp + dStamp #읽어온 기온데이터를 파일에 쓴다 f.write(timestamp + ',' + dayMeanTemp + ',' + dayMaxTemp + ',' + dayMinTemp + '\n') # 모든 데이터를 읽었으면, 기온데이터를 저장한 파일을 닫는다 f.close()
이제 서울의 2013년 기온데이터 365개를 일자별로 얻었습니다. 세부 데이터는 첨부파일을 참고하세요
Beautiful Soup라이브러리의 HTML, XML 파싱이 필요한 어디에서는 사용할 수 있습니다. 즐겁게 사용해 보시기 바랍니다.
소스를 그대로 따라해보니
Traceback (most recent call last):
File "C:/Python34/aaa.py", line 35, in <module>
soup = BeautifulSoup(page)
File "C:\Python34\lib\site-packages\bs4\__init__.py", line 172, in __init__
self._feed()
File "C:\Python34\lib\site-packages\bs4\__init__.py", line 185, in _feed
self.builder.feed(self.markup)
File "C:\Python34\lib\site-packages\bs4\builder\_htmlparser.py", line 146, in feed
parser.feed(markup)
File "C:\Python34\lib\html\parser.py", line 165, in feed
self.goahead(0)
File "C:\Python34\lib\html\parser.py", line 222, in goahead
k = self.parse_starttag(i)
File "C:\Python34\lib\html\parser.py", line 413, in parse_starttag
self.handle_starttag(tag, attrs)
File "C:\Python34\lib\site-packages\bs4\builder\_htmlparser.py", line 48, in handle_starttag
self.soup.handle_starttag(name, None, None, dict(attrs))
File "C:\Python34\lib\site-packages\bs4\__init__.py", line 298, in handle_starttag
self.currentTag, self.previous_element)
File "C:\Python34\lib\site-packages\bs4\element.py", line 749, in __init__
self.name, attrs)
File "C:\Python34\lib\site-packages\bs4\builder\__init__.py", line 160, in _replace_cdata_list_attribute_values
values = whitespace_re.split(value)
TypeError: expected string or buffer
이런 에러가 나타나는데 왜 그런가요??
글 잘 읽었습니다. 파이썬이 이렇게 유용하게 쓰일 수 있다는 게 참 좋은 것 같습니다. 그런데 올라온 파일, get-weather-data-seoul.txt, 다운받아서 matplotlib으로 그래프를 그려본 결과 몇몇 잘못된 데이터 row가 있습니다. 10 이상인 걸로 보아 꽤 많더라고요. 그 부분 수정이 필요할 것 같습니다.