크롤러
인공지능과 관련해 데이터를 수집할 일들이 생긴다.
인터넷에서 빅 데이터를 수집할 때 API를 제공하지 않는다면 직접 수집해야할 때도 있다.
이 때 정해진 웹 페이지 형식에서 데이터를 수집할 때 사용하는 프로그램을 크롤러 라고 하며, 데이터 수집 과정을 크롤링이라 한다.
beautifulsoup
크롤러 개발에는 여러 라이브러리들이 제공되고 있다.
나는 가장 개발이 빠르고 편하다고 생각하는 python 라이브러리인 beautifulsoup을 통해 개발하도록 하겠다.
크롤링 대상은 네이버 영화다.
2000년대부터 모든 페이지를 돌면서 줄거리와 기본 정보가 있고, 국내에서 개봉했으며 최소 50명 이상이 평가한 영화들만 수집할 것이다.
실제 수집해보니 네이버 영화의 경우 예외처리가 필요한 부분이 생겨 코드가 더러워 보이지만
코드 구현은 아주 간단하다.
수집을 원하는 홈페이지 URL을 입력해 html형식의 문서를 얻어내고 객체 타입과 객체의 class, id를 통해 직접적으로 찾아갈 수 있으며 attributes(href, style, class, id ..) 와 text 또한 얻어낼 수 있다. 찾아간 객체의 parent를 얻을 수도 있으다.
네이버 영화의 모든 페이지는 일정한 형식이 있는데 예외처리가 필요한 부분을 처리하면서 디버그와 프로그래밍을 동시에 수행하면서 충분히 구현 가능하다.
아마 다른 페이지들도 마찬가지.
줄거리를 얻어내는 부분의 코드에서 .prettify(fomatter="html")를 사용한 이유는
. get_text()로는 " " 와 같은 부분이 있다면 온전한 데이터를 얻을 수 없기 때문에 사용했으며
# -*- coding: utf-8 -*- import requests import urllib2 import re from bs4 import BeautifulSoup def single_line(raw_str): return " ".join(raw_str.split()) def uni_to_utf8(unicode_str): return str(unicode_str.encode('utf-8')) def printError(err_message): print(err_message) def crawling(year, target_link): url = target_link r = requests.get(url) data = r.text soup = BeautifulSoup(data, 'html.parser') info = soup.find('div', class_='mv_info') if not info: return None content = soup.find('div',class_='story_area') if not content: return None uni_movie_name = info.find('h3', class_='h_movie') if not uni_movie_name: return None uni_movie_name = uni_movie_name.find('a') if not uni_movie_name: return None movie_name = uni_to_utf8(uni_movie_name.get_text()) netizen_count = info.find('div',id=re.compile("pointNetizen")) if not netizen_count: return None netizen_count = netizen_count.find('em') if not netizen_count: return None netizen_count = netizen_count.get_text().replace(',',"") if int(netizen_count) < 50: return None score = info.find('a', id=re.compile("pointNetizen")) if not score: return None score = score.find('span',class_='st_on')['style'] if not score: return None score = float(score.split(':')[1].split('%')[0]) genres = info.find_all('a', href=re.compile("/movie/sdb/browsing/bmovie.nhn\?genre")) genre_array = [] for genre in genres: genre_array.append(uni_to_utf8(genre.get_text())) grade_list = ['전체 관람가', '12세 관람가', '15세 관람가', '청소년 관람불가', '제한상영가', '등급보류'] grade = info.find('a', href=re.compile("/movie/sdb/browsing/bmovie.nhn\?grade")) if not grade: return None grade = uni_to_utf8(grade.get_text()) if grade in grade_list: grade = grade_list.index(grade) raw_main_story = content.find('p',class_='con_tx') if not raw_main_story: return None raw_main_story = raw_main_story.prettify(formatter="html") raw_main_story = (re.sub(r'<.*>',"",raw_main_story)) uni_main_story = single_line((re.sub(r'&.*;',"",raw_main_story))) main_story = uni_to_utf8(uni_main_story) print ('[' + target_link + '] : get data') movie = {"year": year, "movie_name": movie_name, "score": score, "grade" : grade} #create movie print( movie) print("---------------------------------") def get_link(target_page): url = target_page r = requests.get(url) data = r.text soup = BeautifulSoup(data, 'html.parser') ul = soup.find('ul', class_='directory_list') return ul.find_all('a',href=re.compile("/movie/bi/mi/")) def call_crawler(): year = 2000 for page in range(1,999): print(str(year) + 'year - [' + str(page) + '] page') target_page = 'http://movie.naver.com/movie/sdb/browsing/bmovie.nhn?year=' + str(year) + '&page=' + str(page) r = requests.get(target_page) data = r.text soup = BeautifulSoup(data, 'html.parser') cur_page = soup.find('span', style='color:#FF7632').get_text() if page > int(cur_page): page = 1 year = year + 1 if year > 2017: break target_links = get_link(target_page) for target_link in target_links: crawling(year,'http://movie.naver.com'+target_link['href']) call_crawler()
'job sound' 카테고리의 다른 글
[C++] Dynamic Programming을 알아보자. (0) | 2017.05.11 |
---|---|
[C++] BFS와 DFS (0) | 2017.05.11 |
[Windows] Windows 10 부팅(설치) 디스크를 만들어보자 (0) | 2017.04.17 |
[Ubuntu] Ubuntu 부팅(설치) 디스크를 만들어보자 (0) | 2017.04.10 |
[키보드] 무접점 정전 용량 키보드 관련 정보 (0) | 2017.04.05 |