7 분 소요

1. 네이버 API 사용 등록

  • 네이버 개발자 센터
  • https://developers.naver.com/main/
  • Application
    • 어플리케이션 등록
    • 어플리케이션 이름
    • 사용 API
      • 검색
    • 환경추가
      • WEB 설정
      • http://localhost
    • Client ID : **
    • Client Secret: **
    • https://developers.naver.com/apps/#/myapps/E_N2j6ER9uWLIDb2BEEc/overview

2. 네이버 검색 API 사용

  • urllib: http 프로토콜에 따라서 서버의 요청/응답을 처리하기 위한 모듈
  • urllib.request: 클라이언트의 요청을 처리하는 모듈
  • urllib.parse: url 주소에 대한 분석

    개발 가이드

  • https://developers.naver.com/docs/serviceapi/search/blog/blog.md#python

검색: 블로그(blog)

# 네이버 검색 API 예제 - 블로그 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/blog?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

"title":"<b>파이썬<\/b>학원 초보자를 위한 공부과정!",
			"link":"https:\/\/blog.naver.com\/chzhvkdll\/222931446581",
			"description":"그래서 제가 <b>파이썬<\/b>학원을 다닌 계기과 장단점, 고민에 대해 써보도록 하겠습니다 :) 모두가 같을 수는... <b>파이썬<\/b>학원 수강 신청한 건 대학 후배 중에 갑자기 전공 무관하게 그쪽으로 턴해서 공부하고 취직했단... ",
			"bloggername":"에피",
			"bloggerlink":"blog.naver.com\/chzhvkdll",
			"postdate":"20221118"
            								.
                                            .
                                            .

response, response.getcode(), response.code, response.status

=>

(<http.client.HTTPResponse at 0x25e7c01c190>, 200, 200, 200)

# 글자로 읽을 경우, decode utf-8 설정
print(response_body.decode("utf-8"))

