tak's data blog

네이버 뉴스댓글 어뷰징분석 (1)크롤링 본문

프로젝트/네이버 뉴스댓글 어뷰징 분석

네이버 뉴스댓글 어뷰징분석 (1)크롤링

hyuntaek 2024. 1. 13. 15:58
반응형
SMALL

 

주의 사항: 어뷰저라고 정의하는 방법이나 분석 방향 등은 순전히 작성자만의 생각이고  Naver는 전혀 상관없다고 말씀드리고 싶습니다. Naver는 편향성을 가지지 않는 중립적인 플랫폼입니다.

 

 

0. 문제 정의

 

문득 뉴스, 웹툰, 게임 등 여러 매체들의 댓글을 보면 심상치 않은 상황들이 오고갑니다. 서로 시비를 걸며 싸우거나 각자의 생각을 주입하며 선동하기도 하고 또는 광고성 댓글로 댓글창을 어지럽히곤 합니다. 저는 이러한 상황에서 데이터분석으로 어뷰저를 판별해볼 수 있지 않을까?라는 물음을 가지게 되었습니다.

 

여기서 제가 정의하는 어뷰저란

1) 남에게 생각을 주입하는 등의 영향력을 끼칠 수 있는 댓글

2) 특정 광고성 댓글

3) 특정한 패턴을 보이는 댓글

이렇게 일반 댓글과는 다른 형태를 가지는 댓글들 이러한 댓글을 작성하는 유저들을 어뷰저라고 정의할 수 있다고 생각했습니다.

 

그래서 이러한 분석을 하기위해 네이버 뉴스 본문, 댓글의 크롤링을 진행하고 분석해보며 인사이트 발굴까지 나아가는 과정을 보여드리도록 하겠습니다.

 

 

1. 데이터 구조

2022년 1월1일 ~ 2024년 1월 10일까지의 네이버 랭킹뉴스 데이터

 

- 약 30,000여 개의 뉴스 데이터

- 70여 만개의 댓글 데이터

(더 많은 댓글을 수집하고 싶었지만 수집 시간+노트북의 여력으로 불가능했음)

 

 

2. 데이터 수집 방법

BeautifulSoup을 이용해서 데이터를 수집하였습니다. Selenium을 활용하게 된다면 동적 크롤링으로 시간이 배로 더 걸린다고 판단을 했기 때문에 정적크롤링을 주로 활용하였습니다.

 

 

2-1. 뉴스 제목 주소 등 기본정보 수집

별다른 설명 없이 바로 코드로 넘어가겠습니다. 다른 분들께서 이미 작성해주신 코드들이 다양해서 해당 코드를 기반으로 조금씩 고쳐서 수집하였습니다.

from tqdm import tqdm
import requests
from bs4 import BeautifulSoup

index = pd.date_range(start='20220101', end='20240110')
dt_list = index.strftime("%Y%m%d").tolist()
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36"}
newsData = []

for d in tqdm(dt_list):
    url = "https://news.naver.com/main/ranking/popularDay.naver?date=" + str(d)
    res = requests.get(url, headers=headers)
    soup = BeautifulSoup(res.text, 'lxml')
    newslist = soup.select(".rankingnews_list")
    # 언론사마다
    for news in newslist[:12]:
    # 5개의 상위랭킹 뉴스를 가져옴
        lis = news.findAll("li")
    # 5개 뉴스 데이터 수집
        for li in lis:
        # 뉴스랭킹
            news_ranking = li.select_one(".list_ranking_num").text
        # 뉴스링크와 제목
            list_title = li.select_one(".list_title")
            news_title = list_title.text
            news_link = list_title.get("href")
            type_ = re.sub(r"[^가-힣]", "", soup.find_all(class_='media_end_categorize_item')[-1])
            
            newsData.append({
            'ranking': news_ranking,
            'news_type': type_,
            'title': news_title,
            'link': news_link,
            'date':d})

