쥬니어 분석가

[파이썬/크롤링] 집닥 고객 후기 크롤링 with Selenium, BeautifulSoup 본문

python

[파이썬/크롤링] 집닥 고객 후기 크롤링 with Selenium, BeautifulSoup

jyuuni 2024. 2. 14. 17:39
반응형

먼저 크롤링을 하기 위한 환경 구성을 위해 webdrvier-manager를 설치해준다.

pip install webdriver-manager

 

 

그 후 크롤링을 위해 필요한 라이브러리와 그 외 필요한 time, pandas 라이브러리를 import 해준다.

동적 크롤링을 위한 selenium과 정적 크롤링을 위한 Beautifulsoup 두 개를 사용하였고, webdriver로는 크롬드라이버를 사용해서 진행하였다.

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

import time
import pandas as pd

 

 

인테리어/시공 중개 플랫폼인 집닥의 고객후기를 크롤링하기 위해 집닥 고객후기에 있는 모든 데이터를 가져오려고 한다.

집닥의 고객후기 리뷰 페이지 구조

 

집닥의 고객 후기 페이지 전체 화면

 

집닥의 HTML 구조 상 해당 고객후기 페이지에서는 아래와 같이 리뷰가 특정 개수까지만 노출이 되고 잘리는 것으로 확인이 되어 전체 리뷰의 a 태그 내 하이퍼링크를 가져온 후 해당 링크를 하나씩 들어가서 전체 리뷰를 크롤링하는 순서로 진행하였다. 

 

집닥 고객 후기 페이지의 HTML 구조

 

전체 리뷰를 확인하기 위해서는?

 

후기 더보기 버튼의 위치를 파악

 

총 513개의 전체 후기를 확인하기 위해서는 후기 더보기 버튼이 나오지 않을 때까지 클릭해주어야 한다. 해당 부분 구현을 위해 Selenium의 크롬 웹드라이버를 사용해 아래와 같이 간단하게 작성해 보았다.

load_more_button = driver.find_element(By.CLASS_NAME, "_btn_more_view")
        if load_more_button.is_displayed():
            load_more_button.click()
            time.sleep(2)  # 로딩을 기다리기 위해 잠시 대기
        else:
            break

 

 

전체 후기에 대해 하이퍼링크 크롤링하기

 

후기 더보기 버튼 클릭을 통해 전체 후기를 확인했다면 이제 해당 후기들의 하이퍼링크를 추출해 오는 작업을 해야 한다.

자세한 코드는 아래와 같다.

# 페이지 소스 가져오기
html_content = driver.page_source
# BeautifulSoup을 사용하여 HTML 파싱
soup = BeautifulSoup(html_content, 'html.parser')
# 모든 a 태그 가져오기
a_tags = soup.find_all('a')
# 하이퍼링크 추출하여 리스트에 저장
links = [a.get('href') for a in a_tags]

 

링크 저장 후 원하는 형식에 맞는 링크만 필터링하여 사용하면 된다.

 

후기 상세페이지 크롤링

 

이후 후기 상세페이지에 있는 고개후기 전체 텍스트와 별점, 공사기간, 공사금액 데이터를 크롤링하여 가져와 보려고 한다.

후기 상세 페이지에서 볼 수 있는 인테리어 세부 정보
후기 상세 페이지의 HTML 구조

 

"star-score-title" class 내 텍스트와 dd 태그에 있는 세 번째, 네 번째 값인 공사기간, 공사금액의 텍스트를 가져와 보자.

 

가져오는 코드는 아래와 같다.

# 리뷰 데이터를 저장할 리스트 초기화
reviews = []
stars = []
details_period =[]
details_cost = []

# "review_detail" 클래스를 가진 div 요소 찾기
review_detail_element = driver.find_element_by_css_selector('div.review_detail')
star_score_element = driver.find_element_by_css_selector('div.star-score-title')

try:
    # <dl> 클래스가 "info_form clearfix"인 요소를 찾습니다.
    dl_element = driver.find_element(By.CLASS_NAME, "info_form.clearfix")

    # 세 번째 <dd> 태그의 텍스트를 가져옵니다.
    third_dd_text = dl_element.find_elements(By.TAG_NAME, 'dd')[2].text.strip()
    # 네 번째 <dd> 태그의 텍스트를 가져옵니다.
    fourth_dd_text = dl_element.find_elements(By.TAG_NAME, 'dd')[3].text.strip()

    # 리뷰 텍스트 값 추출
    review_text = review_detail_element.text
    # 리뷰 데이터를 리스트에 추가
    reviews.append(review_text)
        
    star_score_text = star_score_element.text
    stars.append(star_score_text)
        
    details_period.append(third_dd_text)
    details_cost.append(fourth_dd_text)

 

