김건

Merge branch 'naverNews' into 'master'

Naver news

Naver News 크롤링 결과

See merge request !2
1. Data 받아오기
1) selenuim을 이용하여 웹페이지에서 데이터를 검색
2) 원하는 URL 입력받는다
3) headless하게 구현하기 위해 chrome option 적용하여 driver 생성
4) naverNews는 댓글 영역 하단 부 '더보기'를 지속적으로 눌러줘야하므로
driver의 find_element_by_css_selector함수로 해당 class인
u_cbox_btn_more을 페이지가 끝날 때까지 돌림
5) 위의 과정에서 얻은 페이지 소스를 beautifulSoup을 이용하여, find_all을 통해 {사용자ID, 댓글, 작성시간}의 데이터를 각각 raw하게 뽑음. (naverNews의 제한적인 특징으로 사용자ID 뒤 4자리는 비공개처리됨)
2. 사용할 DataSet으로 가공
1) 리스트 형태로 각각 nicknames(사용자ID), comments(댓글), times(작성시간)을 뽑아냄
2) 세 리스트에서 짝을 이루는 쌍을 dictionary형태로 {사용자ID, 댓글, 작성시간} 다음과 같이 저장
3) 저장된 dictionary list(info_dic)을 최종 결과 리스트인 naverNewsList에 저장한다.
3. 함수 구현
1) KEYWORD 기반 검색 기능
2) 가장 자주 나온 단어 검색 기능
3) ID 기반 검색 기능
4) 시간 대별 검색 기능
등 여러 함수 구현 예정
=> 수정사항
data를 get하여 정제하는 파일을 모듈로 분리해 내어 list형태로 저장된 데이터셋을 반환하여
main 에서 사용할 수 있도록 한다. 이 후 main에서 리스트를 받아와 url을 입력받아 데이터를
받아오는 방식으로 사용한다. 이 후, keyword기반, id기반, 시간대 기반 검색 함수를 구현하였고
시간대별 검색 함수의 기능 보강과 가장 자주 나온 단어 검색 기능을 추가 구현할 예정이다.
* 4차 수정사항
기존파일의 분리 관리 시, import관련 오류 문제 해결 완료(하나의 파일로 관리)
사용자 UI의 틀을 구축해놓았고, 곧바로 함수별 추가 세부 구현 예정
* 5차 수정사항
1) 네이버 댓글공간엑서 받아온 날짜 정보를 YYYY-MM-DD형식으로 바꿈. ('방금 전, 몇 분 전, 몇 시간 전, 몇 일 전'의 경우를 처리하기 위해 dateTime과 timeDelta 모듈을 활용하여
현재 날짜를 기준으로 계산하여 YYYY-MM-DD로 저장될 수 있도록
코드 추가)
2) 시간대별로 (시작시간, 끝시간)을 입력하여 그 시간에 해당하는 기사를 출력해주는 함수 구현
가장 자주 많이 나온 단어 검색과 MATPLOTLIB을 활용한 시각적 표현 구현 예정
* 6차 수정사항
konlpy를 활용한 명사 추출 및 단어 빈도수가 많으 순대로 사용자가 입력한 limit만큼 출력해주는 함수 구현 완료
\ No newline at end of file
from selenium import webdriver
from selenium.common import exceptions
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
from konlpy.tag import Twitter
from collections import Counter
import time
def getData(url):
## chrome option걸기 (headless하게 웹 크롤링 수행하기 위해<웹페이지 안보이게 하기>)
options = webdriver.ChromeOptions()
#options.add_argument('headless')
#options.add_argument("disable-gpu")
#_url = "https://entertain.naver.com/ranking/comment/list?oid=144&aid=0000642175" # 크롤링할 URL
_url = url # 크롤링할 URL
webDriver = "C:\\Users\\user\\Desktop\\chromedriver_win32\\chromedriver.exe" # 내 웹드라이버 위치
driver = webdriver.Chrome(webDriver,chrome_options=options)
#driver = webdriver.Chrome(webDriver)
driver.get(_url)
pageCnt = 0
driver.implicitly_wait(3) # 페이지가 다 로드 될때까지 기다리게함
try:
while True: # 댓글 페이지 끝날때까지 돌림
#driver의 find_element_by_css_selector함수로 '네이버 뉴스'의 댓글 '더보기' 버튼을 찾아서 계속 클릭해준다(끝까지)
driver.find_element_by_css_selector(".u_cbox_btn_more").click()
pageCnt = pageCnt+1
except exceptions.ElementNotVisibleException as e: # 페이지가 끝남
pass
except Exception as e: # 다른 예외 발생시 확인
print(e)
pageSource = driver.page_source # 페이지 소스를 따와서
result = BeautifulSoup(pageSource, "lxml") # 빠르게 뽑아오기 위해 lxml 사용
# nickname, text, time을 raw하게 뽑아온다
comments_raw = result.find_all("span", {"class" : "u_cbox_contents"})
nicknames_raw = result.find_all("span", {"class" : "u_cbox_nick"})
times_raw = result.find_all("span", {"class" : "u_cbox_date"})
# nickname, text, time 값 만을 뽑아내어 리스트로 정리한다
comments = [comment.text for comment in comments_raw]
nicknames = [nickname.text for nickname in nicknames_raw]
times = [time.text for time in times_raw]
naverNewsList = []
for i in range(len(comments)):
info_dic = {'userID' : nicknames[i], 'comment' : comments[i], 'time' : times[i]}
naverNewsList.append(info_dic)
return naverNewsList
#driver.quit()
from time import sleep
def print_cList(c_List) :
for item in c_List :
print(item)
def search_by_author(c_List,user_ID) :
result_List = []
for item in c_List :
#print(item['userID'])
if ( user_ID in item['userID']) :
result_List.append(item)
return result_List
def search_by_keyword(c_List,keyword) :
result_List = []
for item in c_List :
#print(item['comment'])
if ( keyword in item['comment']) :
result_List.append(item)
return result_List
def refine_time(c_List): # 시간에서 몇일 전, 몇 분 전, 방금 전 등의 형태를 YYYY.MM.DD로 바꿔준다
now = datetime.now()
for item in c_List:
if (item['time'].find('전') != -1): # ~~전이 있으면
if (item['time'].find('일 전') != -1): # ~일 전이라면
_day = -(int)(item['time'][0]) # 몇 일전인지에 대한 정수형 변수
tempTime = now + timedelta(days=_day)
item['time'] = str(tempTime)
item['time'] = item['time'][0:10]
continue
elif (item['time'].find('시간 전') != -1):
_index = item['time'].index('시')
_time = -(int)(item['time'][0:_index]) # 몇 시간 전인지에 대한 정수형 변수
tempTime = now + timedelta(hours = _time)
item['time'] = str(tempTime)
item['time'] = item['time'][0:10]
continue
elif (item['time'].find('분 전') != -1):
_index = item['time'].index('분')
_minute = -(int)(item['time'][0:_index]) # 몇 분 전인지에 대한 정수형 변수
tempTime = now + timedelta(minutes = _minute)
item['time'] = str(tempTime)
item['time'] = item['time'][0:10]
continue
elif (item['time'].find('방금 전') != -1):
tempTime = now
item['time'] = str(tempTime)
item['time'] = item['time'][0:10]
continue
else:
item['time'] = item['time'][0:10]
continue
def search_by_time(c_List,startTime, endTime) :
result_List = []
startYear = int(startTime[0:4])
if (int(startTime[5]) == 0): # 한자리의 월일 때
startMonth = int(startTime[6])
else:
startMonth = int(startTime[5:7])
if (int(startTime[8]) == 0): # 한자리의 일일 때
startDay = int(startTime[9])
else:
startDay = int(startTime[8:10])
endYear = int(endTime[0:4])
if (int(endTime[5]) == 0): # 한자리의 월일 때
endMonth = int(endTime[6])
else:
endMonth = int(endTime[5:7])
if (int(endTime[8]) == 0): # 한자리의 일일 때
endDay = int(endTime[9])
else:
endDay = int(endTime[8:10])
for item in c_List:
itemYear = int(item['time'][0:4])
if (int(item['time'][5]) == 0): # 한자리의 월일 때
itemMonth = int(item['time'][6])
else:
itemMonth = int(item['time'][5:7])
if (int(item['time'][8]) == 0): # 한자리의 일일 때
itemDay = int(item['time'][9])
else:
itemDay = int(item['time'][8:10])
if (itemYear >= startYear and itemYear <= endYear):
if (itemMonth >= startMonth and itemMonth <= endMonth):
if(itemDay >= startDay and itemDay <= endDay):
result_List.append(item)
return result_List
def printMostShowed(c_List,limit):
temp = ""
result = ""
for item in c_List:
temp = str(item['comment']) + " "
result = result + temp
sp = Twitter()
nouns = sp.nouns(result)
_cnt = Counter(nouns)
tempList = []
repCnt = 0
for i,j in _cnt.most_common(limit):
print(str(repCnt+1)+'. '+str(i)+" : "+str(j))
repCnt += 1
def printResult(c_List):
for i in range(0,len(c_List)):
print(c_List[i])
def main ():
## 시작화면
_star = '*'
print(_star.center(30,'*'))
print('\n')
headString = '< Naver News Crawling >'
print(headString.center(30,'*'))
print('\n')
print(_star.center(30,'*'))
# 검색하고자 하는 url을 입력받는다
_url = input('검색하고자 하는 url을 입력해주세요: ')
print('comment_list를 가져오는 중.....')
cList = getData(_url)
refine_time(cList)
#printMostShowed(cList,10)
print('\n')
print('comment_list를 다 가져왔습니다!')
while(True):
print('***********************************')
print('1.닉네임 기반 검색')
print('2.키워드 기반 검색')
print('3.작성시간 기반 검색')
print('4.자주 나타난 단어 출력')
menu = input('메뉴를 입력해주세요: ')
if(menu == str(1)):
print('***********************************')
inputID = input('검색할 닉네임 앞 4자리를 입력해주세요(전 단계로 가시려면 -1을 입력해주세요): ')
if(inputID == str(-1)):
continue
_result = search_by_author(cList,inputID)
printResult(_result)
print(_result)
elif(menu == str(2)):
print('***********************************')
inputKW = input('검색할 키워드를 입력해주세요(전 단계로 가시려면 -1을 입력해주세요): ')
if(inputKW == str(-1)):
continue
_result = search_by_keyword(cList,inputKW)
printResult(_result)
elif(menu == str(3)):
print('***********************************')
print('전 단계로 돌아가시려면 -1을 입력해주세요')
startTime = input('검색할 시간대의 시작일을 입력해주세요(YYYY-MM-DD): ')
endTime = input('검색할 시간대의 마지막 일을 입력해주세요(YYYY-MM-DD): ')
if(startTime == str(-1) or endTime == str(-1)):
continue
_result = search_by_time(cList,startTime,endTime)
printResult(_result)
elif(menu == str(4)):
print('***********************************')
inputLimit = input('상위 몇 개 까지 보고 싶은지 입력하세요(1~20): ')
while(True):
if (int(inputLimit) <= 0 or int(inputLimit) > 20):
inputLimit = input('상위 몇 개 까지 보고 싶은지 입력하세요(1~20): ')
else:
break
printMostShowed(cList,int(inputLimit))
else:
print('잘못된 입력입니다')
continue
main()