본문으로 바로가기

[Python]웹페이지 크롤링(requests,beautifulSoup 사용)

category Python 2017. 11. 23. 17:59

프로젝트를 진행함에있어, 어떤 정보가 필요함에 우리는 웹페이지에서 원하는 정보를 얻을수 있습니다. 


정보가 공공데이터나 어디서 쉽게 구할수 있다면 가장 좋겠지만 그렇지 않은경우 웹페이지를 크롤링해서 정보를 얻어올 수 있습니다.


크롤링(Crawling)이란.

웹페이지를 그대로 가져와서 데이터를 추출하는 행위를 말합니다.


엄청난 양의 웹페이지 데이터를 일일이 추출해 내기란 너무 힘이듭니다. 그래서 우리는 파이썬을 활용해 웹페이지 크롤러를 만들어 내가원하는 정보를 얻어올 수 있습니다.



하지만 웹페이지를 크롤링 할때도 주의해야할 사항이 있습니다.


1. 스크랩하는 컨텐츠에 지적재산권이 있는지 

2. 크롤링 하는 행동이 사이트에 큰 부담을 주지 않는지

3. 크롤러가 사이트의 이용방침을 위반하지 않는지

4. 크롤러가 사용자의 민감한 정보를 가져오지 않는지

5. 가져온 컨텐츠를 적합한 사용 표준하에 사용하는


 더 자세히 알아보시려면 구글에 검색해주세요.



그럼 파이썬으로 기상청에서 과거 기상정보를

크롤링하는 예제를 보겠습니다.


먼저 기상청 홈페이지 과거 기상정보 페이지로 가봅니다.


http://www.kma.go.kr/weather/climate/past_cal.jsp?stn=108&yy=2010&mm=1&obs=1&x=21&y=8



과거 기온자료입니다. 페이지 소스를 보시면 오른쪽 tbody 부분 안의 빨간 테두리 표시부분이 기온달력의 한 행입니다.

가장위(빨간테두리) tr 이 1일,2일 부분의 빨간테두리 부분입니다.


tbody 안의 초록테두리 tr 은 1일,2일의 기온부분입니다.


우리는 이 tbody 부분이 일별 기온을 알 수 있는 부분이란것을 알게되었고, 이부분을 크롤링 해오면 된다는걸 알게되었습니다.

(년도와 월은 페이지 url 에 있습니다.)


그럼 이제 파이썬프로젝트를 하나 생성합니다.



1. requests, BeautifulSoup import 받기

파이선 프로젝트를 생성하였으면 requests 와 BeaurifulSoup를 import 받습니다.


calendar 는 오늘날짜를 구하기위해 import 받습니다.


requests와 BeaurifulSoup는 웹페이지를 크롤링하고 파싱하는데 필요합니다.

import requests
import calendar
import datetime
from bs4 import BeautifulSoup



2.현재 날짜 구하기

오늘날짜를 구하여 2011년부터 오늘까지 크롤링을 하도록 설정하기 위해 오늘날자를 구합니다. 

data = []
now = datetime.datetime.now()
nowyear = now.strftime('%Y')
nowmonth = now.strftime('%m')


3.for문을 돌며 크롤링을 실행합니다.

