Requests
와 BeautifulSoup
라이브러리가 필요합니다.
>>> pip install requests # 라이브러리를 설치합니다.
>>> pip install BeautifulSoup # 현재 BeautifulSoup은 버젼 4를 사용합니다.
>>> import requests
>>> from bs4 import BeautifulSoup
>>> url = "https://www.rottentomatoes.com/m/parasite_2019/reviews"
>>> req = requests.get(url)
>>> print(req) # get은 단순히 응답코드만 가져옵니다.
<Response [200]>
>>> html = req.text # html내용을 가져오기 위해 text를 가져옵니다. 인코딩이 안 맞을 경우에는 인코딩 방식을 바꾸거나 .content를 쓸 수 있습니다.
>>> print(html)
<!DOCTYPE html>
<html lang="en"
dir="ltr"
xmlns:fb="http://www.facebook.com/2008/fbml"
xmlns:og="http://opengraphprotocol.org/schema/">
<head prefix="og: http://ogp.me/ns# flixstertomatoes: http://ogp.me/ns/apps/flixstertomatoes#">
...
>>> soup = BeautifulSoup(html, 'html.parser')
<!DOCTYPE html>
<html dir="ltr" lang="en" xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:og="http://opengraphprotocol.org/schema/">
<head prefix="og: http://ogp.me/ns# flixstertomatoes: http://ogp.me/ns/apps/flixstertomatoes#">
<!-- salt=lay-def-02-juRm -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="ie=edge" http-equiv="x-ua-compatible"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>Parasite (Gisaengchung) - Movie Reviews</title>
...
리뷰를 보면 여러 개가 같은 형식으로 되어 있습니다. 이럴 때는 보통 html 리스트 형식을 사용합니다. 이럴 경우 이름, 소속, 평가, 날짜끼리는 같은 CSS 클래스를 사용했을 가능성이 큽니다.
사진과 같이 크롬 개발자 도구를 열고(F12
) 커서 표시를 클릭(Ctrl+Shift+C
)한 후 원하는 부분(이름, 소속, 평가, 날짜)를 클릭합니다. 그럼 오른쪽에 파란색 영역표시 되는 부분에서 우클릭 후 Copy - Copy selector
를 눌러 값을 복사합니다.
selector의 전체 부분이 다 필요한 것은 아닙니다. 클래스명이 겹치지 않는다는 가정 하에 div.review_table
부터 가져오고 리스트의 첫번째 항목에 해당하는 :nth-child(1)
를 지워 전체 값을 다 가져오도록 코드에 넣습니다.
원래 selector 값
#content > div > div > div > div.review_table > div:nth-child(1) > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a.unstyled.bold.articleLink
>>> name = soup.select(
'div.review_table > div > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a.unstyled.bold.articleLink'
)
>>> print(name)
[<a class="unstyled bold articleLink" href="/critic/jeremy-jahns">Jeremy Jahns</a>, <a class="unstyled bold articleLink" href="/critic/sebastian-zavala-kahn">Sebastian Zavala Kahn</a>, <a class="unstyled bold articleLink" href="/critic/paul-whitington-15988">Paul Whitington</a>, <a class="unstyled
...
>>> print(name[0])
<a class="unstyled bold articleLink" href="/critic/jeremy-jahns">Jeremy Jahns</a>
>>> print(name[0].text)
Jeremy Jahns
가져온 값(name)은 리스트로 되어 있으며 원하는 텍스트를 가져오는 방법은 마지막 줄과 같습니다.
이와 같이 소속, 평가, 날짜도 가져옵니다. 그런 다음 zip
함수로 리스트로 묶고, replace
함수로 불필요한 텍스트를 제거하는 과정을 거치면 원하는 값만 가져올 수 있습니다.
>>> name = soup.select(
'div.review_table > div > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a.unstyled.bold.articleLink'
)
>>> belongto = soup.select(
'div.review_table > div > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a > em'
)
>>> review = soup.select(
'div.review_table > div > div.col-xs-16.review_container > div.review_area > div.review_desc > div.the_review'
)
>>> created_at = soup.select(
'div.review_table > div > div.col-xs-16.review_container > div.review_area > div.review-date.subtle.small'
)
>>> movie_review = []
>>> for item in zip(name, belongto, review, created_at):
movie_review.append(
{
'name' : item[0].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'belongto' : item[1].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'review' : item[2].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'created_at': item[3].text.replace('\n', '').replace('\t', '').replace(' ', ''),
}
)
>>> print(movie_review)
[{'name': 'Jeremy Jahns', 'belongto': 'Me gusta el cine', 'review': 'The movie itself - message aside - is remarkably entertaining.', 'created_at': 'February 13, 2020'}, {'name': 'Sebastian Zavala Kahn', 'belongto': 'Irish Independent', 'review': 'It conveys very clear messages about classism and discrimination, [all through] an entertaining and visually arresting story. [Full review in Spanish]', 'created_at': 'February 12, 2020'}, {'name': 'Paul Whitington', 'belongto': 'entertainment.ie', 'review': "It's a splendid film, beautifully acted and realised, which manages to be both entertaining and profound.", 'created_at': 'February 12, 2020'}, {'name': 'Deirdre Molumby', 'belongto': 'Independent (UK)', 'review': 'A breath-taking cinematic accomplishment that will have you talking for days', 'created_at': 'February 12, 2020'}, {'name': 'Clarisse Loughrey', 'belongto': 'The Jewish Chronicle', 'review': "[Bong Joon-ho]'s work is as playful as it is sincere and revelatory.
1페이지 크롤링을 완성했습니다. 20페이지까지 하기 위해 url list를 만들고 for문으로 코드를 수정합니다. 아래는 최종코드입니다. csv 저장을 위해 pandas 라이브러리도 설치해 가져옵니다. 리스트 형식으로만 결과를 뽑으면 판다스를 이용해 손쉽게 파일로 저장할 수 있습니다.
import requests
import pandas as pd
from bs4 import BeautifulSoup
ran = range(1,21)
url = "https://www.rottentomatoes.com/m/parasite_2019/reviews?type=&sort=&page="
url_list = []
for r in ran:
url_list.append(url+str(r))
print(url_list)
movie_review = []
for url in url_list:
req = requests.get(url)
html = req.text
soup = BeautifulSoup(html, 'html.parser')
name = soup.select(
'div.review_table > div > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a.unstyled.bold.articleLink'
)
belongto = soup.select(
'div.review_table > div > div.col-xs-8 > div.col-sm-13.col-xs-24.col-sm-pull-4.critic_name > a > em'
)
review = soup.select(
'div.review_table > div > div.col-xs-16.review_container > div.review_area > div.review_desc > div.the_review'
)
created_at = soup.select(
'div.review_table > div > div.col-xs-16.review_container > div.review_area > div.review-date.subtle.small'
)
for item in zip(name, belongto, review, created_at):
movie_review.append(
{
'name' : item[0].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'belongto' : item[1].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'review' : item[2].text.replace('\n', '').replace('\t', '').replace(' ', ''),
'created_at': item[3].text.replace('\n', '').replace('\t', '').replace(' ', ''),
}
)
data = pd.DataFrame(movie_review)
data.to_csv('movie_review.csv')