: 데이터를 수집하는 기술에는 스크레이핑과 크롤링이 있다.
: 스크레이핑은 웹 사이트에서 특정 데이터를 수집하는 것이다.
: 크롤링은 크롤러 또는 스파이더라는 프로그램으로 웹 사이트에서 데이터를 추출하는 것이다.
: 웹에서 데이터를 수집하는 작업을 통틀어 크롤링이라고 한다.
: HTTP 통신 사용
: 사용자가 데이터를 가지고 있는 서버(웹 사이트)의 url에 접속하여 수집할 데이터에 HTTP 요청
: 서버가 그에 대한 응답을 JSON 또는 XML 형식으로 보내는 방식
: 이때 웹 API를 사용
: 웹 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 파일로 저장
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 파일에 저장한다.
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)이 발생하면 에러 메시지를 파이썬 셸 창에 출력한다.
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 형태의 응답 객체를 파이썬 객체로 로드하여 반환한다.
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 파일이 생성된다.