Recent Posts
Recent Comments
Archives
반응형
250x250
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Today
Yesterday

Total
05-08 01:43
관리 메뉴

Hey Tech

파이썬 기반 구글 플레이 스토어 웹 크롤러 개발하기 Version1 본문

AI & 빅데이터/데이터 엔지니어링

파이썬 기반 구글 플레이 스토어 웹 크롤러 개발하기 Version1

Tony Park 2021. 10. 1. 15:21
728x90
반응형

 

 

 

필독!


안녕하세요,

구글 플레이 스토어 웹 페이지 구조가 변경됨에 따라 현재 포스팅에 업로드한 크롤러는 작동하지 않습니다.

개편된 웹 페이지 구조를 고려하여 크롤러를 업데이트하였습니다.

아래 포스팅을 참고해 주세요! 감사합니다.

https://heytech.tistory.com/293

 

[Python] 구글 플레이 스토어 웹 크롤러 코드 Version2

안녕하세요! 오늘은 파이썬(주피터 노트북)을 기반으로 직접 코딩한 구글 플레이 스토어 웹 크롤러 코드를 공유합니다. 📝 목차 1. 업데이트 Log 2. 주요 기능 3. 전체 코드 4. 필수 초기 세팅 5.

heytech.tistory.com


 

 

 

 

 

안녕하세요!

오늘은 파이썬(주피터 노트북)을 기반으로 직접 코딩한 구글 플레이 스토어 웹 크롤러 코드를 공유합니다.

📝 목차

1.  주요 기능
2. 전체 코드
3.  필수 초기 세팅
4. 코드 및 설명

1.  주요 기능

(1) 구글 플레이 스토어 App 사용자 리뷰 자동 수집(그림 1)

  • 리뷰 등록일
  • 작성자 닉네임
  • 리뷰 내용
  • 리뷰 평점

그림 1. App 리뷰 수집을 위한 브라우저 자동 제어 모습

 

(2) Parsing 한 데이터 html 문서로 저장

(3) 수집 데이터는 아래와 같이 데이터프레임 형태로 포매팅(그림 2)

그림 2. 수집 데이터 포맷

2.  전체 코드

다들 바쁘실텐데 크롬 드라이버 세팅, 필요 패키지 설치, 간단한 파일 경로 편집이 가능하신 분은

이 문서를 참고하셔서 필요한 부분을 이용하시면 되겠습니다 :)

https://github.com/park-gb/playstore-review-crawler/blob/main/src/crawler.ipynb

 

GitHub - park-gb/playstore-review-crawler: The web crawler to collect app user reviews from Google Play Store

The web crawler to collect app user reviews from Google Play Store - GitHub - park-gb/playstore-review-crawler: The web crawler to collect app user reviews from Google Play Store

github.com

3.  필수 초기 세팅

이제부터 차근차근 웹 크롤러를 구현하는 방법에 대해 소개해 드리겠습니다.

혹시라도 잘 안되는 곳 있다면 아래에 👇👇👇 댓글 남겨주세요! 해결책을 찾아드릴 수 있도록 노력해 보겠습니다👨‍💻🔥

(1)  코드 다운로드

Github 링크 이곳을 클릭하셔서 코드를 포함한 파일을 설치해 줍니다(그림 3).

그림 3. 소스코드 및 필요한 파일 다운로드

1) 초록색 버튼 'Code'를 클릭

2) 'Download ZIP' 클릭(git이 설치되어 있으신 분들은 clone 하셔도 됩니다)

3) 다운로드 받은 알집 해제

 

(2)  크롬 설치

크롬 미설치자는 이곳을 클릭하셔서 설치해 주시기 바랍니다. 크롬은 구글에서 개발한 브라우저입니다.

(3)  크롬 드라이버 설치

1) 이곳을 클릭해 사용 중인 크롬 버전을 확인합니다. 앞서 설치한 파일 내 크롬 드라이버는 Chrome version 94 사양에 적합합니다.

2) 사용 중인 크롬 버전이 94와 같다면 바로 4) 과정으로, 다르다면 3-1) 과정으로 이동하세요.

3-1) 이곳을 클릭해 버전에 맞는 크롬 드라이버를 설치합니다.

3-2) 설치한 크롬 드라이버는 앞서 (1)에서 설치한 파일 안으로 이동시켜 줍니다.

4.  코드 및 설명

코드는 (1)에서 설치한 파일 내 src 폴더에 주피터 노트북 파일입니다.

크롬 드라이버 설정

파일 확장자 이름 사용여부에 따라 앞서 chromedriver 파일명을 수정해 줍니다.

# chrome_driver = '../chromedriver.exe' # 파일 확장자 이름 표기
chrome_driver = '../chromedriver' # 파일 확장자 이름 미표기

수집할 앱 주소(구글 플레이 스토어)

구글 플레이 스토어에서 수집할 App 검색 후 App을 선택합니다.

