How We Coding

동영상 강의 : http://pythonkim.tistory.com/notice/77


Day_02_03_kma.py


- import requests 에서 requests 는 외부 모듈.


- PyCharm 에서 외부 모듈 추가하기.


>>  preferences (Mac) - Project - Project Interpreter - "+ 버튼" 클릭 - "requests" 검색 - Install Package 


1
2
3
4
5
6
import requests
import re
 
url = 'http://www.naver.com'
recvd = requests.get(url)
print(recvd)    # <Response [200]>
cs



>> www.naver.com 으로부터 데이터를 성공적으로 가져온 상태. (200)



1
print(recvd.text)
cs


>> Chrome 에서 페이지 소스보기 통해 확인할 수 있는 html 소스가 출력된다.



### 기상청의 전국 날씨정보 파싱


http://www.kma.go.kr/index.jsp 에서 날씨누리 바로가기 - 생활과 산업 - 서비스 - RSS 로 이동




 RSS란?


 RSS(Really Simple Syndication, Rich Site Summary)란 블로그처럼 컨텐츠 업데이트가   

 자주 일어나는 웹사이트에서, 업데이트된 정보를 쉽게 구독자들에게 제공하기 위해 XML을 

 기초로 만들어진 데이터 형식입니다. RSS서비스를 이용하면 업데이트된 정보를 찾기 위해 

 홈페이지에 일일이 방문하지 않아도 업데이트 될 때마다 빠르고 편리하게 확인할 수 

 있습니다. 





- 전국의 중기예보 RSS 클릭 후 URL 클립보드에 복사.


1
2
3
4
url = 'http://www.weather.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=108'
recvd = requests.get(url)
print(recvd)    # <Response [200]>
print(recvd.text)
cs


>> 크롤링 이라고 한다. (python 이 편리한 이유)



-


This XML file does not appear to have any style information associated with it. The document tree is shown below.


>> html 은 style 정보가 포함되어 있다.

>> xml 은 순수하게 데이터만 들어가있다.

>> 데이터 전송 포맷의 두가지 (xml, json)


http://www.weather.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=108 에서 날씨 데이터 찾아보기.


>> <item> - <description> - <body> 안에서 확인가능


>> xml 이든 html 이든 여는태그가 있으면 닫는태그가 있다...!!


1
2
3
4
5
6
url = 'http://www.weather.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=108'
recvd = requests.get(url)
 
tmp = re.findall(r'<province>서울ㆍ인천ㆍ경기도</province>', recvd.text)
print(tmp)  # ['<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>']
print(len(tmp)) # 4
cs



- 모든 <province> 태그 가져오기 (정규표현식 이용)


1
2
3
prov = re.findall(r'<province>.+</province>', recvd.text)
print(prov) # ['<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>', '<province>서울ㆍ인천ㆍ경기도</province>', '<province>강원도영서</province>', '<province>강원도영서</province>', '<province>강원도영동</province>', '<province>대전ㆍ세종ㆍ충청남도</province>', '<province>대전ㆍ세종ㆍ충청남도</province>', '<province>대전ㆍ세종ㆍ충청남도</province>', '<province>충청북도</province>', '<province>광주ㆍ전라남도</province>', '<province>광주ㆍ전라남도</province>', '<province>광주ㆍ전라남도</province>', '<province>전라북도</province>', '<province>전라북도</province>', '<province>부산ㆍ울산ㆍ경상남도</province>', '<province>부산ㆍ울산ㆍ경상남도</province>', '<province>부산ㆍ울산ㆍ경상남도</province>', '<province>대구ㆍ경상북도</province>', '<province>대구ㆍ경상북도</province>', '<province>대구ㆍ경상북도</province>', '<province>제주도</province>', '<province>제주도</province>']
print(len(prov))    # 24
cs



>> <province>.+</province> 패턴은 

     <province> 로 시작하고 하나 이상의 문자가 있고, </province> 로 끝나는 패턴



# 문제

# 전체 location 가져오기


