크롤러


인공지능과 관련해 데이터를 수집할 일들이 생긴다.


인터넷에서 빅 데이터를 수집할 때 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()
 



+ Recent posts