아래 그림 4 빨간 박스처럼 선택한 App 소개 페이지의 URL 링크를 복사하여 소스코드 내 url 변수에 할당해 줍니다.

그림 4. 수집할 App URL 가져오기

url = 'https://play.google.com/store/apps/details?id=com.github.android&showAllReviews=true' # 예시: Github App 주소

파이썬 패키지 설치

!pip install beautifulsoup4
!pip install selenium
!pip install tqdm
!pip install pandas
  • beatuiful soup: HTML/XML 문서 parsing
  • selenium: 브라우저 동작 자동 제어
  • pandas: 데이터 분석 라이브러리
  • tqdm: 작업 프로세스 바(progress bar) 시각화

패키지 불러오기

import requests
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup
import time
from time import sleep
import random
from tqdm.auto import tqdm, trange
import pandas as pd

무한 스크롤 함수

구글 플레이 스토어의 사용자 리뷰는 무한 스크롤 형태로 제공합니다.

즉, 스크롤 할 때마다 새로운 사용자 리뷰를 계속 보여주는 형태입니다.

따라서 App 내 모든 사용자 리뷰를 웹 페이지에서 확인하려면 반복하여 스크롤해야 합니다.

def scrolling():
    try:        
        # 스크롤 높이 받아오기
        last_height = driver.execute_script("return document.body.scrollHeight")
        while True:
            pause_time = random.uniform(0.5, 0.8)
            # 최하단까지 스크롤
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            # 페이지 로딩 대기
            time.sleep(pause_time)
            # 무한 스크롤 동작을 위해 살짝 위로 스크롤
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight-50);")
            time.sleep(pause_time)
            # 스크롤 높이 새롭게 받아오기
            new_height = driver.execute_script("return document.body.scrollHeight")
            try:
                # '더보기' 버튼 있을 경우 클릭
                more_btn = driver.find_element_by_xpath('/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/div/div[1]/div[2]/div[2]/div/span/span').click()
            except:
                # 스크롤 완료 경우
                if new_height == last_height:
                    print("Scrolling is completed!!!")
                    break
                last_height = new_height
                
    except Exception as e:
        print("error occurred: ", e)

HTML 데이터 가져오기

초기에 설정한 App URL에 접근해 HTML 데이터를 가져옵니다.

웹 페이지 접근을 시도하고 5초간 정상적으로 페이지가 로딩되었는지 확인합니다.

driver = webdriver.Chrome(chrome_driver)
# 페이지 열기(모든 리뷰 보기)
driver.get(url + "&showAllReviews=true")
# 페이지 로딩 대기(5초 간)
wait = WebDriverWait(driver, 5)
xpath_code = '/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/div/div[1]/div[2]/div/div[1]/div/div[2]/div[1]/div[2]/div/div[2]/span/span/span'
chk_loading = wait.until(EC.element_to_be_clickable((By.XPATH, xpath_code)))

앞서 정의한 무한 스크롤 함수를 통해 모든 리뷰 데이터를 서버에 요청해 받아 옵니다.

이제 전체 웹 페이지 소스를 받아오고 Beautifulsoup 패키지를 활용해 parsing 합니다.

# 페이지 무한 스크롤 다운
scrolling()
# html parsing하기
html_src = driver.page_source
soup_src = BeautifulSoup(html_src, 'html.parser')

 

이제 아래 그림 5와 같이 웹 페이지가 열리고 모든 리뷰 데이터가 페이지에 로딩될 때까지 무한 스크롤이 진행됩니다.

그림 5. App 리뷰 수집을 위한 브라우저 자동 제어 모습

HTML 데이터 저장

parsing 한 데이터 자체를 html 파일로 저장합니다.

추후에 추가적인 크롤링 작업 없이도 해당 웹 페이지의 전체 데이터를 활용하기 위함입니다.

# html 데이터 저장
with open("../dataset/html_data.html", "w", encoding = 'utf-8') as file:
    file.write(str(soup_src))

parsing 한 html 데이터에서 필요한 데이터만 추출해 보겠습니다.

# 리뷰 데이터 클래스 접근
review_all= soup_src.find_all(class_ = 'd15Mdf bAhLNe')

필요 데이터 추출

이제 리뷰 등록일, 작성자 닉네임, 리뷰 내용, 평점 정보를 추출하겠습니다.

리뷰 등록일의 경우, 'yyyymmdd' 포맷과(e.g., 20211001), 연도, 월, 일 정보를 각각 나누어 저장하겠습니다.

그 이유는 시계열(Time Series) 분석에 활용하기 위함입니다. 필요에 따라 원하는 정보를 사용하시길 바랍니다.

start = time.time() # 코드 실행 시간 측정을 위한 변수
date_ymd = [] # 리뷰등록일을 yyyymmdd 형태로 저장할 리스트 생성
date_y = [] # 리뷰등록일 중 연도 정보를 yyyy 형태로 저장할 리스트 생성
date_m = [] # 리뷰등록일 중 월 정보를 mm 형태 저장할 리스트 생성
date_d = [] # 리뷰등록일 중 일 정보를 dd 형태로 저장할 리스트 생성
username_list = [] # 사용자 닉네임 저장용 리스트
rating_list = [] # 평점 데이터 저장용 리스트
content_list = [] # 텍스트 리뷰 저장용 리스트

