#!/usr/bin/env python # coding: utf-8 # # **Menu List Crawling** # ## **1 청심중고교 메뉴 데이터 호출** # 무영 메뉴작업 목록 호출하기 # ```python # from muyong.food import menu_chungsim # from tqdm import tqdm # date = [str(_).split(" ")[0][:-3] for _ in pd.date_range(start='1/1/2017', end="8/1/2019", freq='MS')] # result = [menu_chungsim(_).values.tolist() for _ in tqdm(date)] # temp = [] # for _ in result: # temp.extend(_) # temp = pd.DataFrame(temp, columns = ["Date", "조식", "중식", "석식"]) # ``` # In[1]: # 2017-01-01 부터 수집 가능합니다. import pandas as pd df = pd.read_csv('data/menu_chungsim.csv') df.head(2) # ## **2 성균관 대학교 메뉴 데이터 호출** # 무영 메뉴작업 목록 호출하기 : 1년 전까지만 호출가능 # ```python # div class="weekly_list" # div class="tabCon listcon1" # div class="weeListWrap" # div class="weeListTit" : 날짜만 추출시 # idx_date_range = [_.date().strftime("%Y-%m-%d") # for _ in pd.date_range(start=idx_date, periods=len(menu_detail))] # ``` #

# # **10,000 개의 레시피 메뉴 함수** # 개별 작업을 구분한 뒤, 모듈로써 작업을 진행하도록 합니다 # 1. **크롤링용** 함수 # 1. 원본과 **비교용** 함수 # 1. **비교 후 합치는** 함수 # # ## **1 작업용 함수 만들기** # 크롤링 및 주소값을 활요한 filtering # In[1]: # "<제목>" 추출시 lxml 로는 안되더라 왜???? import requests, re from bs4 import BeautifulSoup def crawMenuBs4(url_no): url = "http://www.10000recipe.com/recipe/list.html?order=date&page=" userAgent = {"user-agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"} result, resp = [], requests.request('get', url+str(url_no), headers=userAgent, timeout=5) dom = BeautifulSoup(resp.text, "html.parser") titles = dom.find_all("h4", {"class":"ellipsis_title2"}) titles = [_.text for _ in titles] for _ in dom.find_all("div", {"class":"col-xs-4"}): try: url_href = _.find("a", {"class":"thumbnail"})["href"] _title = _.find("h4", {"class":"ellipsis_title2"}).text result.append([url_href, _title]) except: pass return result # 특정 페이지 링크데이터 목록 수집하기 menuList = crawMenuBs4(17) menuList[:3] # In[1]: # 파일을 기준으로 결과물 필터링 import pandas as pd def crawFileFilter(menuList, files): df = pd.read_csv(files, header=None) limitOrg = int(re.findall(r"\d+", df[0][0])[0]) mTemp = pd.DataFrame(menuList) mTemp[0] = [int(re.findall(r"\d+", _)[0]) for _ in mTemp[0]] mTemp = mTemp[mTemp[0] > limitOrg] mTemp[0] = ["/recipe/"+str(_) for _ in mTemp[0]] # 필터링 결과 url return mTemp.values.tolist() # In[103]: # Web Page 수집함수 import requests from lxml.html import fromstring def crawData(url_menu): url = "http://www.10000recipe.com/recipe/list.html?order=accuracy&page=" url = "http://www.10000recipe.com/recipe/" userAgent = {"user-agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"} xpath_rcp = '//div[@id="contents_area"]//div[starts-with(@class,"cont_ingre")]//text()' xpath_c = '//div[@id="contents_area"]/div[@class="view_step"]/div[starts-with(@id,"stepDiv")]//text()' xpath_cOld = '//div[@id="contents_area"]/div[@class="view_step"]/div[@id="oldContArea"]//text()' xpath_tip = '//div[@id="contents_area"]/div[@class="view_step"]//dl[@class="view_step_tip"]//text()' xpath_name = '//div[@id="contents_area"]/div[@class="view2_summary"]/h3/text()' urlDetail = requests.compat.urljoin(url, url_menu) # urlDetail = url + str(url_menu) resp = requests.request('get', urlDetail, headers=userAgent, timeout=5) resp_lxml = fromstring(resp.text) try: name = resp_lxml.xpath(xpath_name) # 레시피 데이터 name = " ".join([_.strip() for _ in name if len(_.strip())>1]) recipe = resp_lxml.xpath(xpath_rcp) # 레시피 데이터 recipe = " ".join([_.strip() for _ in recipe if len(_.strip())>1]) cooking = resp_lxml.xpath(xpath_c) # 조리법 크롤링 cooking = " ".join([_.strip() for _ in cooking if len(_.strip())>1]) if len(cooking) < 5: # 조리법 크롤링 (old style) cooking = resp_lxml.xpath(xpath_cOld) cooking = " ".join([_.strip() for _ in cooking if len(_.strip())>1]) cookTip = resp_lxml.xpath(xpath_tip) cookTip = " ".join([_.strip() for _ in cookTip if len(_.strip())>1]) if len(cookTip) < 3: cookTip="None" # url 은 레시피 Url 숫자 저장 (압축) url_menu = int("".join(re.findall(r'\d+', url_menu))) return [url_menu, name, recipe, cooking, cookTip] except: return None # ## **2 레시피 데이터 전처리** # 작업한 내용 살펴보기 # In[11]: # import pandas as pd # recipes = pd.read_csv('data/foodRecipe.csv', sep="|", header=None) # recipes[0] = [int(_) for _ in recipes[0]] # 문자열 대신 숫자로 모두 변환 # # 중복 컬럼 줄이기 : 6917054, 6917053, 6917052, 6917051, 6917050, 6917049 # from tqdm import tqdm # result, recipesNo = [], sorted(set(recipes[0]), reverse=True) # for _ in tqdm(recipesNo): # result.append(recipes[recipes[0] == _].iloc[0,:].values.tolist()) # recipes = pd.DataFrame(result) # recipes.to_csv('recipe.csv', index=None, header=None, sep="|") # recipes.head(2) #