수집 내용은 1)뉴스의 랭킹, 2)뉴스 타입, 3)제목, 4)주소, 5)작성날짜 입니다.

 

 

2-2. 뉴스별 댓글 및 통계정보 일부 수집

import requests
from bs4 import BeautifulSoup 
import pprint
import json
import re
import sys
from tqdm import tqdm

url_list = df['link'].values
dic2 = {}
dic = {}
List1 = []
List2 = []
List3 = []
List4 = []
List5 = []
List6 = []
List7 = []

for url in tqdm(url_list):
    res = requests.get(url)
    # oid&uid 네이버 뉴스의 고유값
    oid = url.split('/')[-2]
    aid = url.split('/')[-1][:-14]
    page = 1
    
    headers = {
    "referer": url,
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"}
    
 
    c_url = "https://apis.naver.com/commentBox/cbox/web_neo_list_jsonp.json?ticket=news&templateId=default_society&pool=cbox5&_callback=jQuery1707138182064460843_1523512042464&lang=ko&country=&objectId=news"+oid+"%2C"+aid+"&categoryId=&pageSize=20&indexSize=10&groupId=&listType=OBJECT&pageType=more&page="+str(page)+"&refresh=false&sort=FAVORITE"
    res = requests.get(c_url,headers=headers)
    cont = BeautifulSoup(res.content, 'html.parser')
    
    # 뉴스 댓글 내용
    match = re.findall('"contents":([^\*]*),"userIdNo"', str(cont)) 
    
    # 댓글 작성 user_id
    userIdNo = re.findall('"userIdNo":([^\*]*),"exposedUserIp"', str(cont))
    
    # 작성 시각
    modTime = re.findall('"modTime":([^\*]*),"modTimeGmt"', str(cont))
    
    # 댓글 공감수
    sympathyCount = re.findall('"sympathyCount":([^\*]*),"antipathyCount"', str(cont))
    
    # 댓글 비공감수
    antipathyCount = re.findall('"antipathyCount":([^\*]*),"hideReplyButton"', str(cont))
    
    # 답글수
    replyAllCount = re.findall('"replyAllCount":([^\*]*),"replyPreviewNo"', str(cont))
    
    List1.append(userIdNo)
    List2.append(match)
    List3.append(modTime)
    List4.append(sympathyCount)
    List5.append(antipathyCount)
    List6.append(replyAllCount)
        
    # 전체 댓글 수
    total_comments = int(re.sub(r'[^0-9]', '', str(cont).split('comment":')[1].split(",")[7]))
    List7.append(total_comments)
    
    dic['userIdNo'] = List1
    dic['match'] = List2
    dic['modTime'] = List3
    dic['sympathyCount'] = List4
    dic['antipathyCount'] = List5
    dic['replyAllCount'] = List6
    
    dic2[url] = dic
    
    dic = {}
    List1 = []
    List2 = []
    List3 = []
    List4 = []
    List5 = []
    List6 = []

 

 

 

이렇게 수집을 통해 완성된 데이터프레임 예시는 다음과 같습니다.

 

 

 

 

데이터수집 단계는 이정도로 마무리하겠습니다. 그리고 해당 내용들을 기반으로 한 분석은 현재 진행중이기 때문에 분석이 완료되는대로 올려보도록 하겠습니다.

 

 

 

참고 자료

https://drfirst.tistory.com/entry/%EB%84%A4%EC%9D%B4%EB%B2%84%EC%9D%98-%EB%8C%93%EA%B8%80-%EB%B0%8F-%EB%8C%93%EA%B8%80-%ED%86%B5%EA%B3%84%EC%A0%95%EB%B3%B4-%ED%81%AC%EB%A1%A4%EB%A7%81%ED%95%98%EA%B8%B0-Feat-python

https://domdom.tistory.com/633

https://wikidocs.net/151506

https://blog.naver.com/seodaeho91/221273565367

 

반응형
LIST