네이버 API를 이용한 크롤링

leban·2022년 5월 8일
1

데이터분석

목록 보기
1/6

# 크롤링이란?

: 데이터를 수집하는 기술에는 스크레이핑과 크롤링이 있다.
: 스크레이핑은 웹 사이트에서 특정 데이터를 수집하는 것이다.
: 크롤링은 크롤러 또는 스파이더라는 프로그램으로 웹 사이트에서 데이터를 추출하는 것이다.
: 웹에서 데이터를 수집하는 작업을 통틀어 크롤링이라고 한다.

# 웹 통신 방법

: HTTP 통신 사용
: 사용자가 데이터를 가지고 있는 서버(웹 사이트)의 url에 접속하여 수집할 데이터에 HTTP 요청
: 서버가 그에 대한 응답을 JSON 또는 XML 형식으로 보내는 방식
: 이때 웹 API를 사용
: 웹 API - 지도, 검색, 환율, 주가 등 다양한 정보를 가지고 있는 웹 사이트의 기능을 외부에서 쉽게 사용할 수 있도록 사용 절차와 규약을 정의한 것.

# 네이버 개발자 가입

  1. 네이버 개발자 센터 접속하기 (https://developers.naver.com)
    [서비스 API] 클릭
  2. 오픈 API 이용 신청하기
    [서비스 API] 하위 메뉴 중 [검색] 선택 후 <오픈 API 이용 신청> 클릭
  3. 애플리케이션 등록하기
    [애플리케이션 등록(API 이용 신청)]
  4. 애플리케이션 정보 확인하기
  5. 검색 API 이용 안내 페이지 확인하기

# 네이버 뉴스 크롤링

# 전체 작업 설계하기

작업 설계사용할 코드
1. 검색어 지정하기srcText = '월드컵'
2. 네이버 뉴스 검색하기getNaverSearch()
2.1 url 구성하기url = base + node + srcText
2.2 url 접속과 검색 요청하기urllib.request.urlopen()
2.3 요청 결과를 응답 JSON으로 받기json.load()
3. 응답 데이터를 정리하여 리스트에 저장하기getPostData()
4. 리스트를 JSON 파일로 저장하기json.dumps()

# 프로그램 구성 설계하기

def main()

1. 검색어 지정

2. 네이버 뉴스 검색

3. 응답 데이터 정리 후 리스트에 저장

4. 리스트를 JSON 파일로 저장

# 함수 설계하기

  1. [CODE 0] 먼저, 전체 작업 스토리를 설계한다.
01 def main():
02    node = 'news'  #크롤링한 대상
03    srcText = input('검색어를 입력하세요: ')
04    cnt = 0
05    jsonResult = []
06    
07    jsonResponse = getNaverSearch(node, srcText, 1, 100)  #[CODE 2]
08    total = jsonResponse['total']
09    
10    while((jsonResponse != None) and (jsonResponse['display'] != 0)):
11        for post in jsonResponse['items']:
12            cnt+= 1
13            getPostData(post, jsonResult, cnt)   #[CODE 3]
14            
15        start = jsonResponse['start'] + jsonResponse['display']
16        jsonResponse = getNaverSearch(node, srcText, start, 100)   #[CODE 2]
17        
18    print('전체 검색 : %d 건' %total)
19        
20    with open('%s_naver_%s.json' % (srcText, node), 'w', encoding='utf8') as outfile:
21        jsonFile = json.dumps(jsonResult, indent=4, sort_keys = True, ensure_ascii = False)
22            
23        outfile.write(jsonFile)
24            
25    print("가져온 데이터 : %d 건" %(cnt))
26    print('%s_naver_%s.json SAVED' % (srcText, node))

02행 : 네이버 뉴스 검색을 위해 검색 API 대상을 'news'로 설정한다.
03행 : 파이썬 셸 창에서 검색어를 입력받아 srcText에 저장한다.
07행 : getNaverSearch() 함수를 호출하여 start = 1, display = 100에 대한 검색 결과를 반환받아 jsonResponse에 저장한다.
10~16행 : 검색 결과(jsonResponse)에 데이터가 있는 동안 for문(11~13행)으로 검색 결과를 한 개씩 처리하는 작업(getPostData())을 반복한다. 반복 작업이 끝나면 다음 검색 결과 100개를 가져오기 위해 start 위치를 변경하고(15행), getNaverSearch() 함수를 호출하여 새로운 검색 결과를 jsonResponse에 저장하고(16행) for문(11~13행)을 다시 반복한다.
20~23행 : 파일 객체를 생성하여 정리된 데이터를 JSON 파일에 저장한다.

  1. [CODE 1] url 접속을 요청하고 응답을 받아서 반환하는 부분을 작성한다.
01 def getRequestUrl(url):
02     req = urllib.request.Request(url)
03     req.add_header("X-Naver-Client-Id", client_id)
04     req.add_header("X-Naver-Client-Secret", client_secret)
05     
06     try:
07         response = urllib.request.urlopen(req)
08         if response.getcode() == 200:
09             print("[%s]Url Request Success" % datetime.datetime.now())
10             return response.read().decode('utf-8')
11     except Exception as e :
12         print(e)
13         print("[%s] Error for URL : %s" % (datetime.datetime.now(), url))
14         return None

02행 : 매개변수로 받은 url에 대한 요청을 보낼 객체를 생성한다.
03~04행 : API를 사용하기 위한 Client ID와 Client Secret 코드를 요청 객체 헤드에 추가한다.
07행 : 요청 객체를 보내고 그에 대한 응답을 받아 response 객체에 저장한다.
08~10행 : getcode()로 response 객체에 저장된 코드를 확인한다. 200이면 요청이 정상처리된 것이므로 성공 메시지를 파이썬 셸 창에 출력하고 응답을 utf-8 형식으로 디코딩하여 반환한다.
11~14행 : 요청이 처리되지 않은 예외 사항(exception)이 발생하면 에러 메시지를 파이썬 셸 창에 출력한다.

  1. [CODE 2] 네이버 뉴스 검색 url을 만들고 [CODE 1]의 getRequestUrl(url)을 호출하여 반환받은 응답 데이터를 파이썬 json 형식으로 반환하는 부분이다.
01 def getNaverSearch(node, srcText, start, display):
02     base = "https://openapi.naver.com/v1/search"
03     node = "/%s.json" % node
04     parameters = "?query=%s&start=%s&display=%s" % (urllib.parse.quote(srcText), start,    display)
05 
06     url = base + node + parameters
07     responseDecode = getRequestUrl(url)     #[CODE 1]
08 
09     if(responseDecode == None):
10         return None
11     else:
12         return json.loads(responseDecode)

02~06행 : 네이버 검색 API 정보에 따라 요청 URL을 구성한다.
07행 : 완성한 url을 이용하여 getRequestUrl() 함수를 호출하여 받은 utf-8 디코드 응답을 responseDecode에 저장한다.
12행 : 서버에서 받은 JOSN 형태의 응답 객체를 파이썬 객체로 로드하여 반환한다.

  1. [CODE 3] JSON 형식의 응답 데이터를 필요한 항목만 정리하여 딕셔너리 리스트인 jsonResult를 구성하고 반환하도록 작성한다.
01 def getPostData(post, jsonResult, cnt):
02     title = post['title']
03     description = post['description']
04     org_link = post['originallink']
05     link = post['link']
06
07     pDate = datetime.datetime.strptime(post['pubDate'], '%a, %d, %b, %Y, %H:%M:%S+0900')
08     pDate = pDate.strftime('%Y-%m-%d %H:%M:%S')
09
10     jsonResult.append({'cnt':cnt, 'title':title, 'description':description,
11                        'org_link':org_link, 'link':org_link, 'pDate':pDate})
12     return

02~05행 : 검색 결과가 들어 있는 post 객체에서 필요한 데이터 항목을 추출하여 변수에 저장한다.
07행 : 네이버에서 제공하는 시간인 pubDate는 문자열 형태이므로 날짜 객체로 변환한다. pubDate는 그리니치 평균시 형식을 사용하는데 한국 표준시보다 9시간 느리므로 +0900을 사용해 한국 표준시로 맞춘다.
08행 : 수정된 날짜를 '연-월-일 시:분:초' 형식으로 나타낸다.
10행 : 2~5행에서 저장한 데이터를 딕셔너리 형태인 {'키':값}으로 구성하여 리스트 객체인 jsonResult에 추가한다.

# 전체 프로그램 작성

import os
import sys
import urllib.request
import datetime
import time
import json

client_id = '본인이 발급받은 네이버 Client ID'
client_secret = '본인이 발급받은 네이버 Client Secret'

#[CODE 1]
def getRequestUrl(url):
    req = urllib.request.Request(url)
    req.add_header("X-Naver-Client-Id", client_id)
    req.add_header("X-Naver-Client-Secret", client_secret)
    
    try:
        response = urllib.request.urlopen(req)
        if response.getcode() == 200:
            print("[%s]Url Request Success" % datetime.datetime.now())
            return response.read().decode('utf-8')
    except Exception as e :
        print(e)
        print("[%s] Error for URL : %s" % (datetime.datetime.now(), url))
        return None

#[CODE 2]
def getNaverSearch(node, srcText, start, display):
    base = "https://openapi.naver.com/v1/search"
    node = "/%s.json" % node
    parameters = "?query=%s&start=%s&display=%s" % (urllib.parse.quote(srcText), start, display)

    url = base + node + parameters
    responseDecode = getRequestUrl(url)     #[CODE 1]

    if(responseDecode == None):
        return None
    else:
        return json.loads(responseDecode)

#[CODE 3]
def getPostData(post, jsonResult, cnt):
    title = post['title']
    description = post['description']
    org_link = post['originallink']
    link = post['link']

    pDate = datetime.datetime.strptime(post['pubDate'], '%a, %d, %b, %Y, %H:%M:%S+0900')
    pDate = pDate.strftime('%Y-%m-%d %H:%M:%S')

    jsonResult.append({'cnt':cnt, 'title':title, 'description':description,
                       'org_link':org_link, 'link':org_link, 'pDate':pDate})
    return

#[CODE 0]
def main():
    node = 'news'  #크롤링한 대상
    srcText = input('검색어를 입력하세요: ')
    cnt = 0
    jsonResult = []
    
    jsonResponse = getNaverSearch(node, srcText, 1, 100)  #[CODE 2]
    total = jsonResponse['total']
    
    while((jsonResponse != None) and (jsonResponse['display'] != 0)):
        for post in jsonResponse['items']:
            cnt+= 1
            getPostData(post, jsonResult, cnt)   #[CODE 3]
            
        start = jsonResponse['start'] + jsonResponse['display']
        jsonResponse = getNaverSearch(node, srcText, start, 100)   #[CODE 2]
        
    print('전체 검색 : %d 건' %total)
        
    with open('%s_naver_%s.json' % (srcText, node), 'w', encoding='utf8') as outfile:
        jsonFile = json.dumps(jsonResult, indent=4, sort_keys = True, ensure_ascii = False)
            
        outfile.write(jsonFile)
            
    print("가져온 데이터 : %d 건" %(cnt))
    print('%s_naver_%s.json SAVED' % (srcText, node))

if __name__ == '__main__':
    main()                  

-> 파일을 실행시키면 파이썬 셸 창에 print 명령의 실행 결과인 '검색어를 입력하세요:'가 출력되고 '월드컵'을 입력하면 nvCrawler.py 파일이 저장된 위치에 JSON 파일이 생성된다.

0개의 댓글