- 상위 데이터를 가져온 다음, 하위 데이터를 분리하는 방식으로 진행해야 한다.!!

- 태그를 타이핑 하지 말고 긁어오쟈 (블럭지정 후 복붙)


1
2
location = re.findall(r'<location wl_ver="3">.+</location>', recvd.text)
print(len(location))
cs


>> 실행 결과는 0 이다.

>> 위의 예제의 경우 여는 태그와 닫는 태그 사이에 한줄에 하나의 데이터만 있지만, 이 예제의 경우 데이터가 여러줄에 걸쳐서 존재한다.

>> 옵션을 추가해서 해결할 수 있다.


1
2
location = re.findall(r'<location wl_ver="3">.+</location>', recvd.text, re.DOTALL)
print(len(location))
cs


>> re.DOTALL 옵션 추가. 내가 찾고자 하는 패턴이 여러줄에 걸쳐있을 때 사용. 

>> 정확히는 개행 문자를 무시해준다.

>> 하지만 실행결과는 1.

>> 가장 짧은 패턴과, 가장 긴 패턴 중 가장 긴 패턴을 디폴트로 찾는다. (Greedy 방식)



>> 데이터가 위와 같이 있는 경우, 첫번째 한줄이 가장 짧은 패턴, 모든 줄을 포함 시킨 것이 가장 긴 패턴이 된다.



- non-greedy 방식으로 하려면 '?' 하나를 추가하면 된다.


1
2
locations = re.findall(r'<location wl_ver="3">.+?</location>', recvd.text, re.DOTALL)
print(len(locations))
cs


>> .+? 라고 적음. ? 는 작은 녀석을 먼저 찾았을 때 멈추게 한다.

>> 실행결과는 24


- 이젠 24개의 데이터에서 원하는 데이터를 다시 또 찾으면 된다.


1
2
3
def printLoc():
    for loc in locations:
        print(loc)
cs


>> 24개의 location 확인 가능



# 문제

# province 를 찾아서 출력 


1
2
3
4
def printProvince():
    for loc in locations:
        prov = re.findall(r'<province>.+</province>', loc)
        print(prov)
cs


>> 24 개의 <province> 데이터를 출력한다.

>> 한줄안에 있으므로 re.DOTALL 없어도 된다.


>> 실행결과


['<province>서울ㆍ인천ㆍ경기도</province>']

['<province>서울ㆍ인천ㆍ경기도</province>']

['<province>서울ㆍ인천ㆍ경기도</province>']

['<province>서울ㆍ인천ㆍ경기도</province>']

['<province>강원도영서</province>']

['<province>강원도영서</province>']

['<province>강원도영동</province>']

['<province>대전ㆍ세종ㆍ충청남도</province>']

['<province>대전ㆍ세종ㆍ충청남도</province>']

['<province>대전ㆍ세종ㆍ충청남도</province>']

['<province>충청북도</province>']

['<province>광주ㆍ전라남도</province>']

['<province>광주ㆍ전라남도</province>']

['<province>광주ㆍ전라남도</province>']

['<province>전라북도</province>']

['<province>전라북도</province>']

['<province>부산ㆍ울산ㆍ경상남도</province>']

['<province>부산ㆍ울산ㆍ경상남도</province>']

['<province>부산ㆍ울산ㆍ경상남도</province>']

['<province>대구ㆍ경상북도</province>']

['<province>대구ㆍ경상북도</province>']

['<province>대구ㆍ경상북도</province>']

['<province>제주도</province>']

['<province>제주도</province>']



>> 여기서 우리가 필요한 것은 <province> 태그 안의 데이터이므로 , 태그 이름까지는 없어도 된다..!!


1
2
3
4
def printProvinceData():
    for loc in locations:
        prov = re.findall(r'<province>(.+)</province>', loc)
        print(prov)
cs


>> 괄호를 치면 된다.!!

>> 실행결과 


['서울ㆍ인천ㆍ경기도']

['서울ㆍ인천ㆍ경기도']

['서울ㆍ인천ㆍ경기도']

['서울ㆍ인천ㆍ경기도']

