KB Idea Market 디지털 공모전 - 1 네이버 종목 토론방 스크래핑

해당 본문은 KB Idea Market 디지털 공모전을 하면서 각 사이트를 스크래핑을 했던 코딩, 텍스트 마이닝 코딩을 첨부하였음.

필요한 라이브러리

from selenium.webdriver import Chrome
import time
import os
import pandas as pd
from bs4 import BeautifulSoup
from selenium.webdriver.common.desired_capabilities import  DesiredCapabilities
import datetime as dt
import urllib.request
import openpyxl
from selenium import webdriver
import requests
import subprocess
import re
from selenium.webdriver.support.ui import Select
from selenium.webdriver import ActionChains
import os, shutil
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import xlrd
import io
import sys
import json

1. 네이버 종목 토론방 사이트 분석

네이버 종목 토론방은 특이하게도 모바일 사이트에서만 종목 토론방을 제공하고 있다. 네이버 종목 토론방의 URL은
https://m.stock.naver.com/worldstock/stock/ZTEK.O/discuss 로 이루어져 있는데,
여기서 주목할 점은 ZTEK.O인데, 모든 종목토론방은 /ZTEK.O/만을 제외하고 공통된 형식을 가진다. 그렇기 때문에, 젠택의 종목코드는 ZTEK이고, 애플은 AAPL, 테슬라는 TSLA인데, 이를 수집할 필요가 있겠다.

[그림1: 네이버 종목 토론방 URL 형태]
또한, 네이버 종목 토론방은 동적 스크래핑이 필요한 사이트다.

[그림2: 네이버 종목 토론방 더보기 버튼]
해당 사진처럼, 토론 댓글이 60~80개가 넘어가면 '더보기' 버튼을 눌러야지 진행되는 것을 알 수 있는데, 이를 위해서 BeautifulSoup, Selenium 라이브러리를 사용하였다.

2. NASDAQ 주가총액 50위 종목코드(TICKER) 데이터 수집

해당 공모에 앞서, 나스닥 주가총액 50위의 주식이름이 뭔지 알아야했다. 이는 나스닥 공식 홈페이지에서 제공을 하고 있어 해당 데이터를 사용하였다.
https://www.nasdaq.com/market-activity/stocks/screener?exchange=nasdaq&letter=0&render=download
에서 이를 확인할 수 있다.

3. 네이버 종목 토론방 스크래핑

options = webdriver.ChromeOptions()
browser = webdriver.Chrome('C:/data/chromedriver.exe', options=options) #selenium 실행
data = pd.read_csv('C:/Users/apjh2/공모전/나스닥_50.csv')
ticker = data['Symbol'] #NASDAQ 사이트에서 다운로드 받은 CSV에서 'Symbol' 컬럼을 사용하여 ticker 데이터프레임에 포함

이렇게 하여 Selenium을 실행시키고, 종목 토론방 URL에 들어갈 'symbol' 또한 로딩이 완료되었다. 이제 스크래핑을 할 차례

stop_date = ('2022/01/01') #크롤링 기간 설정
formatted_date2 = time.strptime(stop_date, "%Y/%m/%d")
for tick in ticker:
    titles = []
    comments = []
    종목 = []
    dates = []
    df = pd.DataFrame()
    browser.get('https://m.stock.naver.com/worldstock/stock/{}.O/discuss'.format(tick))
    time.sleep(0.5)
    SCROLL_PAUSE_SEC = 0.5
    last_height = browser.execute_script("return document.body.scrollHeight")         

    while True:
        # 해당 페이지를 '더보기' 버튼이 나올 때까지 스크롤 다운                      
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")

        time.sleep(SCROLL_PAUSE_SEC)                                          
        browser.execute_script("window.scrollTo(0, document.body.scrollHeight-50);")
        time.sleep(SCROLL_PAUSE_SEC)
        # Calculate new scroll height and compare with last scroll height            
        new_height = browser.execute_script("return document.body.scrollHeight")
        try: #더보기 버튼이 있으면 클릭하고, 없으면 더 보기 버튼이 없음을 출력
            element = browser.find_element_by_xpath('//*[@id="content"]/div[7]/a')
            browser.execute_script("arguments[0].click();", element)
            time.sleep(SCROLL_PAUSE_SEC)
        except NoSuchElementException:
            print(tick,': 더 보기 없음')
            break
        html = browser.page_source
        soup = BeautifulSoup(html.decode('euc-kr'),'html.parser') #해당 html를 euc-kr로 디코딩할 것을 지정
        final = browser.find_elements_by_class_name('DiscussListItem_info__23BlI')
        final_date = final[-1].text
        final_date = re.search('\n(.+?)\n', final_date).group(1)
        final_date =final_date.replace('.','/')
        final_date = final_date.rstrip('/')
        formatted_date1 = time.strptime(final_date, "%Y/%m/%d") #날짜 비교를 위해 맨 마지막 댓글의 날짜를 YY-MM-DD의 형태로 변환
        if formatted_date1 < formatted_date2:
            try: #종료 날짜보다 맨 마지막 댓글의 날짜가 더 옛날 것이면, 모든 제목과 댓글을 데이터프레임에 저장
                data_html = soup.find('ul',{'class':'DiscussList_listDiscuss__3AaMp listDiscussCard'}).find_all('li',{'class':'DiscussListItem_item__2W_lB'})
                for i in range(len(data_html)):
                    titles_1 = remove_html(str(data_html[i].find('strong')))
                    comments_1 = remove_html(str(data_html[i].find('p')))
                    titles.append(titles_1)
                    comments.append(comments_1)
                    df_1 = pd.DataFrame(titles)
                    df_2 = pd.DataFrame(comments)
            except AttributeError as e:
                    print(e)
            result = pd.concat([df_1,df_2],axis=1,ignore_index = True)
            result.to_csv('C:/Users/apjh2/공모전/나스닥_50/{}.csv'.format(tick))
            #나스닥_50 폴더에 Symbol 이름으로 csv로 저장
            print("총 ", i, "개 댓글 수집 완료 ", tick,':저장 완료')
            break

        last_height = new_height

해당 코딩 실행 결과, 모든 주식에 대한 스크래핑 결과가 알맞게 저장된 것을 알 수 있다.

[그림3. 스크래핑 코드 실행 결과]

좋은 웹페이지 즐겨찾기