AI/정책 댓글 반응 NLP

[1] 네이버 뉴스 댓글 크롤러_ver1_4. 데이터 저장 및 마무리

eraser 2020. 4. 1. 06:16
반응형

 

 이번 단계의 작업에서는 크롤러를 통해 뉴스 기사 댓글을 스크레이핑하고, 그것을 저장하는 함수를 만든다. 작업을 통해 얻고자 하는 결과물은 크롤러가 직접 네이버 뉴스 홈에서 '주52시간'을 검색하여 찾아낸 마지막 페이지 범위까지의 기사들 중, 네이버 뉴스 플랫폼에 등록된 모든 기사들에서 스크레이핑한 플랫폼 정보(NAVER), 기사 제목, 기사 작성 시간, 언론사, 댓글 작성자, 댓글 작성 시간, 댓글 내용, 댓글 공감/비공감 수이다.

 


# 사용한 라이브러리

 

  • RequestsSelenium, time, BeautifulSoup, urllib.parse, re : 이전과 동일.
  • csv

 

 

# csv 파일로 저장하기

 

 csv 모듈을 이용해 csv 파일로 저장하는 함수를 만든다.

 


 아래 함수는 리스트를 인자로 받아 리스트의 각 요소들을 csv 파일의 한 행으로 쓴다.

 

def save_to_file(lst):
    file = open("news_comments_NAVER.csv", mode="w", encoding="UTF-8")
    writer = csv.writer(file)
    writer.writerow(['site', 'title', 'article_time', 'press', 'total_comments', 'reply_contents'])
    for result in lst:
        writer.writerow(list(result.values()))
    file.close()
    return

 


# 크롤러를 통해 정보 저장하기

 

 위의 모든 과정을 정리하면 다음과 같다.

 

 

# module import
import requests
from urllib.parse import urlparse
from bs4 import BeautifulSoup
import re
from selenium import webdriver
import time
import numpy as np
import csv

# 변수 설정
QUERY = "주52시간"
search_QUERY = urllib.parse.urlencode({'query':QUERY}, encoding='utf-8')
URL = f"https://search.naver.com/search.naver?&where=news&{search_QUERY}\
        &sm=tab_pge&sort=0&photo=0&field=0&reporter_article=&pd=0&ds=&de=&docid=&nso=so:r,p:all,a:all&mynews=0"
LINK_PAT = "https:\/\/news\.naver\.com\/main\/read\.nhn\?"

# driver 설정
driver = webdriver.Chrome("D:\python_DA\chromedriver.exe")

# 마지막 페이지 호출 : 나중에 변경 방법 생각해 보기
def get_last_page():
    req = requests.get(URL)
    soup = BeautifulSoup(req.text, 'lxml')
    pagination = soup.find('div', {'class' : 'paging'})
    pages = pagination.find_all("a")
    page_list = []
    for page in pages[1:-1]:
        page_list.append(int(page.get_text(strip = True)))
    max_page = page_list[-1]
    return max_page

# 검색결과 내 링크 찾기 : news.naver.com으로 시작하는 모든 링크 반환
def get_news_links(page_num, link_pattern):
    links = []
    for page in range(page_num):
        print(f"Scrapping page : {page+1}") # 확인용
        req = requests.get(f"{URL}&start={10*page+1}"); print(req.status_code)
        soup = BeautifulSoup(req.text, 'lxml')
        results = soup.find_all('a', {'href' : re.compile(link_pattern)})
        for result in results:
            links.append(result['href'])
    print(f"총 {len(links)}개의 뉴스 링크를 찾았습니다.") # 확인용
    return links
   

# 한 페이지 별로 필요한 정보 스크레이핑
def extract_info(url, wait_time=1, delay_time=0.3):
    
    driver.implicitly_wait(wait_time)
    driver.get(url)
    
    # 댓글 창 있으면 다 내리기
    while True:
        try:
            more_comments = driver.find_element_by_css_selector('a.u_cbox_btn_more')
            more_comments.click()
            time.sleep(delay_time)
        except:
            break
    
    # html 페이지 읽어오기
    html = driver.page_source
    soup = BeautifulSoup(html, 'lxml')       
        
    # 출처
    site = soup.find('h1').find("span").get_text(strip=True)
    # 기사 제목
    title = soup.find('h3', {'id':'articleTitle'}).get_text(strip=True)
    # 작성 시간
    article_time = soup.find('span', {'class':'t11'}).get_text(strip=True)
    # 언론사
    press = soup.find('div', {'class':"press_logo"}).find('a').find('img')['title']
    
    # 댓글 수
    total_com = soup.find("span", {"class" : "u_cbox_info_txt"}).get_text()
    
    # 댓글 작성자
    nicks = soup.find_all("span", {"class":"u_cbox_nick"})
    nicks = [nick.text for nick in nicks]
    
    # 댓글 날짜
    dates = soup.find_all("span", {"class":"u_cbox_date"})
    dates = [date.text for date in dates]
    
    # 댓글 내용
    contents = soup.find_all("span", {"class":"u_cbox_contents"})
    contents = [content.text for content in contents]
    
    # 공감 수
    recomms = soup.find_all("em", {"class":"u_cbox_cnt_recomm"})
    recomms = [recomm.text for recomm in recomms]
    
    # u_cbox_cnt_unrecomm
    unrecomms = soup.find_all("em", {"class":"u_cbox_cnt_unrecomm"})
    unrecomms = [unrecomm.text for unrecomm in unrecomms]    
    
    # 취합
    # replys = list(zip(nicks, dates, contents)) # tuple형태
    reply = []
    for i in range(len(contents)):
        reply.append({'nickname':nicks[i],
                      'date':dates[i],
                      'contents':contents[i],
                      'recomm':recomms[i],
                      'unrecomm':unrecomms[i]})
    print("완료") # 확인용
    return {'site':site, 'title':title, 'article_time':article_time, 'press':press, 'total_comments':total_com, 'reply_content':reply}

# 각 페이지 돌면서 스크레이핑
def extract_contents(links):
    contents = []
    for link in links:
        content = extract_info(f"{link}&m_view=1") # 각각의 링크에 대해 extract_info 함수 호출
        contents.append(content) # extract_info의 결과로 나오는 dict 저장
    return contents


# main 함수
def main():
    last_page = get_last_page()  # 마지막 페이지
    news_links = get_news_links(last_page, LINK_PAT) 
    result = extract_comments(news_links)
    driver.quit()
    return result

# 출력 결과 저장 함수
def save_to_file(lst):
    file = open("news_comments_NAVER.csv", mode="w", encoding="UTF-8")
    writer = csv.writer(file)
    writer.writerow(['site', 'title', 'article_time', 'press', 'total_comments', 'contents'])
    for result in lst:
        writer.writerow(list(result.values()))
    file.close()
    return

# 함수 실행
NAVER_RESULT = main()
save_to_file(NAVER_RESULT)

 


 

 그 결과 다음과 같이 '주52시간'으로 검색했을 때 나오는 기사 1페이지부터 10페이지까지의 모든 정보들을 저장했다.

news_comments_NAVER.csv
2.17MB

 

 

 

반응형