=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:40 +0900",
	"total":384417,
	"start":1,
	"display":10,
	"items":[
		{
			"title":"<b>파이썬<\/b>학원 초보자를 위한 공부과정!",
			"link":"https:\/\/blog.naver.com\/chzhvkdll\/222931446581",
			"description":"그래서 제가 <b>파이썬<\/b>학원을 다닌 계기과 장단점, 고민에 대해 써보도록 하겠습니다 :) 모두가 같을 수는... <b>파이썬<\/b>학원 수강 신청한 건 대학 후배 중에 갑자기 전공 무관하게 그쪽으로 턴해서 공부하고 취직했단... ",
			"bloggername":"에피",
			"bloggerlink":"blog.naver.com\/chzhvkdll",
			"postdate":"20221118"
		},
        									.
                                            .
                                            .

검색: 책(book)

# 네이버 검색 API 예제 - 책 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/book?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:40 +0900",
	"total":826,
	"start":1,
	"display":10,
	"items":[
		{
			"title":"혼자 공부하는 파이썬 (1:1 과외하듯 배우는 프로그래밍 자습서)",
			"link":"https:\/\/search.shopping.naver.com\/book\/catalog\/32507605957",
			"image":"https:\/\/shopping-phinf.pstatic.net\/main_3250760\/32507605957.20221019133018.jpg",
			"author":"윤인성",
			"discount":"19800",
			"publisher":"한빛미디어",
			"pubdate":"20220601",
			"isbn":"9791162245651",
            							.
                                        .
                                        .

검색: 영화(movie)

# 네이버 검색 API 예제 - 영화 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/movie?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:40 +0900",
	"total":1,
	"start":1,
	"display":1,
	"items":[
		{
			"title":"<b>파이썬<\/b> 앤 가드",
			"link":"https:\/\/movie.naver.com\/movie\/bi\/mi\/basic.nhn?code=152070",
			"image":"https:\/\/ssl.pstatic.net\/imgmovie\/mdi\/mit110\/1520\/152070_P01_145336.jpg",
			"subtitle":"PYTHON AND GUARD",
			"pubDate":"2015",
			"director":"안톤 디아코프|",
			"actor":"",
			"userRating":"0.00"
		}
        									.
                                            .
                                            .

검색: 카페(cafearticle)

# 네이버 검색 API 예제 - 카페 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/cafearticle?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:41 +0900",
	"total":156167,
	"start":1,
	"display":10,
	"items":[
		{
			"title":"<b>파이썬<\/b> vs C언어",
			"link":"http:\/\/cafe.naver.com\/mathall\/2564974",
			"description":"고수님들의 현명한 답변 기다립니다 <b>파이썬<\/b>을 가르친다는 학원은 저희 집에서 차로 15분 거리라서 제가... 제가 라이딩이 힘든 건 아니니 그건 감안하고 <b>파이썬<\/b> vs C언어 중 어느 학원을 선택해야 아이한테 도움이 될까요?",
			"cafename":"[상위1%카페] 대한민국 상위1% 교육정...",
			"cafeurl":"https:\/\/cafe.naver.com\/mathall"
		},
        								.
                                        .
                                        .

검색: 쇼핑(shop)

# 네이버 검색 API 예제 - 쇼핑 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/shop?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:41 +0900",
	"total":148244,
	"start":1,
	"display":10,
	"items":[
		{
			"title":"잘모이 셀리나 리얼 <b>파이톤<\/b> 뉴 빅 토트백 ZA-4022",
			"link":"https:\/\/search.shopping.naver.com\/gate.nhn?id=35683981989",
			"image":"https:\/\/shopping-phinf.pstatic.net\/main_3568398\/35683981989.20221107081401.jpg",
			"lprice":"165530",
			"hprice":"",
			"mallName":"네이버",
			"productId":"35683981989",
			"productType":"1",
			"brand":"잘모이",
			"maker":"",
			"category1":"패션잡화",
			"category2":"여성가방",
			"category3":"토트백",
			"category4":""
		},
        								.
                                        .
                                        .

검색: 백과사전(encyc)

# 네이버 검색 API 예제 - 백과사전 검색
import os
import sys
import urllib.request
client_id = "E_N2j6ER9uWLIDb2BEEc"
client_secret = "OwQUT_S108"
encText = urllib.parse.quote("파이썬")
url = "https://openapi.naver.com/v1/search/encyc?query=" + encText # JSON 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # XML 결과
request = urllib.request.Request(url)
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
response = urllib.request.urlopen(request)
rescode = response.getcode()
if(rescode==200):
    response_body = response.read()
    print(response_body.decode('utf-8'))
else:
    print("Error Code:" + rescode)
    
=>

{
	"lastBuildDate":"Thu, 02 Feb 2023 18:25:41 +0900",
	"total":522,
	"start":1,
	"display":10,
	"items":[
		{
			"title":"<b>파이썬<\/b>",
			"link":"https:\/\/terms.naver.com\/entry.naver?docId=3580815&cid=59088&categoryId=59096",
			"description":"‘<b>파이썬<\/b>’이다. 간결한 문법으로 입문자가 이해하기 쉽고, 다양한 분야에 활용할 수 있기 때문이다. 이 외에도 <b>파이썬<\/b>은 머신러닝, 그래픽, 웹 개발 등 여러 업계에서 선호하는 언어로 꾸준히... ",
			"thumbnail":"http:\/\/openapi-dbscthumb.phinf.naver.net\/4749_000_1\/20170118193349632_0CHSSS5Y6.png\/01_16.png?type=m160_160"
		},
        						.
                                .
                                .

3. 상품 검색

  • “몰스킨” ```py import os import sys import urllib.request client_id = “E_N2j6ER9uWLIDb2BEEc” client_secret = “OwQUT_S108” encText = urllib.parse.quote(“몰스킨”) url = “https://openapi.naver.com/v1/search/shop?query=” + encText # JSON 결과

    url = “https://openapi.naver.com/v1/search/blog.xml?query=” + encText # XML 결과

    request = urllib.request.Request(url) request.add_header(“X-Naver-Client-Id”,client_id) request.add_header(“X-Naver-Client-Secret”,client_secret) response = urllib.request.urlopen(request) rescode = response.getcode() if(rescode==200): response_body = response.read() print(response_body.decode(‘utf-8’)) else: print(“Error Code:” + rescode)

=>

{ “lastBuildDate”:”Thu, 02 Feb 2023 18:25:41 +0900”, “total”:43102, “start”:1, “display”:10, “items”:[ { “title”:”몰스킨<\/b> 2023 다이어리 위클리 소프트커버”, “link”:”https:\/\/search.shopping.naver.com\/gate.nhn?id=84662525433”, “image”:”https:\/\/shopping-phinf.pstatic.net\/main_8466252\/84662525433.2.jpg”, “lprice”:”22950”, “hprice”:””, “mallName”:”베스트펜”, “productId”:”84662525433”, “productType”:”2”, “brand”:”몰스킨”, “maker”:””, “category1”:”생활\/건강”, “category2”:”문구\/사무용품”, “category3”:”다이어리\/플래너”, “category4”:”다이어리” }, . . .


---

### gen_search_url()
<span style="color: #FAFAD2">encText = urllib.parse.quote("몰스킨")
url = "https://openapi.naver.com/v1/search/shop?query=" + encText # JSON 결과</span>
```py
def gen_search_url(api_node, search_text, start_num, disp_num):
    base = "https://openapi.naver.com/v1/search"
    node = "/" + api_node + ".json"
    param_query = "?query=" + urllib.parse.quote(search_text)
    param_start = "&start=" + str(start_num)
    param_disp = "&display=" + str(disp_num)
    
    return base + node + param_query + param_start + param_disp
    
gen_search_url("shop", "TEST", 10, 3)

=>

'https://openapi.naver.com/v1/search/shop.json?query=TEST&start=10&display=3'

get_result_onpage()

import json
import datetime

def get_result_onpage(url):
    request = urllib.request.Request(url)
    request.add_header("X-Naver-Client-Id",client_id)
    request.add_header("X-Naver-Client-Secret",client_secret)
    response = urllib.request.urlopen(request)
    print("[%s] Url Request Success" % datetime.datetime.now())
    return json.loads(response.read().decode("utf-8"))
    
url = gen_search_url("shop", "몰스킨", 1, 5)
one_result = get_result_onpage(url)

=>

[2023-02-02 18:25:42.249704] Url Request Success

one_result

=>

{'lastBuildDate': 'Thu, 02 Feb 2023 18:25:42 +0900',
 'total': 43102,
 'start': 1,
 'display': 5,
 'items': [{'title': '<b>몰스킨</b> 2023 다이어리 위클리 소프트커버',
   'link': 'https://search.shopping.naver.com/gate.nhn?id=84662525433',
   'image': 'https://shopping-phinf.pstatic.net/main_8466252/84662525433.2.jpg',
   'lprice': '22950',
   'hprice': '',
   'mallName': '베스트펜',
   'productId': '84662525433',
   'productType': '2',
   'brand': '몰스킨',
   'maker': '',
   'category1': '생활/건강',
   'category2': '문구/사무용품',
   'category3': '다이어리/플래너',
   'category4': '다이어리'},
   								.
                                .
                                .

get_fields()

import pandas as pd

def get_fields(json_data):
    title = [each["title"] for each in json_data["items"]]
    link = [each["link"] for each in json_data["items"]]
    lprice = [each["lprice"] for each in json_data["items"]]
    mall_name = [each["mallName"] for each in json_data["items"]]
    
    result_pd = pd.DataFrame({
        "title": title,
        "link": link,
        "lprice": lprice,
        "mall": mall_name,
    }, columns=["title", "lprice", "link", "mall"])
    return result_pd
    
get_fields(one_result)
title lprice link mall
0 <b>몰스킨</b> 2023 다이어리 위클리 소프트커버 22950 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
1 <b>몰스킨</b> 2023 데일리 12개월 다이어리 L 38030 https://search.shopping.naver.com/gate.nhn?id=... 네이버
2 <b>몰스킨</b> 노트 가죽 하드커버 감성 고급 업무용 이쁜 심플 24000 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
3 <b>몰스킨</b> 2023다이어리 데일리 하드커버 라지블루 다이어리노트 31000 https://search.shopping.naver.com/gate.nhn?id=... 네이버
4 [<b>몰스킨</b>] 2023년 클래식 다이어리(12개월) (데일리, 위클리, 먼슬리) 27000 https://search.shopping.naver.com/gate.nhn?id=... 몰스킨공식온라인스토어

delete_tag()

def delete_tag(input_str):
    input_str = input_str.replace("<b>", "")
    input_str = input_str.replace("</b>", "")
    return input_str
    
import pandas as pd

def get_fields(json_data):
    title = [delete_tag(each["title"]) for each in json_data["items"]]
    link = [each["link"] for each in json_data["items"]]
    lprice = [each["lprice"] for each in json_data["items"]]
    mall_name = [each["mallName"] for each in json_data["items"]]
    
    result_pd = pd.DataFrame({
        "title": title,
        "link": link,
        "lprice": lprice,
        "mall": mall_name,
    }, columns=["title", "lprice", "link", "mall"])
    return result_pd
    
get_fields(one_result)
title lprice link mall
0 몰스킨 2023 다이어리 위클리 소프트커버 22950 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
1 몰스킨 2023 데일리 12개월 다이어리 L 38030 https://search.shopping.naver.com/gate.nhn?id=... 네이버
2 몰스킨 노트 가죽 하드커버 감성 고급 업무용 이쁜 심플 24000 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
3 몰스킨 2023다이어리 데일리 하드커버 라지블루 다이어리노트 31000 https://search.shopping.naver.com/gate.nhn?id=... 네이버
4 [몰스킨] 2023년 클래식 다이어리(12개월) (데일리, 위클리, 먼슬리) 27000 https://search.shopping.naver.com/gate.nhn?id=... 몰스킨공식온라인스토어

url = gen_search_url("shop", "몰스킨", 1, 5)
json_result = get_result_onpage(url)
pd_result = get_fields(json_result)

=>

[2023-02-02 18:48:57.156929] Url Request Success

pd_result
title lprice link mall
0 몰스킨 2023 다이어리 위클리 소프트커버 22950 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
1 몰스킨 2023 데일리 12개월 다이어리 L 38030 https://search.shopping.naver.com/gate.nhn?id=... 네이버
2 몰스킨 노트 가죽 하드커버 감성 고급 업무용 이쁜 심플 24000 https://search.shopping.naver.com/gate.nhn?id=... 베스트펜
3 몰스킨 2023다이어리 데일리 하드커버 라지블루 다이어리노트 31000 https://search.shopping.naver.com/gate.nhn?id=... 네이버
4 [몰스킨] 2023년 클래식 다이어리(12개월) (데일리, 위클리, 먼슬리) 27000 https://search.shopping.naver.com/gate.nhn?id=... 몰스킨공식온라인스토어

actMain()

result_mol = []

for n in range(1, 1000, 100):
    url = gen_search_url("shop", "몰스킨", n, 100)
    json_result = get_result_onpage(url)
    pd_result = get_fields(json_result)

    result_mol.append(pd_result)

result_mol = pd.concat(result_mol)

result_mol.info()

=>

<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000 entries, 0 to 99
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   title   1000 non-null   object
 1   lprice  1000 non-null   object
 2   link    1000 non-null   object
 3   mall    1000 non-null   object
dtypes: object(4)
memory usage: 39.1+ KB

인덱스 재정렬, object -> float

result_mol.reset_index(drop=True, inplace=True)
result_mol["lprice"] = result_mol["lprice"].astype("float")
result_mol.info()

=>

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   title   1000 non-null   object 
 1   lprice  1000 non-null   float64
 2   link    1000 non-null   object 
 3   mall    1000 non-null   object 
dtypes: float64(1), object(3)
memory usage: 31.4+ KB

result_mol.tail()
title lprice link mall
995 몰스킨 까이에 룰드 라지 사이즈 옵션1 20000 https://search.shopping.naver.com/gate.nhn?id=... 네이버
996 갤럭시 갤럭시 몰스킨 다잉 팬츠 GA1821U22P 116630 https://search.shopping.naver.com/gate.nhn?id=... 네이버
997 몰스킨 Moleskine 클래식 2023 데일리 플래너 하드 커버 라지 12 x 스칼렛 29800 https://search.shopping.naver.com/gate.nhn?id=... 네이버
998 몰스킨 기프트박스 트래블 - Travel Journal+Luggage Tags 73700 https://search.shopping.naver.com/gate.nhn?id=... 몰스킨스토어
999 올젠 몰스킨 워싱 스트레치 자켓 편한 착장 고급스러운 연출 ZOC3KG1312 230910 https://search.shopping.naver.com/gate.nhn?id=... 네이버

to_excel()

writer = pd.ExcelWriter("../data/06_molskin_diary_in_naver_shop.xlsx", engine="xlsxwriter")
result_mol.to_excel(writer, sheet_name="Sheet1")

workbook = writer.book
worksheet = writer.sheets["Sheet1"]
worksheet.set_column("A:A", 4)
worksheet.set_column("B:B", 80)
worksheet.set_column("C:C", 7)
worksheet.set_column("D:D", 10)
worksheet.set_column("E:E", 40)
worksheet.set_column("F:F", 10)

worksheet.conditional_format("C2:C1001", {"type": "3_color_scale"})
writer.save()


시각화

import set_matplotlib_hangul
import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(15, 6))
sns.countplot(
    x=result_mol["mall"], 
    data=result_mol, 
    palette="RdYlGn",
    order=result_mol["mall"].value_counts().index
)
plt.xticks(rotation=90)
plt.show()