본문 바로가기
Programming/Python

[Python] 파이썬 영화 사이트 (씨네21) 크롤링 2

by 코딩하는 금융인 2021. 6. 1.

안녕하세요.
저번 게시물에 이어 파이썬 영화 데이터 크롤링 2편 포스팅하겠습니다.

씨네21 크롤링

▶ 2차 크롤링 작업
- result_data01

kr_c_link kr_c_name
http://www.cine21.com/db/writer/info/?pre_code=E20041252 박평식
http://www.cine21.com/db/writer/info/?pre_code=E20041291 이용철
http://www.cine21.com/db/writer/info/?pre_code=E20041338 황진미
http://www.cine21.com/db/writer/info/?pre_code=E20041283 이동진
˙˙˙˙ ˙˙˙˙

2차까지는 Selenium으로 작업하였습니다.

result_data01에서 가져온 링크에 접속하여 별점 페이지로 넘어가고 end 버튼의 'href' 속성에 명시된 endpoint를 추출했습니다.

btn_end class html

또한, 프로필 사진에 있는 image 링크도 추출했습니다.

profile image html

이렇게 하나하나 셀레니움으로 버튼 클릭, css select를 하면 시간이 엄청나게 오래 걸린다는 단점이 있습니다.

당시 저는 크롤링에 익숙하지 않았고 자동화 코드를 만들 때 selenium만 사용해봤습니다.

( 지금 생각해보면 되게 비효율적인 코드입니다..)

 

만약 크롤링 작업을 하신다면, json이나 request를 사용하여 html 데이터를 추출하고 bs4 모듈로 파싱하는 방식을 적극 추천드립니다. ( 시간이 비교가 안됩니다.. )


▶ Python Code

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import pandas as pd
from bs4 import BeautifulSoup
from selenium.common.exceptions import NoSuchElementException
from tqdm import tqdm
import time

options = webdriver.ChromeOptions()
options.add_argument("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36") # 네트워크 설정
options.add_argument("lang=ko_KR") # 사이트 주언어

driver = webdriver.Chrome(ChromeDriverManager().install(),chrome_options=options)

# 2차 목표 : 01에서 가져온 사이트를 토대로 별점페이지수와 필자별 이미지 크롤링

df = pd.read_excel("/Users/mycelebs/PycharmProjects/Mycelebs/RealData/result_data01.xlsx")
kr_c_link = df.loc[:,"kr_c_link"]
data_list=[]
for i in tqdm(kr_c_link):
    driver.get(f"{i}")
    # 별점 페이지로 넘어가기 버튼 클릭
    driver.find_element_by_css_selector('#content > div > div.floatL > div.tab_area1 > ul > li:nth-child(2)').click()
    end = driver.find_element_by_css_selector('#write_view_review20_holder > div.pagination > a.btn_end').get_attribute('href')
    # print(end)
    image = driver.find_element_by_css_selector("#content > div > div.floatR > div.profile > img").get_attribute("src")
    data = {"end":end, "image":image}
    data_list.append(data)

driver.close()
result_df = pd.DataFrame(data_list, columns=['end','image'])
result_df.to_excel(f'/Users/mycelebs/PycharmProjects/Mycelebs/RealData/endpoint.xlsx', index=False)

▶ 3차 크롤링 작업
- result_data01 (수정)

kr_c_name pre_code endpoint
박평식 E20041252 898
이용철 E20041291 433
황진미 E20041338 273
이동진 E20041283 224
김성훈 E20041648 92
˙˙˙˙ ˙˙˙˙ ˙˙˙˙

앞서 추출한 데이터들에서 평론가 이름(kr_c_name), 코드(pre_code), 평점 영화 개수(endpoint)로 이루어진 result_data01 데이터 프레임을 수정했습니다.

 

마지막 작업은 requests(추출)와 BeautifulSoup(파싱) 모듈을 사용했습니다.

씨네21 사이트의 html 구조를 살펴보던 중 Network tab에서 info_review20 이라는 Request url을 발견했습니다.

Request url

Form Data를 살펴보니 pre_code와 p(endpoint)를 post해주면 될 것 같아서 result_data01에서