이후 해당 리스트를 모아 데이터프레임 형태로 변환하면 아래와 같은 형식으로 출력이 된다.

# 리스트를 데이터프레임으로 변환
df = pd.DataFrame({'Reviews': reviews, 'Star_score': stars,'period':details_period,'cost':details_cost})

리뷰 크롤링 후 파이썬 데이터프레임으로 출력한 결과

 

필자가 크롤링을 한 당시에는 총 510개의 리뷰 데이터가 있던 상태라 510개가 저장되었다.

 

전체 리뷰에 대해 하이퍼링크 추출 및 후기 텍스트 크롤링을 한 코드는 아래와 같다.

 

1. 전체 후기 하이퍼링크 크롤링

# 필요한 라이브러리 가져오기
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# URL 설정
url = "https://zipdoc.co.kr/postscript?category_cd=90"


#웹드라이버에 옵션 설정
options = webdriver.ChromeOptions()
options.add_argument('window-size=1920, 1080')
options.add_argument('--incognito')

# Chrome 웹드라이버 인스턴스 생성
driver=webdriver.Chrome(options = options)

# 페이지 열기
driver.get(url)


# "후기 더 보기" 버튼 클릭
while True:
    try:
        load_more_button = driver.find_element(By.CLASS_NAME, "_btn_more_view")
        if load_more_button.is_displayed():
            load_more_button.click()
            time.sleep(2)  # 로딩을 기다리기 위해 잠시 대기
        else:
            break
    except Exception as e:
        print(f"Error: {e}")
        break

# 페이지 소스 가져오기
html_content = driver.page_source
# BeautifulSoup을 사용하여 HTML 파싱
soup = BeautifulSoup(html_content, 'html.parser')
# 모든 a 태그 가져오기
a_tags = soup.find_all('a')
# 하이퍼링크 추출하여 리스트에 저장
links = [a.get('href') for a in a_tags]
#postscript 붙어있는 경우만 추출
filtered_links = [link for link in links if link is not None and 'postscript' in link]
# 첫 번째와 마지막 값 제외
filtered = filtered_links[1:-1]

base_url = 'https://zipdoc.co.kr'
complete_links = [base_url + link for link in filtered]

 

2. 추출한 전체 링크에 대해 후기, 별점 등 상세 크롤링

# 리뷰 데이터를 저장할 리스트 초기화
reviews = []
stars = []
details_period =[]
details_cost = []

# Selenium 웹 드라이버 초기화
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Selenium 웹 드라이버 초기화
driver = webdriver.Chrome()

# 필터링된 링크 리스트에서 'postscript'를 포함하고 None이 아닌 링크만 선택
filtered_links = [link for link in complete_links if link is not None and 'postscript' in link]

for link in filtered_links:
    # 각 링크를 열어서 페이지 로딩 기다리기
    driver.get(link)
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, 'body')))


    # "review_detail" 클래스를 가진 div 요소 찾기
    review_detail_element = driver.find_element_by_css_selector('div.review_detail')
    star_score_element = driver.find_element_by_css_selector('div.star-score-title')

    try:
        # <dl> 클래스가 "info_form clearfix"인 요소를 찾습니다.
        dl_element = driver.find_element(By.CLASS_NAME, "info_form.clearfix")

        # 세 번째 <dd> 태그의 텍스트를 가져옵니다.
        third_dd_text = dl_element.find_elements(By.TAG_NAME, 'dd')[2].text.strip()
        # 네 번째 <dd> 태그의 텍스트를 가져옵니다.
        fourth_dd_text = dl_element.find_elements(By.TAG_NAME, 'dd')[3].text.strip()

        # 리뷰 텍스트 값 추출
        review_text = review_detail_element.text
        # 리뷰 데이터를 리스트에 추가
        reviews.append(review_text)
        
        star_score_text = star_score_element.text
        stars.append(star_score_text)
        
        details_period.append(third_dd_text)
        details_cost.append(fourth_dd_text)
        
    except Exception as e:
        print("에러 발생:", e)


driver.quit()

# 리스트를 데이터프레임으로 변환
df = pd.DataFrame({'Reviews': reviews, 'Star_score': stars,'period':details_period,'cost':details_cost})
df

 

반응형