크롤링과 함께 쓰는 mongoDB 예제

6. 크롤링과 함께 쓰는 mongoDB 예제

import requests
import re
import datetime
from bs4 import BeautifulSoup
from pymongo import MongoClient
import pymongo
username = 'davelee'
password = 'happy91'
connection = pymongo.MongoClient('mongodb://%s:%s@www.funcoding.xyz' % (username, password))
mongodb = connection.cine21
actor_collection = mongodb.actor_collection
actor_list = actor_collection.find()
for actor in actor_list:
    print(actor['actor'])

cine21 인물 랭킹 알아내기

cine21_url = 'http://www.cine21.com/rank/person/content'
month = "2017-10"
conditions = dict()
conditions['section'] = 'actor'
conditions['period_start'] = month
conditions['gender'] = 'all'
conditions['page'] = 1
response = requests.post(cine21_url, data = conditions)
response
response.content
soup = BeautifulSoup(response.content.decode('utf-8'), 'html.parser')
soup
actors = soup.select('li.people_li div.name')
actors
실습
actors 리스트에서 배우 이름만 추출하기 예) 마동석(3편) --> 마동석
import re
for actor in actors:
    print(re.sub("\(\w+\)", "", actor.text))

각 배우별 상세 정보를 document에 넣고 싶다.

  • 각 배우별 상세 정보를 별도 컬럼으로 만들려했더니, 각 배우별 상세 정보 항목이 다르다!
  • 모든 상세 정보 항목을 컬럼으로 만들고, 각 컬럼에 매칭되는 컬럼값을 넣기가 쉽지 않다. 코드도 복잡하고!
  • Mongodb는 NoSQL -> 통째로 집어넣자.!
  • embedded document
    • document 의 컬럼값으로 document를 넣을 수 있다.

크롤링해서, embedded document 로 각 배우별 상세 정보를 통째로 만들고, document 컬럼에 넣기

actor_detail_info = list()

for actor in actors:

    actor_info_dict = dict()
    
    actor_info = 'http://www.cine21.com' + actor.select_one('a').attrs['href']
    
    response_actor = requests.get(actor_info)
    
    soup_actor = BeautifulSoup(response_actor.content.decode('utf-8'), 'html.parser')
    
    actor_datas = soup_actor.select('ul.default_info')
    for actor_data in soup_actor.select('ul.default_info'):
        for actor_item in actor_data.select('li'):
            actor_item_text = re.sub('.*?
actor_info_dict = dict()

actor_info = 'http://www.cine21.com/db/person/info/?person_id=19889'

response_actor = requests.get(actor_info)

soup_actor = BeautifulSoup(response_actor.content.decode('utf-8'), 'html.parser')

actor_datas = soup_actor.select('ul.default_info')
for actor_data in soup_actor.select('ul.default_info'):
    for actor_item in actor_data.select('li'):
        actor_item_text = re.sub('.*?
actor_info_dict = dict()

actor_info = 'http://www.cine21.com/db/person/info/?person_id=19889'

response_actor = requests.get(actor_info)

soup_actor = BeautifulSoup(response_actor.content.decode('utf-8'), 'html.parser')
soup_actor
actor_datas = soup_actor.select('ul.default_info')
actor_datas
for actor_data in soup_actor.select('ul.default_info'):
    for actor_item in actor_data.select('li'):
        actor_item_text = re.sub('.*?
print(actor_info_dict)

흥행지수 뽑기

actor_rates = soup.select('li.people_li ul.num_info strong')
for actor_rate in actor_rates:
    print(actor_rate.text)

흥행지수 숫자로 만들어주기

actor_rate_list = list()
for actor_rate in actor_rates:
    actor_rate_list.append(int(actor_rate.text.replace(",","")))  # int() 로 해주지 않으면, 문자열로 됩니다.
actor_rate_list
actor_list = list()
for actor in actors:
    actor_list.append(re.sub("\(\w+\)", "", actor.text))
actor_list

각 배우별 출연 영화를 document에 저장하고 싶다.

  • 출연 영화는 한 개가 될 수도 있고, 여러 개가 될 수도 있음
  • 파이썬은 리스트, mongodb document는 컬럼에 배열(array)로 넣으면 됨
  • 어떻게? 다음과 같이 합니다.
movie_list = list()
movies = soup.select('li.people_li ul.mov_list')
for movie in movies:
    actor_movie = list()
    movie_titles = movie.select('li a span')
    for movie_title in movie_titles:
        actor_movie.append(movie_title.text)
    movie_list.append(actor_movie)
movie_list
  • 이렇게 만든 리스트를 넣으면 됩니다.

insert_one() 로 하나씩 데이터 입력하기 (반복문과 함께 사용하면, 여러 데이터를 넣을 수 있음)

  • actor_list: 배우 이름
  • actor_details: 배우 상세 정보
  • actor_rate: 흥행 지수
  • date: 기준월
  • movie_list: 출연 영화 리스트!
for num, actor in enumerate(actor_list):
    actor_collection.insert_one(
        {"actor":actor_list[num], 
         "actor_details": actor_detail_info[num], 
         "actor_rate":actor_rate_list[num], 
         "date":month, 
         "movie_list":movie_list[num]})
docs = actor_collection.find()
for doc in docs:
    print(doc)

collection 삭제하기

actor_collection.drop()
docs = actor_collection.find()
for doc in docs:
    print(doc)

Dictionary 타입으로 만들어서 한번에 insert_many() 로 데이터 입력하기

actor_info = list()
for num, actor in enumerate(actor_list):
    actor_info.append(
        {"actor":actor_list[num], 
         "actor_details": actor_detail_info[num], 
         "actor_rate":actor_rate_list[num], 
         "date":month, 
         "movie_list":movie_list[num]}
    )
actor_info
actor_collection.insert_many(actor_info)
docs = actor_collection.find()
for doc in docs:
    print(doc)

Update (컬럼명 변경 예제)

actor_collection.update_many( {}, { "$rename": { "actor": "actor_name" } } )
docs = actor_collection.find()
for doc in docs:
    print(doc)
실습
actor_details 필드 이름을 actor_info 로 변경하기
actor_collection.update_many( {}, { "$rename": { "actor_details": "actor_info" } } )
docs = actor_collection.find()
for doc in docs:
    print(doc)
  • 컬렉션 객체 이름도 바꿀 수 있겠지요
actor = actor_collection