['강원도영서']

['강원도영서']

['강원도영동']

['대전ㆍ세종ㆍ충청남도']

['대전ㆍ세종ㆍ충청남도']

['대전ㆍ세종ㆍ충청남도']

['충청북도']

['광주ㆍ전라남도']

['광주ㆍ전라남도']

['광주ㆍ전라남도']

['전라북도']

['전라북도']

['부산ㆍ울산ㆍ경상남도']

['부산ㆍ울산ㆍ경상남도']

['부산ㆍ울산ㆍ경상남도']

['대구ㆍ경상북도']

['대구ㆍ경상북도']

['대구ㆍ경상북도']

['제주도']

['제주도']




# Data 찾기


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
32
33
34
# Data 찾기
 
def findData():
    for loc in locations:
        prov = re.findall(r'<province>(.+)</province>', loc)
        city = re.findall(r'<city>(.+)</city>', loc)
        data = re.findall(r'<data>(.+)</data>', loc, re.DOTALL)
 
        #print(prov[0], prov)
        #print(city[0])
        # print(data)
        # print(len(data))    # 1
 
        for datum in data:
            # print(datum)
 
            # 문제
            # mode 를 비롯한 나머지를 찾아보기
            mode = re.findall(r'<mode>(.+?)</mode>', datum)
            tmEf = re.findall(r'<tmEf>(.+?)</tmEf>', datum)
            wf   = re.findall(r'<wf>(.+?)</wf>', datum)
            tmn  = re.findall(r'<tmn>(.+?)</tmn>', datum)
            tmx  = re.findall(r'<tmx>(.+?)</tmx>', datum)
            reli = re.findall(r'<reliability>(.+?)</reliability>', datum)
            # print(prov[0], city[0], mode[0], tmEf[0], wf[0], tmn[0], tmx[0], reli[0])
 
            row = '{}, {}, {}, {}, {}, {}, {}, {}'.format(prov[0], city[0], mode[0], tmEf[0], wf[0], tmn[0], tmx[0], reli[0])
            print(row)
 
 
findData()
 
 
 
cs


>> datum 하나의 출력 결과


<data>

<mode>A01</mode>

<tmEf>2018-03-02 00:00</tmEf>

<wf>구름많음</wf>

<tmn>6</tmn>

<tmx>13</tmx>

<reliability>보통</reliability>

</data>



>> 25 : print(prov[0], city[0], mode[0], tmEf[0], wf[0], tmn[0], tmx[0], reli[0]) 의 결과


서울ㆍ인천ㆍ경기도 서울 A02 2018-02-24 00:00 구름조금 -2 7 높음

서울ㆍ인천ㆍ경기도 인천 A02 2018-02-24 00:00 구름조금 -2 5 높음

서울ㆍ인천ㆍ경기도 수원 A02 2018-02-24 00:00 구름조금 -3 7 높음

서울ㆍ인천ㆍ경기도 파주 A02 2018-02-24 00:00 구름조금 -7 6 높음

강원도영서 춘천 A02 2018-02-24 00:00 구름조금 -5 6 보통

강원도영서 원주 A02 2018-02-24 00:00 구름조금 -4 6 보통

강원도영동 강릉 A02 2018-02-24 00:00 구름조금 -1 7 보통

대전ㆍ세종ㆍ충청남도 대전 A02 2018-02-24 00:00 구름조금 -4 8 보통

대전ㆍ세종ㆍ충청남도 세종 A02 2018-02-24 00:00 구름조금 -5 7 보통

대전ㆍ세종ㆍ충청남도 홍성 A02 2018-02-24 00:00 구름조금 -4 7 보통

충청북도 청주 A02 2018-02-24 00:00 구름조금 -3 8 보통

광주ㆍ전라남도 광주 A02 2018-02-24 00:00 구름조금 0 12 보통

광주ㆍ전라남도 목포 A02 2018-02-24 00:00 구름조금 1 10 보통

광주ㆍ전라남도 여수 A02 2018-02-24 00:00 구름조금 3 12 보통

