1. 네이버 API를 이용한 크롤링(22.05.12)
1. 크롤링이란
웹에서 데이터를 수집하는 기술에는 스크레이핑, 크롤링 이렇게 두가지가 존재한다. 두개를 구분하자면 스크레이핑은 웹에서 특정데이터를 수집하는 것이고, 크롤링은 프로그램으로 웹사이트에서 데이터를 추출하는 것인데 그냥 웹에서 데이터를 수집하는 것 자체를 크롤링이라고 묶어서 부른다. 크롤링의 원리는 웹의 통신 방법에 있다.
[웹의 통신방법]
사용자가 데이터를 가지고있는서버의 url에 접속
수집할 데이터에 HTTP 요청(request)
서버가 그에 대한 응답(response)
응답을 JSON 또는 XML형식으로 보내는 방식
- > 이 때 API( 웹사이트의 기능을 외부에서 쉽게 사용할 수 있도록 사용절차와 규약을 정의해놓은 것)을 사용한다.
웹 API를 제공하는 사이트는 다양한데 오늘은 네이버 API를 발급하여 사용해보도록 하겠다.
우선 네이버 API를 발급받고 Client ID와 Client Secret을 발급받았다는 준비하에 진행할 것이다.
1. 전체 작업 설계
| 작업 설계 | 사용할 코드 |
| --- | --- |
| 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() |
2. 프로그램 구성 설계
def main()
1. 검색어 지정
2. 네이버 뉴스 검색
3. 응답데이터 정리 후 리스트에 저장
4. 리스트를 JSON 파일로 저장
3. 함수 설계
[main함수]
def main():
node='news'# api노드(news,blog,cafearticle,movie,shop..)
srcText=input('검색어를 입력하세요: ')# 검색어
cnt=0# 검색결과 count
jsonResult=[]# 검색결과를 정리하여 저장
jsonResponse=getNaverSearch(node,srcText,1,100)
total=jsonResponse['total']# 전체 검색 결과 개수
while((jsonResponse != None) and (jsonResponse['display']!=0)):
for post in jsonResponse['items']:
cnt+=1
getPostData(post,jsonResult,cnt)
start=jsonResponse['start']+jsonResponse['display']
jsonResponse=getNaverSearch(node,srcText,start,100)
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)# json파일 형태로 저장
print("가져온 데이터: %d건" %(cnt))
print("%s_naver_%s.json SAVED" %(srcText,node))
[02행]
api대상을 news로 선택
[07행]
getNaverSearch() 함수를 호출해서 start=1, display=100에 대한 검색결과를 반환받아 jsonResponse에 저장
[10~16행]
- jsonResponse에 데이터가 존해하면 for문을 통해 결과를 한개씩 가져오면서 getPostData() 반복
- 반복이 끝난후 다음결과 100개를 가져오기 위해 start를 새로 갱신하고 다시 반복
[20-23행]
- 파일 객체를 생성하여 정리된 데이터를 json파일에 저장.
[getRequestUrl 함수]
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
[02행]
url에 대한 요청을 보낼 객체 req를 생성
[03~04행]
API를 사용하기 위한 Client ID와 Secret을 req헤더에 추가
[07행]
req개체를 보내고 그에 대한 응답을 response에 저장
[08~10행]
getcode()로 response에 저장된 객체를 확인하고 200이면 요청이 정상 처리된 것이므로 성공메세지 출력
[getNaverSearch 함수]
def getNaverSearch(node,srcText,start,display):
base="https://openapi.naver.com/v1/search"# 검색url의 기본주소
node="/%s.json" %node# 검색 대상에 따른 json파일 이름
parameters="?query=%s&start=%s&display=%s" %(urllib.parse.quote(srcText),start,display)
# url에 추가할 검색어와 검색 시작 위치, 출력 건수 매개변수
url=base+node+parameters
responseDecode=getRequestUrl(url)# 반환받은 응답 개체
if(responseDecode==None):
return None
else:
return json.loads(responseDecode)
[02-06행]
url구성
[07행]
완성한 url을 이용하야 getRequestUrl()함수를 호출하여 받은 utf-8 디코드 응답을 responseDecode에 저장
[12행]
서버에서 받은 json형태의 응답 객체를 파이썬 객체로 로드하여 반환
[getPostData 함수]
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,'decription':description,'org_link':org_link,'link':org_link,'pDate':pDate})
return
[02~05행]
검색결과가 들어있는 post객체에서 필요한 데이터 항목들을 변수에 저장
[07행]
네이버에서 제공하는 시간형태인 pubDate가 문자열형태로 반환되므로 날짜 객체로 변환
[10행]
02~05행에서 저장한 데이터를 딕셔너리형태인 {'키':값}으로 구성하여 리스트객체인 jsonresult에 저장
[Navernewscrawilingcode]*
import os
import sys
import urllib.request
import datetime
import time
import json
import requests
client_id = "발급받은 Client_id를 입력하세요"
client_secret = "발급받은 Client_Secret를 입력하세요"
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
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)
if(responseDecode==None):
return None
else:
return json.loads(responseDecode)
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,'decription':description,'org_link':org_link,'link':org_link,'pDate':pDate})
return
def main():
node='news'
srcText=input('검색어를 입력하세요: ')
cnt=0
jsonResult=[]
jsonResponse=getNaverSearch(node,srcText,1,100)
total=jsonResponse['total']
while((jsonResponse != None) and (jsonResponse['display']!=0)):
for post in jsonResponse['items']:
cnt+=1
getPostData(post,jsonResult,cnt)
start=jsonResponse['start']+jsonResponse['display']
jsonResponse=getNaverSearch(node,srcText,start,100)
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()
Result
우선 "월드컵"이라는 단어를 검색한다고 입력하면, 결과값은 월드컵 navernews.json파일이 저장되고, http error 400이 뜨게 된다. 오류가 뜨는 이유는 네이버 검색 api에서는 한번 호출에 최대 100개의 검색결과를 최대 10번 즉 1000개의 데이터를 가져올 수 있어서 우리는 한 번에 100개의 데이터를 가져왔고 출력값을 보면 10번이 반복된후에 접속이 거부되어 오류가 뜨는 것을 볼 수 있다. 오류 메세지를 보면 1001번째에서 오류가 나는 것을 확인할 수 있다.
Review
중간에 계속 오류가 났었는데, 우선 수정한 부분은 두개였다.
- base+node+parameters를 통해서 url을 생성할 때, 가독성이 안좋아서 주소에 띄어쓰기를 했었는데, 당연히 이건 내가 임의로 주소값을 수정한게 되므로 없는 url에 들어가 객체를 반환받으려고 하니 오류가 났었다.
- 네이버의 시간형태를 문자열에서 날짜 객체로 바꾸는 과정에서 오류가 났었는데,
pDate=datetime.datetime.strptime(post['pubDate'], '%a, %d %b %Y %H:%M:%S +0900')
datetime.strptime(문자열, 형식)에서 문자열의 형태와 형식의 형태가 다르면 오류가 뜬다고 했다.
즉 post['pubDate']가 "Thu, 12 May 2022 13:56:00 +0900" 을 반환하므로, 뒤에 형식도 "%a, %d %b %Y %H:%M:%S +0900" 처럼 띄어쓰기와 ,하나까지 정확하게 써줘야 했다.
'데이터분석실습 > 데이터 과학 기반의 파이썬 빅데이터 분석' 카테고리의 다른 글
파이썬 빅데이터 분석 Day 5 (1) | 2023.10.26 |
---|---|
파이썬 빅데이터 분석 Day 4 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 3 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 2 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 0 (0) | 2023.10.26 |