for y in range(2011,2018):
    print('y : '+str(y) + 'year : ' + str(nowyear))
    if str(y)==str(nowyear):
        monthrange = int(nowmonth)+1
    else:
        monthrange = 13
        
    for m in range(1,monthrange):
        response = requests.get('http://www.kma.go.kr/weather/climate/past_cal.jsp?stn=108&yy='+str(y)+'&mm='+str(m)+'&obs=1')
        soup = BeautifulSoup(response.content, 'html.parser')
        table = soup.find('table', {'class': 'table_develop'})  

        count = 0
        point = [''] * 7
        pointt = [''] * 7
        fstr = [''] * 7
        tstr = [''] * 7
        mstr = [''] * 7
        estr = [''] * 7
        temp = [''] * 7
        temptop = [''] * 7
        tempmin = [''] * 7
        rain = [''] * 7
        
        for tr in table.find_all('tr'):
            tds = list(tr.find_all('td'))
    
            if tds:
                for i in range(0,7):
                    point[i] = tds[i].text
        
                if count%2!=0:
                    for j in range(0,7):
                        pointt[j] = point[j].translate({ord('일'):''})
            
                if count%2==0:
                    for k in range(0,7):
                        fstr[k] = point[k].find('최고기온')
                        tstr[k] = point[k].find('최저기온')
                        mstr[k] = point[k].find('평균운량')
                        estr[k] = point[k].find('일강수량')
                        temp[k] = point[k][5:fstr[k]].translate({ord('℃'):''})
                        temptop[k] = point[k][fstr[k]+5:tstr[k]].translate({ord('℃'):''})
                        tempmin[k] = point[k][tstr[k]+5:mstr[k]].translate({ord('℃'):''})
                        rain[k] = point[k][estr[k]+5:].translate({ord(' '):'',ord('-'):'0.0',ord('m'):''})
                
                    if pointt[0]=='\xa0' or temp[0]=='':
                        sun = ""
                    else:
                        sun = str(y)+'-'+str(m)+'-'+pointt[0]+' '+temp[0]+' '+temptop[0]+' '+tempmin[0]+' '+rain[0]
                        data.append([sun])
            
                    if pointt[1]=='\xa0' or temp[1]=='':
                        mon = ""
                    else:
                        mon = str(y)+'-'+str(m)+'-'+pointt[1]+' '+temp[1]+' '+temptop[1]+' '+tempmin[1]+' '+rain[1]
                        data.append([mon])
            
                    if pointt[2]=='\xa0' or temp[2]=='':
                        tue = ""
                    else:
                        tue = str(y)+'-'+str(m)+'-'+pointt[2]+' '+temp[2]+' '+temptop[2]+' '+tempmin[2]+' '+rain[2]
                        data.append([tue])
            
                    if pointt[3]=='\xa0' or temp[3]=='':
                        wed = ""
                    else:
                        wed = str(y)+'-'+str(m)+'-'+pointt[3]+' '+temp[3]+' '+temptop[3]+' '+tempmin[3]+' '+rain[3]
                        data.append([wed])
            
                    if pointt[4]=='\xa0' or temp[4]=='':
                        thu = ""
                    else:
                        thu = str(y)+'-'+str(m)+'-'+pointt[4]+' '+temp[4]+' '+temptop[4]+' '+tempmin[4]+' '+rain[4]
                        data.append([thu])
            
                    if pointt[5]=='\xa0' or temp[5]=='':
                        fri = ""
                    else:
                        fri = str(y)+'-'+str(m)+'-'+pointt[5]+' '+temp[5]+' '+temptop[5]+' '+tempmin[5]+' '+rain[5]
                        data.append([fri])
            
                    if pointt[6]=='\xa0' or temp[6]=='':
                        sat = ""
                    else:
                        sat = str(y)+'-'+str(m)+'-'+pointt[6]+' '+temp[6]+' '+temptop[6]+' '+tempmin[6]+' '+rain[6]
                        data.append([sat])
            
                    print(sun)
                    print(mon)
                    print(tue)
                    print(wed)
                    print(thu)
                    print(fri)
                    print(sat)
            count+=1


1. 2011년부터 2018년(for y in range(2011,2018)) 까지 돌기위해 for문을 만듭니다.


2. if문으로 가 올해이면 monthrange(1~13(일년은 12개월)) monthrange를 현재 월으로 설정합니다(올해는 현재월까지만 클롤링)


3. monthrange 를 돌며 본격적인 크롤링을 실행합니다. response 에 크롤링할 웹사이트를 get하여 얻어옵니다(url 에 년과 월을 넣어야하기때문에 for문이 돌때마다 증가합니다)


4. BeaurifulSoup 로 html파싱을합니다


5. html 태그를 찾아 파싱합니다.



4. 크롤링한 데이터를 txt 파일로 만듭니다.

크롤링한 데이터를 txt파일로 만드는 작업을 합니다.


for문을 돌며 data를 txt파일로 만듭니다.

with open('./weather/weather.txt', 'w') as file:
    for i in data:
        file.write('{0}\n'.format(i[0]))



간단한 기상청 과거 기상 크롤링을 해보았습니다. 막코딩이라 코드가 지저분합니다 ㅜㅜ 참고용으로만 사용해주세요