파이썬 python

selenium을 이용한 네이버 뉴스 날짜별 크롤링

Aytekin 2021. 12. 20. 22:18
728x90

이번 블로그에서는 selenium을 이용해서 네이버 뉴스를 날짜별로 스크레이핑 하는 방법을 포스팅해보겠습니다~

 

참고로 아래의 링크에 들어가시면 네이버 자체적으로 제공하는 api를 이용할 수 있습니다.

그런데 제가 찾았을때는 뉴스를 날짜별로 긁어올 수 있는 api는 없는것 같더라구요 ㅠㅠ 그래서 이번 기회에 공부도 하고 연습도 해볼겸 네이버 뉴스를 스크래핑 해보았습니다.

https://developers.naver.com/main/


1. selenium을 이용해서 코로나를 검색한 네이버뉴스창 띄우기.

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome('driver\chromedriver')

#코로나로 검색
driver.get('https://search.naver.com/search.naver?query=%EC%BD%94%EB%A1%9C%EB%82%98&where=news&ie=utf8&sm=nws_hty')

# 옵션 클릭.
elem_option = driver.find_element_by_xpath('//*[@id="snb"]/div[1]/div/div[2]/a')
elem_option.send_keys('\n')
elem_option.send_keys(Keys.ENTER)

# # 직접입력 클릭.
elem_input = driver.find_element_by_xpath('//*[@id="snb"]/div[2]/ul/li[2]/div/div[1]/a[9]')
elem_input.send_keys('\n')

naver_news_link = []

위의 코드를 실행시키면 아래 스크린샷처럼 네이버뉴스 페이지에서 [옵션클릭 -> 직접입력 클릭]이 된 상태까지 진행이 됩니다.

 

참고로 셀레니움 웹 드라이버를 사용할 땐 웹 드라이버가 저장되어 있는 위치를 인자로 전달해주어야 실행이 됩니다.

드라이버의 get매서드는 인자로 받은 페이지주소를 띄워줍니다. 저는 처음부터 코로나를 검색한 페이지 주소를 복붙해서 바로 띄워버렸습니다 ㅎㅎㅎ

 

그리고 html에서 원하는 class나 element를 찾기위해서는 여러가지 메서드가 있지만 개인적으로 저는 'find_element_by_xpath'가 가장 편해서 이 매서드를 사용하였습니다.

원하는 부분의 xpath 주소는 원하는 창에서 [F12]를 누르면 나오는 개발자 창에서 우클릭하고 [copy -> copy full xpath]를 클릭하면 손쉽게 얻을 수 있습니다!

 

selenium의 click()이 우리가 웹 브라우저를 쓸 때의 그 클릭을 해주는데 이 클릭으로 안되서 send_keys('/n') 혹은 send_keys(Keys.ENTER)를 사용해서 옵션들을 선택해주었습니다.

아마도 자바스크립트랑 연관되어 있는 내용인것 같은데 제가 이쪽은 잘 모르기에 빠르게 구글링한 후 되는거 확인하고 미련없이 다음 단계로 넘어갔습니다 ㅎㅎ

 

마지막 naver_news_link 는 나중에 긁어온 뉴스 링크들을 저장해둘 리스트입니다.

 

 

2. 코로나와 관련된 날짜별 네이버뉴스의 링크 긁어오기

def select_date_naver_news(year,month,day):

    '''네이버뉴스에서 원하는 날짜의 뉴스를 검색해서 네이버뉴스 링크를 리스트로 return.'''
    
    # 연(year) 클릭하기
    elem_year = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[1]/div/div/div/ul/li[{year-1989}]')
    elem_year.click()

    # 월(month) 클릭하기
    elem_month = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[2]/div/div/div/ul/li[{month}]')
    elem_month.click()

    # # 날짜(day) 클릭하기
    elem_day = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[3]/div/div/div/ul/li[{day}]')
    elem_day.click()

    # 끝나는 날짜 클릭하기
    driver.find_element_by_xpath('//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[1]/span[3]/a').click()

    # 연(year) 클릭하기
    elem_year = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[1]/div/div/div/ul/li[{year-1989}]')
    elem_year.click()

    # 월(month) 클릭하기
    elem_month = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[2]/div/div/div/ul/li[{month}]')
    elem_month.click()

    # # 날짜(day) 클릭하기
    elem_day = driver.find_element_by_xpath(f'//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[2]/div[3]/div/div/div/ul/li[{day}]')
    elem_day.click()

    # 적용 클릭
    driver.find_element_by_xpath('//*[@id="snb"]/div[2]/ul/li[2]/div/div[3]/div[3]/button').click()

    naver_news_link = driver.find_elements_by_link_text('네이버뉴스')
    links = [link.get_attribute('href') for link in naver_news_link]

    # 옵션 초기화 버튼 클릭 
    driver.find_element_by_xpath('//*[@id="snb"]/div[2]/ul/li[6]/div/div/a[1]').click()
    
    time.sleep(2)

    # 직접입력 클릭.
    elem_input = driver.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div[1]/div[2]/ul/li[2]/div/div[1]/a[9]')
    elem_input.send_keys(Keys.ENTER)
    
    return links

