Data Engineering/Crawling

[Crawling] 네이버 OPEN-API를 이용한 네이버 뉴스 크롤링

YSY^ 2020. 8. 4. 17:20

네이버 OPEN-API를 이용하여 네이버 뉴스를 크롤링

이전 포스팅에서 신청했던 네이버 OPEN-API를 이용하여 네이버 뉴스를 크롤링해보겠습니다.

네이버 검색 API 호출 예제를 활용하였습니다.https://developers.naver.com/docs/search/blog/)

네이버 Open-API  코드 세팅

ID와 Password는 네이버 OPEN-API홈페이지에서 확인 가능합니다.

id = <본인의 ID>
pwd= <본인의 Password>
url = 'https://openapi.naver.com/v1/search/news.json?query={}'

검색할 키워드를 입력받습니다.

import requests
import pandas as pd
from pprint import pprint

keyword = input('검색 키워드:')

headers를 작성합니다. 네이버openapi의 아이디와 비밀번호가 들어갑니다.

# clientID,  client Secret -> 요청 header로 전송
headers = {
    'X-Naver-Client-Id':id,
    'X-Naver-Client-Secret':pwd
}

네이버의 출력 필드를 이용하여 크롤링한다. 크롤링할 것은 total과 items입니다.

items에는 링크와 내용, 작성일들이 담겨있습니다.

res = requests.get(url.format(keyword), headers=headers) 
if res.status_code == 200:
#     pprint(res.json())
    datas = res.json()
    print('총 검색 건수 : ', datas['total'])
    print(type(datas), type(datas['items']))
#     pprint(datas['items'])
    df = pd.DataFrame(datas['items'])
    df.to_csv('naver_{}_검색결과.csv'.format(keyword), encoding='utf-8', index=False)

#결과

네이버 뉴스링크 크롤링

%%writefile naver_search.py  #함수를 패키지화 할수 있음

import requests
import time
from datetime import datetime

def get_naver_news_search(keyword, start=1, display=100):
    """
    네이버 open api를 이용해 뉴스 키워드 검색
    뉴스 링크(네이버링크)들을 파일로 저장 (pickle이용)
    [매개변수]
        keyword: 검색키워드
        start: 검색 결과중 조회할 시작 번째 (1 ~ 1000)
        display: 한번에 가져올 개수 (1 ~ 100)
    """
#     id = 'Z7DcJLvd45bsnC9wdF7m'
#     pwd='EXxuxbALoq'
    base_url = 'https://openapi.naver.com/v1/search/news.json?query={}&start={}&display={}'
    headers = {
        'X-Naver-Client-Id':'Z7DcJLvd45bsnC9wdF7m',
        'X-Naver-Client-Secret':'EXxuxbALoq'
    }
    news_links = [] #검색 결과(링크)들 저장할 리스트

    while start <= 1000:
        url = base_url.format(keyword, start, display)
        # 요청
        res = requests.get(url, headers=headers)
        if res.status_code == 200:
            result = res.json()
            items = result['items']
            # 네이버 링크들을 추출
            for item in items:
                link = item['link']
                if 'news.naver.com' in link:
                    news_links.append(link)
            start = start + display
            time.sleep(0.15) 
            # 네이버 open api 요청은 초당 10회까지 호출가능하기 때문에 약간에 시간차를 둔다.
        else:
            raise Exception('검색 실패: {}'.format(res.status_code))

pickle을 이용하여 위의 크롤링 내역을 파일로 저장

    import pickle
    curr = datetime.now().strftime('%Y-%m-%d')
    filename = '네이버뉴스검색_{}_{}.pkl'.format(keyword, curr)
    with open(filename, 'wb') as f:
        pickle.dump(news_links, f)

네이버 뉴스 1개 크롤링함수

위에서 크롤링하여 저장한 뉴스링크를 이용한다.

  • url
    • news.naver.com 의 url 기사만 크롤링.
    • 연예: entertain.naver.com, 스포츠: sports.naver.com 는 제외한다.
  • selector
    • 제목: h3#articleTitle
    • 입력일: span.t11
    • 기사: div#articleBodyContents
# 네이버 뉴스 1개 크롤링함수
from bs4 import BeautifulSoup
import requests

def get_naver_news(url):
    """
    네이버뉴스 url을 받아서 제목, 입력일, 내용을 크롤링.
    연예/스포츠는 제외하고 조회.
    [매개변수]
        url: 네이버뉴스기사 url
    [반환값]
        tuple: 제목, 입력일, 뉴스내용
    [예외]
        Exception: 연예/스포츠 뉴스일 경우 발생.
    """
    # 요청
    res = requests.get(url)
#     print(res.url)
    if res.status_code == 200:
        # 응답을 받은 url - res.url
        if 'news.naver.com' not in res.url:
            raise Exception('{}은 요청할 수 없는 url입니다.'.format(res.url))

        soup = BeautifulSoup(res.text)
        title = soup.select_one('h3#articleTitle').text.strip()
        input_date = soup.select_one('span.t11').text.strip()
        article = soup.select_one('div#articleBodyContents').text.strip()
        # 간혹 flash오류가 발생하므로 이를 우회하기 위한 함수를 추가한다.
        article = article.replace('// flash 오류를 우회하기 위한 함수 추가\nfunction _flash_removeCallback() {}','')

        return title, input_date, article

    else:
        raise Exception("요청 실패: {}".format(res.status_code))

위의 함수를 이용하여 기사내용 크롤링

import pickle
import pandas as pd

with open('네이버뉴스검색_펭수_2020-07-24.pkl', 'rb') as f:
    l = pickle.load(f)

result = []
error_cnt = 0
for url in l:
    try:
        info = get_naver_news(url)
        result.append(info)
    except:
        error_cnt += 1

#파일로 저장
print('error_cnt: {}'.format(error_cnt))
df = pd.DataFrame(result, columns=['기사제목','입력일','기사내용'])
df.to_csv('news_articles.csv', index=False, encoding='utf-8')
print('종료')

#결과

728x90
반응형