[Crawling] 특정한 날짜 간격으로 Naver VIEW (Blog, Cafe) 크롤링하기

[Crawling] 특정한 날짜 간격으로 Naver VIEW (Blog, Cafe) 크롤링하기

2021, Dec 04    


Crawling Code


from selenium import webdriver as wd        
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup
import re
import datetime as dt
import urllib.parse             
import time


def extract_text(posts):            # regex 로 유효한 텍스트만 정제
    tagout = re.compile('<.*?>')
    unicodeout = re.compile(r'"[\\u]%d{4,5}"')
    ps = []
    for p in posts:
        p = re.sub(tagout, "", str(p))
        p = re.sub(unicodeout, "", p)
        p = re.sub(r"[^ㄱ-ㅎㅏ-ㅣ가-힣 ]", "", p)
        ps.append(p)
    return ps


def get_posts(url, startdate):
    driver.get(url)
    time.sleep(5)

    html = driver.page_source
    soup = BeautifulSoup(html,'html.parser')
    last_height = driver.execute_script("return document.body.scrollHeight")
    
    weekly_post = []
    weeklyfreq = 0
    posts = []

    tmp = soup.find_all("a", {'class' : "api_txt_lines total_tit _cross_trigger"})
    posts += extract_text(tmp)
    weeklyfreq += len(tmp)

    tmp = soup.find_all("div",  {'class' : "total_group"})
    posts += extract_text(tmp)
    weeklyfreq += len(tmp)

    while True:
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
            time.sleep(1.5)
            new_height = driver.execute_script("return document.body.scrollHeight")

            if new_height != last_height:
                html = driver.page_source
                soup = BeautifulSoup(html,'html.parser')
                
                tmp = soup.find_all("a", {'class' : "api_txt_lines total_tit _cross_trigger"})
                posts += extract_text(tmp)
                weeklyfreq += len(tmp)

                tmp = soup.find_all("div",  {'class' : "total_group"})
                posts += extract_text(tmp)
                weeklyfreq += len(tmp)
            else:                                   # 일별로 검색 후 끝까지 scroll 다 내림
                weekly_post.append([startdate, weeklyfreq, posts])
                break

            last_height = new_height
    
    return weekly_post


def createDF(contents, keyword, tag):
    import pandas as pd
    df = pd.DataFrame(contents, columns=['Date', 'Weekly Frequency', 'Tweets'])
    df.to_excel("NAVER_" + keyword + "_" + str(tag) + ".xlsx")


if __name__ == "__main__":

    driver = wd.Chrome("chromedriver.exe")
    keywords = ["코로나, 감정", "코로나, 기분", "코로나, 일상"]      # 크롤링 키워드
    years = [2020, 2021]        # 크롤링하고자 하는 년도

    for keyword in keywords:
            for year in years:
                contents = []
                if year == 2020: limit = 13
                elif year == 2021: limit = 11
                for m in range(1, limit):
                    i = m
                    if len(str(m)) == 1: m = str(0) + str(m)      # 20210607 이런 형식으로 날짜 입력해줘야 함
                    base = str(year) + str(m)
                    startdate = base + "01"
                    
                    for d in ["07", "14", "21", "28"]:      # 7일 간격으로
                        middate = base + d
                        url = f"https://search.naver.com/search.naver?where=view&query={keyword}&sm=tab_opt&nso=so%3Ar%2Cp%3Afrom{startdate}to{middate}%2Ca%3Aall&mode=normal&main_q=&st_coll=&topic_r_cat="
                        contents += get_posts(url, startdate)
                        startdate = middate
                        # print(i)
                        
                    if i == 6 or i == limit-1:
                        if i == 6: add = "_상반기"
                        elif i == limit-1: add = "_하반기"
                        tag = str(year) + "년" + add
                        createDF(contents, keyword, tag)
                        contents = []


  • html class 가 꽤나 자주 변경되는 거 같으니 find_all 을 사용할 때 원하는 요소의 html class 를 잘 확인해봐야 한다.
  • 검색 결과로 나온 게시글들 전문을 가져오려면 시간이 너무 오래 걸릴 거 같아 포스팅 창을 열지않고 제목, 미리보기로 노출되는 부분만 가져왔다.