#!/usr/bin/env python # coding: utf-8 # # **Url Encoding / Parsing** # 출처: https://dololak.tistory.com/255 [코끼리를 냉장고에 넣는 방법] # # **urllib 모듈을 사용한 경로명 작업** # # ## **1 Url Encoding** # **한글 쿼리문의 인코딩** 해결 및 **Url Query** 생성 및 경로 연결 # 1. parse.**quote_plus** ("%B8%D3%BD%C5%B7%AF%B4%D7") # 1. parse.**unquote_plus** ("파이썬", encoding='euc-kr') # In[1]: # 한글 인코딩/ 디코딩 문법 from urllib import parse temp = "%B8%D3%BD%C5%B7%AF%B4%D7" parse.unquote_plus(temp, encoding='euc-kr') # In[2]: parse.quote_plus("머신러닝", encoding='euc-kr') # In[7]: # Base url 추출 및 추가경로 붙이기 from urllib import parse url_root = "https://www.kamis.or.kr/test/join" url_base = parse.urljoin(url_root, '/customer/price/retail/item.do?action=priceinfo') url_base # In[5]: query = { 'examParam1' : 'value1', 'examParam2' : ['aaa', 'bbb'], 'Korquery' : "파이" } parse.urlencode(query, encoding='UTF-8', doseq=True) # In[9]: # Param 를 사용하여 Query Url 만들기 query = { "regday":"2019-10-18", "itemcode":"111", "convert_kg_yn":"N", "itemcategorycode":"100", } url_query = parse.urlencode(query, encoding='UTF-8', doseq=True) url_query # In[10]: # Base url 과 Params 연결하기 url = url_base + "&" + url_query url # ## **2 Url Parsing** # 필요한 부분 추출하기 # In[11]: # 긴 Url 경로를 Parsing 하기 url_parse = parse.urlparse(url) url_parse # In[12]: # Root Url 추출하기 (url Net Location) url_parse.netloc # In[13]: # url Add Paths url_parse.path # In[14]: # url Query url_parse.query #
# # # **Urllib 의 Request 크롤링** # **[한국 IT협회 교육내용 정리](https://leechamin.tistory.com/category/IT%20%ED%99%9C%EB%8F%99/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%EA%B5%90%EC%9C%A1%20-%20NLP?page=5)** # ## **1 Request 를 사용한 크롤링** # Urllib 모듈의 **request** 사용 # In[15]: # Python 기본 모듈인 urllib 을 사용하여 Robots.txt 내용 확인하기 from urllib import request url = "https://news.naver.com/robots.txt" resp = request.urlopen(url) resp.read() # 통으로 불러오기 # In[16]: # 상세 페이지 크롤링 url = "https://www.kamis.or.kr/customer/price/retail/item.do?action=priceinfo®day=2019-10-18&itemcode=111&convert_kg_yn=N&itemcategorycode=100" resp = request.urlopen(url) r_test = resp.readlines()[103:107] r_test # ## **2 한글 인코딩** # 1. **Byte Text** 를 **str** 로 변환하고 # 1. **인코딩** 으로 **한글을 복구** 합니다. # In[17]: from urllib import parse txt_byte = parse.quote_plus(r_test[3]) type(txt_byte), txt_byte # In[18]: # 변환된 str 중 인코딩 문제를 해결 parse.unquote_plus(txt_byte) # ## **3 한글의 초성, 중성, 조성 분리** # **[한글의 자음/모음 분해하기](https://frhyme.github.io/python/python_korean_englished/)** # In[1]: """Generate Strings from `c1` to `c2`, inclusive.""" def str_range(c1, c2): for c in range(ord(c1), ord(c2)+1): yield chr(c) str_start = [_ for _ in [c for c in str_range('ㄱ', 'ㅎ')] # 초성 리스트 if _ not in ['ㄳ','ㄵ','ㄶ','ㄺ','ㄻ','ㄼ','ㄽ','ㄾ','ㄿ','ㅀ','ㅄ']] str_mid = [c for c in str_range('ㅏ', 'ㅣ')] # 중성 리스트 str_last = [_ for _ in [" "] + [c for c in str_range('ㄱ', 'ㅎ')] if _ not in ['ㄸ', 'ㅃ', 'ㅉ']] # 종성 리스트 # In[2]: def str_korchar(str_text): r_lst = [] for _ in list(str_text.strip()): if '가' <= _ <= '힣': # 영어는 구분작성 ch1 = (ord(_)-ord('가'))//588 # 588개 마다 초성변경 ch2 = ((ord(_)-ord('가'))-(588*ch1))//28 # 중성은 총 28개 ch3 = (ord(_) - ord('가'))-(588*ch1)-28*ch2 r_lst.append([str_start[ch1], str_mid[ch2], str_last[ch3]]) else: r_lst.append([_]) return r_lst str_korchar("된장찌개 볶음abc") # In[4]: list("깍두기") # In[10]: str_korchar("깍두기") # In[9]: (ord("깍")-ord("가"))//588 #
# # # **Requests 크롤링** # **[Pypi](https://pypi.org/project/requests/) :** ! pip install requests # ## **1 Urllib 의 Parse 를 활용한 경로추출** # 앞에서 작업했던 내용을 활용하여 경로명 만들기 # In[21]: # Base url 경로 url = "https://www.kamis.or.kr/customer/price/retail/item.do?action=priceinfo" from urllib import parse parse.urlsplit(url) # In[22]: params = { "regday" : "2019-10-18", "itemcategorycode" : "100", "itemcode" : "111", "convert_kg_yn" : "N", } query = '&' + parse.urlencode(params, encoding='UTF-8') query # In[23]: url + query # In[24]: import pandas as pd pd.read_html(url + query)[3].head(3) # ## **2 Requests 를 사용한 Get 크롤링** # 1. Url 의 **pararm** 경로와, 가상 **web Header** 인코딩을 자동처리 합니다. # 1. https://pypi.org/project/fake-useragent/ # In[25]: # Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US); # Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.2; SV1; .NET CLR 3.3.69573; WOW64; en-US) # Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2' # Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.13 (KHTML, like Gecko) Chrome/24.0.1290.1 Safari/537.13 # Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1 # Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1 # Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11 # Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25 # In[26]: url = "https://www.kamis.or.kr/customer/price/retail/item.do?action=priceinfo" params = { "regday" : "2019-10-18", "itemcategorycode" : "100", "itemcode" : "111", "convert_kg_yn" : "N", } import requests web = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2' headers = {'User-Agent' : web} resp = requests.get(url, params=params, headers=headers) resp.text[2800:3000] # ## **2 Requests 를 사용한 Post 크롤링** # 1. Url 의 **pararm** 경로와, 가상 **web Header** 인코딩을 자동처리 합니다. # 1. https://pypi.org/project/fake-useragent/ # In[27]: # OTP key 값 추출하기 # KRX 주가 데이터 수집예제 gen_otp_url = 'http://marketdata.krx.co.kr/contents/COM/GenerateOTP.jspx' gen_otp_data = { 'name':'fileDown', 'filetype':'xls', 'market_gubun':'ALL', #시장구분: ALL=전체 'url':'MKD/04/0404/04040200/mkd04040200_01', 'schdate':'20191018', 'pagePath':'/contents/MKD/04/0404/04040200/MKD04040200.jsp' } r = requests.post(gen_otp_url, gen_otp_data) OTP_code = r.content OTP_code # In[28]: data = { "Accept" :"text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8", "Accept-Encoding" : "gzip, deflate, br", "Accept-Language" : "ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3", "Connection" : "keep-alive", "Content-Length" : "76940", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.kamis.or.kr", "Referer" : url + query, "Upgrade-Insecure-Requests" : "1", "User-Agent" : "Mozilla/5.0 (X11; Ubuntu; Linu…) Gecko/20100101 Firefox/69.0" } resp = requests.post("https://www.kamis.or.kr/jsp/common/excel_util.jsp", data=data) resp.content # ## **3 KAMIS 데이터 크롤링** # Get 방식으로 기존의 lxml 모듈로 수집하기 # In[29]: url = "https://www.kamis.or.kr/customer/price/retail/item.do?action=priceinfo" params = { "regday" : "2015-10-14", "itemcategorycode" : "100", "itemcode" : "111", "convert_kg_yn" : "N", } import requests web = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2' headers = {'User-Agent' : web} resp = requests.get(url, params=params, headers=headers) resp # In[30]: from lxml.html import fromstring, tostring resp_lxml = fromstring(resp.text) resp_table = resp_lxml.xpath('//table[@id="itemTable_1"]')[0] import pandas as pd table = pd.read_html(tostring(resp_table))[0] table_idx = [_ for _, txt in enumerate(list(table.columns)) if txt.find('당일') != -1] if len(table_idx) == 1: table_idx = table_idx[0] table = table.iloc[:,[0, table_idx]].set_index( table.columns[0]).loc[["평균","최고값","최저값"]] table = list(table.to_dict(orient='list').values())[0] else: table = None table #
# # # **API Key 를 활용한 크롤링** # # ## **1 식품안전나라 안내 Page** # 1. **[Open API 메인 페이지](https://www.foodsafetykorea.go.kr/api/userApiKey.do#)**, **[API 활용 방법](https://www.foodsafetykorea.go.kr/api/howToUseApi.do?menu_grp=MENU_GRP34&menu_no=687)**, **[API 이용절차](https://www.foodsafetykorea.go.kr/api/board/boardDetail.do)** # # 상세페이지 바로가기 # In[31]: # 조리 레시피 API 안내 페이지 https://www.foodsafetykorea.go.kr/api/openApiInfo.do query = { "menu_no":"849", "menu_grp":"MENU_GRP31", "start_idx":"120", "svc_no":"COOKRCP01", "svc_type_cd":"API_TYPE06", "show_cnt":"10", "Referer":"https://www.foodsafetykorea.go.kr/api/sheetInfo.do", } import requests resp = requests.post("https://www.foodsafetykorea.go.kr/api/openApiInfo.do", data=query) resp # with open("food.html", "w") as f: # f.write(resp.text) # ## **2 API 크롤링** # 1. **[Open API 메인 페이지](https://www.foodsafetykorea.go.kr/api/userApiKey.do#)**, **[API 활용 방법](https://www.foodsafetykorea.go.kr/api/howToUseApi.do?menu_grp=MENU_GRP34&menu_no=687)**, **[API 이용절차](https://www.foodsafetykorea.go.kr/api/board/boardDetail.do)** # 1. key : "8acba1823ae742359560" # # **"keyId"** 부분에 **인증키를** 입력하고, **"serviceId"에는** 미리보기 주소에 있는 **serviceId** 를 사용 # # ex) http://openapi.foodsafetykorea.go.kr/api/인증키/I0580/xml/1/20 # # 1. HACCP 적용업소 지정현황 **'I0580'** 사용 # 1. **'dataType'** 에서 **Xml, Json** 중 타입을 한가지 입력 # 1. **'startIdx'** 에서 **시작 정보 행 순번** (1번부터 : '1') # 1. **'endIdx'** 에서 **마지막 행 순번** (20번까지 : '20') # In[32]: # http://openapi.foodsafetykorea.go.kr/api/keyId/serviceId/dataType/startIdx/endIdx url = "http://openapi.foodsafetykorea.go.kr/api" # sample/I2620/xml/1/5" keyId = "8acba1823ae742359560" serviceId = "I0750" # "I0580" # I0750 dataType = "json" startNum = "1" endNum = "3" url = "/".join([url, keyId, serviceId, dataType, startNum, endNum]) # In[33]: get_ipython().run_cell_magic('time', '', "from urllib import request, parse\nresp = request.urlopen(url)\nresp = parse.quote_plus(resp.read()) # Byte to String\nresp = parse.unquote_plus(resp) # Encoding Text\n\nimport json\nresp = json.loads(resp) # Json 데이터를 Dict 으로 변환\nresp\n# len(resp['I0750']['row'])\n") # In[34]: resp['I0750']['RESULT']['CODE'].lower()#.find("error") # In[35]: resp['I0750']['RESULT']['CODE'].lower().find("error") # In[36]: col_to_kor = { "NUM":"번호", "FOOD_CD":"식품코드", "FDGRP_NM":"식품군", "DESC_KOR":"식품이름", "SERVING_WT":"1회제공량(g)", "NUTR_CONT1":"열량(kcal)(1회제공량당)", "NUTR_CONT2":"탄수화물(g)(1회제공량당)", "NUTR_CONT3":"단백질(g)(1회제공량당)", "NUTR_CONT4":"지방(g)(1회제공량당)", "NUTR_CONT5":"당류(g)(1회제공량당)", "NUTR_CONT6":"나트륨(mg)(1회제공량당)", "NUTR_CONT7":"콜레스테롤(mg)(1회제공량당)", "NUTR_CONT8":"포화지방산(g)(1회제공량당)", "NUTR_CONT9":"트랜스지방(g)(1회제공량당)", "ANIMAL_PLANT":"가공업체명", "BGN_YEAR":"구축년도", "FOOD_GROUP":"자료원", } # In[37]: import pandas as pd df = pd.DataFrame(resp['I0750']['row']) df = df.loc[:,list(col_to_kor.keys())] # header 정렬 df.columns = [col_to_kor[_] for _ in list(df.columns)] # df.to_excel('data/food_nutrient.xls', index=False) df