네이버 크롤링은 매우 간단하다.

이 글에서는 영화를 검색했을 경우, 네티즌의 리뷰 갯수가 몇개나 등록되어 있는지를 크롤링하는 코드를 포스팅한다.

# 현재 내가 가지고 있는 영화의 타이틀을 저장함
full_title =np.array([train_and_test['title'].apply(lambda x : x.split(' '))]).reshape(-1, )

# requests, bs4가 없다면 설치해야 한다.
import requests
from bs4 import BeautifulSoup

# 네이버에서 영화를 검색할 시 공통적으로 생성되는 쿼리문은 아래와 같다
# 따라서 영화 이름과 url을 붙여준 리스트를 한번 더 생성해보자
full_url = list()
for title in full_title:
    url = 'https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query=영화'
    for word in title:
        url += '+'
        url += word
    
    full_url.append(url)

# 이제 영화 리뷰 수, 즉 별점을 몇명이나 주었는지에 대한 정보를 담을 dataframe을 생성한다.
star_num_df = pd.DataFrame(columns=['title', 'star_num'])

# headers
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; ko-KR))',
}

# 네이버에서는 우리가 찾을 값을 cont_p로 정의해두었다. 그에 맞춰 이름을 정의하자.
cont_p_list = list()

# main code
for i, (url, title) in enumerate(zip(full_url, train_and_test['title'])):
    print(i)
    response = requests.get(url, headers = headers)
    html = response.text
    
    soup = BeautifulSoup(html, 'lxml')
    
    # cont_p를 찾아준다.
    em = soup.find('em', {'class':'cont_p'})
    
    if(em is None):
        num_df.loc[i, 'title'] = title
        num_df.loc[i, 'star_num'] = 0
    else:
    	# 자신이 찾고 싶은 데이터에 맞게 찾아오면된다. 자세한건 soup.find를 검색해보자
        for em in soup.find('em', {'class':'cont_p'}):
            num_df.loc[i, 'title'] = title
            num_df.loc[i, 'star_num'] = em

지금 글부터는 자바스크립트 형태로 되어 있어 위의 코드로 찾을 수 없는 데이터를 찾으려고 한다.

어떻게 알 수 있냐면, 분명히 페이지 소스에서는 존재하는 데이터가 soup.find로 찾으려고 할때 None값이 리턴되는 경우가 생긴다면 의심해 볼 필요가 있다.

위의 코드는 해당 데이터가 자바스크립트 형태로 되어 있을 시, soup.find를 통하여 클래스를 찾을 수가 없다. 따라서 아래와 같이 코드를 변경해주어야 한다.

이번 예제는 네이버에서 영화를 검색했을 때, 영화의 하트 갯수를 찾을 것이다. (검색하면 쉽게 찾아볼 수 있음)

# 영화의 제목을 저장하자
full_title =np.array([train_and_test['title'].apply(lambda x : x.split(' '))]).reshape(-1, )

# 이부분까지도 위와 같다.
import requests
from bs4 import BeautifulSoup

full_url = list()
for title in full_title:
    url = 'https://search.naver.com/search.naver?sm=top_hty&fbm=1&ie=utf8&query='
    for word in title:
        url += '+'
        url += word
        
    url += '+영화'
    full_url.append(url)
    
# 우리가 원하는 데이터는 하트 갯수이다. 이를 저장할 dataframe을 생성하자
heart_num_df = pd.DataFrame(columns=['title', 'heart_num'])

# main code
# 여러가지 방법이 있겠지만 이 글에서는 크롬을 이용한다
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('headless') # headless 모드를 했을 때 실행이 안된다. 일단 생략.

# driver = webdriver.Chrome(ChromeDriverManager().install())
driver = webdriver.Chrome(executable_path='/Users/johwiyong/.wdm/chromedriver/74.0.3729.6/mac64/chromedriver')

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; ko-KR))',
}

# 네이버에서는 우리가 찾을 데이터를 u_cnt로 정의해두었다. 
u_cnt_list = list()

for i, (url, title) in enumerate(zip(full_url, train_and_test['title'])):
    print(i)
#     response = requests.get(url, headers = headers)
    driver.get(url)
    driver.implicitly_wait(10) # 작동하지 않는 것 같다.
    # 이만큼의 시간을 기다려주는 이유는 데이터가 불려오기 전에 다음 페이지로 넘어갈 경우
    # None을 return하는 경우가 발생하는 점을 방지
    time.sleep(3) 
    html = driver.page_source
    driver.implicitly_wait(10)
    
    # 여기서부터는 위와 비슷하다
    soup = BeautifulSoup(html, 'lxml')
    
#     print(soup.find_all('em'))
    u_cnt_list = soup.find_all('em', 'u_cnt _cnt')

    if(len(u_cnt_list) == 0):
        print(title)
        heart_num_df.loc[i, 'title'] = title
        heart_num_df.loc[i, 'heart_num'] = 0
    else:
        heart_num_df.loc[i, 'title'] = title
        em = soup.find_all('em', 'u_cnt _cnt')[0].get_text()
        heart_num_df.loc[i, 'heart_num'] = em
        
    print(i, em)