# 리뷰 1개씩 접근해 정보 추출
for rv in tqdm(review_all):
    
    date_ymd_v = rv.find_all(class_ = 'p2TkOb')[0].text
    date_y_v = date_ymd_v[0:4] # 연도 정보만 추출
    # 해당 단어가 등장한 인덱스 추출
    idx_y = date_ymd_v.find('년')
    idx_m = date_ymd_v.find('월')
    idx_d = date_ymd_v.find('일')
    date_m_v = str(int(date_ymd_v[idx_y+1:idx_m])) # 월 정보만 추출
    date_d_v = str(int(date_ymd_v[idx_m+1:idx_d])) # 일 정보만 추출
    
    # 월 정보가 1자리의 경우 앞에 0 붙여줌(e.g., 1월 -> 01월)
    if len(date_m_v) == 1:
        date_m_v = '0' + date_m_v
    # 일 정보가 1자리의 경우 앞에 0 붙여줌(e.g., 7일 -> 07일)
    if len(date_d_v) == 1:
        date_d_v = '0' + date_d_v
    
    # 리뷰등록일 full version은 최종적으로 yyyymmdd 형태로 저장
    date_full = date_y_v + date_m_v + date_d_v
    date_ymd.append(date_full)
    date_y.append(date_y_v)
    date_m.append(date_m_v)
    date_d.append(date_d_v)
    username_list.append(rv.find_all(class_ = 'X43Kjb')[0].text) # 닉네임 정보 추출 및 저장
    rating_list.append(rv.select('span.nt2C1d > .pf5lIe > div')[0]['aria-label'][10]) # 평점 정보 추출 및 저장
    content = rv.find_all('span', attrs={'jsname':"fbQN7e"})[0].text # 장문 리뷰 내용 추출 및 저장
    # 장문 리뷰 존재하는 경우 그대로 리스트에 저장
    if content:
        content_list.append(content)
    # 단문 리뷰만 존재하는 경우, 단문 리뷰 추출 및 저장
    else:
        content_list.append(rv.find_all('span', attrs={'jsname':"bN97Pc"})[0].text)
# 코드 실행 소요시간 출력
print(time.time() - start)

데이터프레임 저장

이제 추출한 데이터를 데이터프레임 형태로 바꿔주고 이를 csv 파일로 저장합니다.

start = time.time() # 코드 실행 시간 측정을 위한 변수
rv_df = pd.DataFrame({'id': range(len(date_ymd)), # userID 임의부여
                      'date': date_ymd, # 리뷰등록일 전체(yyyymmdd)
                      'date_y': date_y, # 리뷰등록일 중 연도(yyyy)
                      'date_m': date_m, # 리뷰등록일 중 월(mm)
                      'date_d': date_d, # 리뷰등록일 중 일(dd)
                     'username': username_list, # 사용자 닉네임
                     'rating': rating_list, # 평점
                     'content': content_list}) # 리뷰 내용
rv_df.to_csv('../dataset/review_dataset.csv', encoding = 'utf-8-sig') # csv 파일로 저장

print(time.time() - start) # 코드 실행 소요시간 출력

데이터 불러오기

앞서 저장한 데이터가 정상적으로 저장되었는지 확인합니다(그림 6).

# 저장한 리뷰 정보 불러오기
rv_df = pd.read_csv('../dataset/review_dataset.csv', encoding = 'utf-8-sig')
rv_df = rv_df.drop(['Unnamed: 0'], axis = 1) # 불필요한 칼럼 삭제
rv_df.head()

그림 6. 수집 데이터 포맷


포스팅 내용에 오류가 있을 경우 아래에 👇👇👇 댓글 남겨주시면 감사드리겠습니다 :)

그럼 오늘도 즐겁고 건강한 하루 보내시길 바랍니다.

고맙습니다.

 

 


필독!

안녕하세요,

구글 플레이 스토어 웹 페이지 구조가 변경됨에 따라 위의 포스팅에 업로드한 크롤러는 작동하지 않습니다.

개편된 웹 페이지 구조를 고려하여 크롤러를 업데이트하였습니다.

아래 포스팅을 참고해 주세요! 감사합니다.

https://heytech.tistory.com/293

 

[Python] 구글 플레이 스토어 웹 크롤러 코드 Version2

안녕하세요! 오늘은 파이썬(주피터 노트북)을 기반으로 직접 코딩한 구글 플레이 스토어 웹 크롤러 코드를 공유합니다. 📝 목차 1. 업데이트 Log 2. 주요 기능 3. 전체 코드 4. 필수 초기 세팅 5.

heytech.tistory.com


728x90
반응형
Comments