전라북도 전주 A02 2018-02-24 00:00 구름조금 -2 9 보통

전라북도 군산 A02 2018-02-24 00:00 구름조금 -3 7 보통

부산ㆍ울산ㆍ경상남도 부산 A02 2018-02-24 00:00 구름조금 3 12 보통

부산ㆍ울산ㆍ경상남도 울산 A02 2018-02-24 00:00 구름조금 0 11 보통

부산ㆍ울산ㆍ경상남도 창원 A02 2018-02-24 00:00 구름조금 1 12 보통

대구ㆍ경상북도 대구 A02 2018-02-24 00:00 구름조금 -1 12 보통

대구ㆍ경상북도 안동 A02 2018-02-24 00:00 구름조금 -3 10 보통

대구ㆍ경상북도 포항 A02 2018-02-24 00:00 구름조금 1 11 보통

제주도 제주 A02 2018-02-24 00:00 구름조금 5 12 보통

제주도 서귀포 A02 2018-02-24 00:00 구름조금 7 13 보통



>> 27 : 데이터를 재사용하기 위해 row 및 문자열 포맷 사용.

>> 데이터와 데이터 사이에 콤마로 구분. comma separated // CSV 



- 이런식으로도 할 수 있다.


1
2
items = re.findall(r'<mode>(.+?)</mode>.+<tmEf>(.+?)</tmEf>.+<wf>(.+?)</wf>', datum, re.DOTALL)
print(items)
cs


>> 태그와 태그 사이에 .+ 추가. re.DOTALL 옵션 추가.

>> 실행결과 (리스트 안의 튜플로 된 구조이다.)