이 부분은 네이버뉴스 링크들을 긁어오는 함수입니다.

원하는 연,월,날짜를 클릭해주는 부분을 만들어주고 get_attribute('href')를 통해서 링크만 긁어온 뒤 다시 옵션 초기화해서 다음 날짜에서 다시 링크를 긁어올 수 있도록 짜보았습니다.

 

옵션 초기화를 한 뒤에 페이지가 로딩되는 시간이 필요한데 이 시간을 벌어주기 위해서 파이썬의 time.sleep이라는 함수를 사용했습니다.

처음에 이부분을 모르고 삽질을 열심히 하다 우연히 발견하게 되었습니다...하핳..

 

긁어온 링크들은 리스트에 차곡차곡 저장이 될 겁니다!!

# 2020년 1월부터 ~ 2021 11월 현재까지 2년치 네이버 뉴스데이터 기사 크롤링
for year in tqdm(range(2020,2022),desc='preprocessing year'):
    for month in tqdm(range(1,13),desc='preprocessing month'):
        for day in tqdm(range(1,32),desc='preprocessing day'):
            try:
                res = select_date_naver_news(year=year,month=month,day=day)
                naver_news_link.append(res)
            except:
                pass

이 부분은 2020년 1월부터 2021년 11월까지 크롤링 하는 부분입니다.

날짜는 대충 이정도부터 긁어와봤습니다. 

 

3. 긁어온 링크들을 하나하나 들어가면서 뉴스 기사 스크레이핑하기

#  가상 크롬 드라이버를 불러옴
driver = webdriver.Chrome("driver/chromedriver")

naver_news_title = []
naver_news_content = []

for n in tqdm(range(len(naver_news_link)),desc='preprocessing'):
    news_page_title = []
    news_page_content = []

    for idx in range(len(naver_news_link[n])):
        
        ######## 긇어온 URL로 접속하기 ########
        try:
            driver.get(naver_news_link[n][idx])
        except:
            print("Time Out!")
            continue

        ######## 접속한 URL에서 page_source받아오기 ########
        try:
            response = driver.page_source
        except UnexpectedAlertPresentException:
            driver.switch_to_alert().alert()
            print("게시글이 삭제된 경우입니다.")
            continue
        soup = BeautifulSoup(response,'html.parser')

        ##### 뉴스 타이틀 긇어오기 #####
        title = None
        try:
            item = soup.find('div',class_='article_info')
            title = item.find('h3', class_='tts_head').get_text()
        except:
            title = "OUT_LINK"
        
        news_page_title.append(title)

        ###### 뉴스 본문 긇어오기 #####
        doc = None
        text = ''

        data = soup.find_all("div",{"class":"_article_body_contents"})
        if data:
            for item in data:
                if item.find('script',type='text/javascript'):
                    item.find('script',type='text/javascript').decompose()
                elif item.find('span','end_photo_org'):
                    item.find('span','end_photo_org').decompose()
                text = item.get_text()
                doc = ''.join(text)
        else:
            doc = "OUT_LINK"

        news_page_content.append(doc.replace('\n',' '))

    naver_news_title.append(news_page_title)
    naver_news_content.append(news_page_content)

    time.sleep(2)

이 부분이 실제적으로 네이버 뉴스 기사들을 긁어오는 부분입니다.

나중에 따로 사용할 수 있어서 제목(title)과 본문(content)를 따로 저장해주었습니다.

 

여기에서도 마찬가지로 time.sleep을 주어서 웹 페이지가 중간중간 로딩되는 시간들을 벌어줘야 합니다.

 

4. 긁어온 네이버 뉴스 기사들 pickle파일로 저장하기

import pickle

# 크롤링된 결과 저장
with open("data\kr_naver_news_title.pk",'wb') as f:
    pickle.dump(naver_news_title,f)
with open("data\kr_naver_news_content.pk",'wb') as f:
    pickle.dump(naver_news_content,f)

pickle을 이용해서 크롤링한 뉴스들을 저장해두었다.

왜냐? 2년치 긁어오는데 3시간정도 걸린것같다 ㅎㅎ

매번 크롤링을 할 수는 없으니 저장을 해두고 바로바로 이용하기 위해서 ㅎㅎㅎ

 


개인적으로 하고싶은 프로젝트가 있어서 네이버뉴스 데이터가 필요했습니다.

위에서 말씀드렸지만 네이버 api가 있어서 웬만한 크롤링은 편하게 할 수 있지만 날짜별로 뉴스 기사들을 긁어오는 방법은 없는듯 하여 크롤링 공부도 해볼겸 크롤링해보고 기록하기 위해서 포스팅도 해보았습니다.

 

코딩 시작한지 얼마 안된 정말 초보중에 초보입니다!

막 코딩한걸 올리기가 정말 민망하기도 합니다..ㅎㅎ

부족한 실력이지만 필요한 분들이 계시고 또 참고가 될 수 있다면 너무나 기분이 좋을 것 같습니다.

읽어주셔서 감사합니다.

728x90