for문으로 payload {"pre_code": pre_code, "p": endpoint}를 request url에 post하여 html을 가져왔습니다.

Request url details

가져온 html 구조를 보고 분석하여 제가 필요한 column을 soup으로 파싱하였습니다.

중간에 영화가 없는 경우가 있어 try ~ except문으로 예외 처리해주고 result_data02로 데이터 프레임화하여 작업을 마무리했습니다.

 

▶ Python Code

import requests
import pandas as pd
from bs4 import BeautifulSoup
from tqdm import tqdm
import time
import traceback

# 3차 목표 : 씨네21 평론가들의 영화평가코멘트, 별점, 해당 영화의 연도와 타이틀 크롤링

url ="http://www.cine21.com/db/writer/info_review20"
heades_data = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"}
df = pd.read_excel("C:/RealData/result_data01.xlsx")
sess = requests.Session()
data_list =[]

# numb = -1
for idx, row in tqdm(df.iterrows(), desc="돌리는중"):
    pre_code = row['pre_code']
    endpoint = row['endpoint']
    kr_c_name = row['kr_c_name']
    # numb = numb+1
    for j in tqdm(range(1, endpoint+1), desc = "평론가 한 명의 영화평을 서치 중입니다~"):
        # print(pre_code)
        payload = {"pre_code": pre_code, "p":j}
        res = sess.post(url, headers=heades_data, data=payload)
        soup = BeautifulSoup(res.text, 'html.parser')
        # print(soup)
        for i in range(0, len(soup.find_all('p',{'class','mov_tit'}))):
            try:
                mov = soup.find_all('p', {'class':'mov_tit'})[i]
                kr_mov_url = mov.find('a')['href']
                # print(kr_mov_url)
                kr_title =mov.find('a').text
                # print(kr_title)
                kr_year = soup.find_all('span', {"class":"year"})[i].text
                # print(kr_year)
                kr_comment = soup.find_all('p', {"class":"comment"})[i].text
                # print(kr_comment)
                kr_rating = soup.find_all('span', {'class':'num'})[i].text
                # print(kr_rating)
            except:
                traceback.print_exc()
            data = {"kr_c_name":kr_c_name, "pre_code":pre_code, "kr_mov_url": kr_mov_url,
                    "kr_title":kr_title, "kr_year":kr_year, "kr_comment":kr_comment, "kr_rating":kr_rating}
            data_list.append(data)

result_df = pd.DataFrame(data_list, columns=['kr_c_name','pre_code','kr_mov_url','kr_title','kr_year','kr_comment','kr_rating'])
result_df.to_excel(f'C:/RealData/result_data02.xlsx', index=False)


# 예시 -> range를 5로 확정할 경우 5개가 아닌 데이터에서 에러가 남 따라서 해당 모듈의 length로 해결.

 

- 최종 데이터 프레임

kr_c_name kr_mov_url movie_id kr_title kr_year kr_comment kr_rating
박평식 /movie/info/?movie_id=55371 55371 캔 유 킵 어 시크릿? 2019 푼수 옆에 철부지 3
박평식 /movie/info/?movie_id=7201 7201 타이페이 스토리 1985 시대의 톱니에 낀 떠돌이들의 권태와 불안 7
박평식 /movie/info/?movie_id=55331 55331 왓 데이 해드 2018 가까운 타인, 동지애가 필요한 시간 6
박평식 /movie/info/?movie_id=53448 53448 신의 한 수: 귀수편 2019 만취한 선무당이 칼부림하듯 3
박평식 /movie/info/?movie_id=55389 55389 우먼 인 할리우드 2018 대장은 지나 데이비스 6
박평식 /movie/info/?movie_id=55396 55396 하이 라이프 2018 기괴한 불임클리닉, 옹색한 육아일기 6
박평식 /movie/info/?movie_id=54815 54815 터미네이터: 다크 페이트 2019 반갑되 아쉬운 사라 코너 6
박평식 /movie/info/?movie_id=54608 54608 날씨의 아이 2019 황홀하게 뜬구름 잡기 5
˙˙˙˙ ˙˙˙˙ ˙˙˙˙ ˙˙˙˙ ˙˙˙˙ ˙˙˙˙ ˙˙˙˙

 

반응형

댓글