# # **Naver 자료 수집하기** # Naver 자료들 수집하기 # # ## **1 네이버 블로그 내용 수집하기** # 블로그 URL 에서 본문을 수집 분석하기 # In[2]: # iframe 으로 본문 url 찾은 뒤, //div[@id="postListBody"] 내용의 출력 import requests from lxml.html import fromstring def get_blog_post(url): userAgent = {"user-agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0"} rsp = requests.get(url, headers=userAgent) rsp_lxml = fromstring(rsp.text) # './/태그[contains(@속성명, "속성값")]' text_result = rsp_lxml.xpath('.//iframe[@id="mainFrame"]/@src') get_url = "https://blog.naver.com" + text_result[0] resp = requests.get(get_url) resp_lxml = fromstring(resp.text) blog_xpath = '//div[@id="postListBody"]//table//text()' return " ".join([_.strip() for _ in resp_lxml.xpath(blog_xpath) if _.strip()]) url = "https://blog.naver.com/k77609/221366368354" url = 'https://blog.naver.com/0167513714/221616708943' url = 'https://blog.naver.com/hnn888/221411518781' blog_text = get_blog_post(url) blog_text[:250] # In[4]: from konlpy.tag import Mecab, Okt blog_text tokens = [_[0]+"/"+_[1] for _ in Mecab().pos(blog_text)] # , stem=True from nltk import Text token_blog = Text(tokens) # [list] 객체로 Text 객체의 생성 # In[5]: get_ipython().run_line_magic('matplotlib', 'inline') from matplotlib import rc, rcParams import matplotlib.pyplot as plt rc('font', family=['UbuntuMono-R', 'D2Coding']) # 한글의 표시 rcParams['axes.unicode_minus'] = False # '-' 표시의 처리 plt.figure(figsize=(15, 3)) # 파레트 설정 token_blog.plot(50) # # **Naver Post Detail Crawling** # 메뉴의 이름들 중 대표성 높은 메뉴들 찾기 # # ## **1 네이버 블로그 내용 수집하기** # 블로그 URL 에서 본문을 수집 분석하기 # 1. Naver OPEN API 결과 **Token 이 유효값인지** 확인 가능했다 (Oh!!) # 1. 네이버 블로그 목록만 정리한 DataBase 만들기 # 1. 목록을 4개로 나워서 2개의 서버에서 돌리며 저장하기 # In[4]: import re # 수집결과 불필요한 기호들 제거하는 함수 def blog_preprocess(post): post_temp = post.replace('\n',"").replace('\t',"").split(".") post_temp = [" ".join(re.findall(r"[가-힣0-9A-z]+", _)) for _ in post_temp if len(_.strip()) >= 1] return ".".join(post_temp) # In[2]: # import pandas as pd # links_org = pd.read_csv('backup/naver_link_temp.csv') # # links_org.shape, links_org.head(3) # links_by_token = links_org.iloc[::60, :] # 길이를 절반으로 축소 # links_by_token = links_by_token.data.values.tolist() # len(links_by_token), links_by_token[0][:40] # In[3]: # import sqlite3, time, os, requests_cache # file_db = "naver.db" # conn = sqlite3.connect(file_db) # requests_cache.install_cache('cache') # import pandas as pd # from tqdm import tqdm # from muyong.util import Telegram # from muyong.naver import get_blog_post # t = Telegram() # links_length = len(links_by_token) # for no, links in tqdm(enumerate(links_by_token)): # result, temp = [], [] # links = links.split('|') # for _ in links[:100]: # _ = get_blog_post(_) # _ = blog_preprocess(_) # temp.append(_) # time.sleep(.1) # temp = "|".join(temp) # 500개를 저장 # result.append([no, temp]) # df = pd.DataFrame(result) # df.to_sql('foods', conn, if_exists='append') # os.remove("cache.sqlite") # if no % 200 == 0: # t.msg("{}/ {} th processing".format(no, links_length)) # time.sleep(.1) # conn.commit() # conn.close() # ## **2 수집결과 살펴보기** # Sqlite 결과를 보다 활용하기 쉽게 저장하기 # In[1]: # import sqlite3 # import pandas as pd # conn = sqlite3.connect("naver.db") # df = pd.read_sql('SELECT * FROM "foods"', conn, index_col=None).drop('index', axis=1) # conn.close() # df = df.iloc[11:].reset_index(drop=True) # df.columns = ['Query', 'Posts'] # df.Query = links_org.iloc[::60, 0].tolist() # df.head() # df.to_csv("data/naver_posts_sample.csv", index=None) # df.Query.tolist()