[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름조금')]

[('A02', '2018-03-03 00:00', '구름많음')]

[('A02', '2018-03-03 00:00', '구름많음')]


-  

1
2
= items[0]
print(t[0], t[1], t[2])
cs


>> item 은 리스트

>> items[0] 은 튜플





1
2
3
4
5
6
7
8
def findLoc():
    for loc in locations:
        items = re.findall(r'<mode>(.+?)</mode>.+?<tmEf>(.+?)</tmEf>.+?<wf>(.+?)</wf>', loc, re.DOTALL)
        print(items)
        print(len(items))
 
 
findLoc()
cs


>> 태그와 태그 사이 .+ 가 아닌 .+? 이다!!

>> 실행결과의 일부


[('A02', '2018-02-24 00:00', '구름조금'), ('A02', '2018-02-24 12:00', '구름많음'), ('A02', '2018-02-25 00:00', '구름많음'), ('A02', '2018-02-25 12:00', '구름많음'), ('A02', '2018-02-26 00:00', '구름조금'), ('A02', '2018-02-26 12:00', '구름조금'), ('A02', '2018-02-27 00:00', '구름많음'), ('A02', '2018-02-27 12:00', '구름많음'), ('A02', '2018-02-28 00:00', '구름많음'), ('A02', '2018-02-28 12:00', '구름많음'), ('A01', '2018-03-01 00:00', '구름조금'), ('A01', '2018-03-02 00:00', '구름조금'), ('A01', '2018-03-03 00:00', '구름조금')]

13

[('A02', '2018-02-24 00:00', '구름조금'), ('A02', '2018-02-24 12:00', '구름많음'), ('A02', '2018-02-25 00:00', '구름많음'), ('A02', '2018-02-25 12:00', '구름많음'), ('A02', '2018-02-26 00:00', '구름조금'), ('A02', '2018-02-26 12:00', '구름조금'), ('A02', '2018-02-27 00:00', '구름많음'), ('A02', '2018-02-27 12:00', '구름많음'), ('A02', '2018-02-28 00:00', '구름많음'), ('A02', '2018-02-28 12:00', '구름많음'), ('A01', '2018-03-01 00:00', '구름조금'), ('A01', '2018-03-02 00:00', '구름조금'), ('A01', '2018-03-03 00:00', '구름조금')]

13

[('A02', '2018-02-24 00:00', '구름조금'), ('A02', '2018-02-24 12:00', '구름많음'), ('A02', '2018-02-25 00:00', '구름많음'), ('A02', '2018-02-25 12:00', '구름많음'), ('A02', '2018-02-26 00:00', '구름조금'), ('A02', '2018-02-26 12:00', '구름조금'), ('A02', '2018-02-27 00:00', '구름많음'), ('A02', '2018-02-27 12:00', '구름많음'), ('A02', '2018-02-28 00:00', '구름많음'), ('A02', '2018-02-28 12:00', '구름많음'), ('A01', '2018-03-01 00:00', '구름조금'), ('A01', '2018-03-02 00:00', '구름조금'), ('A01', '2018-03-03 00:00', '구름조금')]

13

[('A02', '2018-02-24 00:00', '구름조금'), ('A02', '2018-02-24 12:00', '구름많음'), ('A02', '2018-02-25 00:00', '구름많음'), ('A02', '2018-02-25 12:00', '구름많음'), ('A02', '2018-02-26 00:00', '구름조금'), ('A02', '2018-02-26 12:00', '구름조금'), ('A02', '2018-02-27 00:00', '구름많음'), ('A02', '2018-02-27 12:00', '구름많음'), ('A02', '2018-02-28 00:00', '구름많음'), ('A02', '2018-02-28 12:00', '구름많음'), ('A01', '2018-03-01 00:00', '구름조금'), ('A01', '2018-03-02 00:00', '구름조금'), ('A01', '2018-03-03 00:00', '구름조금')]

13

[('A02', '2018-02-24 00:00', '구름조금'), ('A02', '2018-02-24 12:00', '구름많음'), ('A02', '2018-02-25 00:00', '구름많음'), ('A02', '2018-02-25 12:00', '구름많음'), ('A02', '2018-02-26 00:00', '구름조금'), ('A02', '2018-02-26 12:00', '구름조금'), ('A02', '2018-02-27 00:00', '구름많음'), ('A02', '2018-02-27 12:00', '구름많음'), ('A02', '2018-02-28 00:00', '구름많음'), ('A02', '2018-02-28 12:00', '구름많음'), ('A01', '2018-03-01 00:00', '구름조금'), ('A01', '2018-03-02 00:00', '구름조금'), ('A01', '2018-03-03 00:00', '구름조금')]

13



1
2
3
4
5
6
7
8
9
10
11
def findLoc():
    for loc in locations:
        items = re.findall(r'<mode>(.+?)</mode>.+?<tmEf>(.+?)</tmEf>.+?<wf>(.+?)</wf>', loc, re.DOTALL)
        # print(items)
        # print(len(items))
 
        for item in items:
            print(item)
 
 
findLoc()
cs


>> 실행결과의 일부


('A02', '2018-02-28 12:00', '구름많고 비')

('A01', '2018-03-01 00:00', '구름많음')

('A01', '2018-03-02 00:00', '구름많음')

('A01', '2018-03-03 00:00', '구름많음')



1
2
for mode, tmEf, wf in items:
    print(mode, tmEf, wf)
cs


>> 이런식으로도 가능하다.



1
2
3
4
5
6
7
8
9
def findLoc2():
    for loc in locations:
        items = re.findall(r'<mode>(.+?)<.+?>.+?<.+?>(.+?)<.+?>.+?<.+?>(.+?)<.+?>', loc, re.DOTALL)
 
        for mode, tmEf, wf in items:
            print(mode, tmEf, wf)
 
 
findLoc2()
cs


>> 이런식으로도 가능하다.

>> 맨 앞에 <mode> 를 남긴 이유는 그 상위 데이터가 더 존재하므로...




'Language > Python' 카테고리의 다른 글

<3-2> Set 과 Dictionary  (0) 2018.03.02
<3-1> 파일 입출력  (0) 2018.02.23
<2-2> 리스트, 튜플  (0) 2018.02.15
<2-1> 제어문과 반복문의 연결고리  (0) 2018.02.06
<1-7> 정규표현식 with Python  (0) 2018.02.03