Kims12 commited on
Commit
67096dc
ยท
verified ยท
1 Parent(s): bdafbef

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +152 -0
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import hashlib
3
+ import hmac
4
+ import base64
5
+ import requests
6
+ import gradio as gr
7
+ import urllib.request
8
+ import urllib.parse
9
+ import json
10
+ import pandas as pd
11
+ from concurrent.futures import ThreadPoolExecutor
12
+ import os
13
+ import tempfile
14
+ from datetime import datetime
15
+
16
+ BASE_URL = "https://api.searchad.naver.com"
17
+ API_KEY = "010000000046604df3a0f6abf4c52824e0d5835c5cbeae279ced8b2bb9007b3cc566b190c7"
18
+ SECRET_KEY = "AQAAAABGYE3zoPar9MUoJODVg1xczNEcSuIBi66wWUy4p4gs/Q=="
19
+ CUSTOMER_ID = 2666992
20
+
21
+ class NaverAPI:
22
+ def __init__(self, base_url, api_key, secret_key, customer_id):
23
+ self.base_url = base_url
24
+ self.api_key = api_key
25
+ self.secret_key = secret_key
26
+ self.customer_id = customer_id
27
+
28
+ def generate_signature(self, timestamp, method, path):
29
+ sign = f"{timestamp}.{method}.{path}"
30
+ signature = hmac.new(self.secret_key.encode('utf-8'), sign.encode('utf-8'), hashlib.sha256).digest()
31
+ return base64.b64encode(signature).decode('utf-8')
32
+
33
+ def get_timestamp(self):
34
+ return str(int(time.time() * 1000))
35
+
36
+ def get_headers(self, method, uri):
37
+ timestamp = self.get_timestamp()
38
+ headers = {
39
+ 'Content-Type': 'application/json; charset=UTF-8',
40
+ 'X-Timestamp': timestamp,
41
+ 'X-API-KEY': self.api_key,
42
+ 'X-Customer': str(self.customer_id),
43
+ 'X-Signature': self.generate_signature(timestamp, method, uri),
44
+ }
45
+ return headers
46
+
47
+ def get_keywords_data(self, keywords):
48
+ uri = "/keywordstool"
49
+ method = "GET"
50
+ query = {
51
+ 'hintKeywords': ','.join(keywords),
52
+ 'showDetail': 1
53
+ }
54
+ headers = self.get_headers(method, uri)
55
+ response = requests.get(self.base_url + uri, headers=headers, params=query)
56
+ response.raise_for_status() # HTTP ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ
57
+ return response.json()
58
+
59
+ def get_blog_count(keyword):
60
+ client_id = "421ZKFMM5TS1xmvsF7C0"
61
+ client_secret = "h47UQHAOGV"
62
+ encText = urllib.parse.quote(keyword)
63
+ url = "https://openapi.naver.com/v1/search/blog?query=" + encText
64
+ request = urllib.request.Request(url)
65
+ request.add_header("X-Naver-Client-Id", client_id)
66
+ request.add_header("X-Naver-Client-Secret", client_secret)
67
+ response = urllib.request.urlopen(request)
68
+ rescode = response.getcode()
69
+ if rescode == 200:
70
+ response_body = response.read()
71
+ data = json.loads(response_body.decode('utf-8'))
72
+ return data['total']
73
+ else:
74
+ return 0
75
+
76
+ def get_keywords_data_chunk(chunk):
77
+ api = NaverAPI(BASE_URL, API_KEY, SECRET_KEY, CUSTOMER_ID)
78
+ return api.get_keywords_data(chunk)
79
+
80
+ def get_blog_count_parallel(keyword):
81
+ return (keyword, get_blog_count(keyword))
82
+
83
+ def get_monthly_search_volumes(keywords):
84
+ all_data = []
85
+ chunk_size = 10 # ํ‚ค์›Œ๋“œ๋ฅผ 10๊ฐœ์”ฉ ๋‚˜๋ˆ„์–ด ์š”์ฒญ
86
+
87
+ # API ๋ณ‘๋ ฌ ์š”์ฒญ
88
+ with ThreadPoolExecutor(max_workers=5) as executor:
89
+ futures = [executor.submit(get_keywords_data_chunk, keywords[i:i+chunk_size]) for i in range(0, len(keywords), chunk_size)]
90
+ for future in futures:
91
+ data = future.result()
92
+ if 'keywordList' in data:
93
+ all_data.extend(data['keywordList'])
94
+
95
+ if not all_data:
96
+ return [("Error", "No data returned or invalid response from API", "", "", "")] # ๋ธ”๋กœ๊ทธ ๋ฌธ์„œ ์ˆ˜ ์นผ๋Ÿผ ์ถ”๊ฐ€
97
+
98
+ results = []
99
+ unique_keywords = set()
100
+ for item in all_data:
101
+ keyword = item['relKeyword']
102
+ if keyword not in unique_keywords:
103
+ unique_keywords.add(keyword)
104
+ monthly_pc = item['monthlyPcQcCnt']
105
+ monthly_mobile = item['monthlyMobileQcCnt']
106
+
107
+ if isinstance(monthly_pc, str):
108
+ monthly_pc = int(monthly_pc.replace(',', '').replace('< 10', '0'))
109
+ if isinstance(monthly_mobile, str):
110
+ monthly_mobile = int(monthly_mobile.replace(',', '').replace('< 10', '0'))
111
+
112
+ total_searches = monthly_pc + monthly_mobile
113
+ results.append((keyword, monthly_pc, monthly_mobile, total_searches))
114
+
115
+ if len(results) >= 100:
116
+ break
117
+
118
+ # ๋ธ”๋กœ๊ทธ ๋ฌธ์„œ ์ˆ˜ ๋ณ‘๋ ฌ ์š”์ฒญ
119
+ with ThreadPoolExecutor(max_workers=5) as executor:
120
+ blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
121
+ for i, future in enumerate(blog_futures):
122
+ keyword, blog_count = future.result()
123
+ results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], blog_count)
124
+
125
+ return results
126
+
127
+ def save_to_excel(results, keyword):
128
+ df = pd.DataFrame(results, columns=["ํ‚ค์›Œ๋“œ", "PC์›”๊ฒ€์ƒ‰๋Ÿ‰", "๋ชจ๋ฐ”์ผ์›”๊ฒ€์ƒ‰๋Ÿ‰", "ํ† ํƒˆ์›”๊ฒ€์ƒ‰๋Ÿ‰", "๋ธ”๋กœ๊ทธ๋ฌธ์„œ์ˆ˜"])
129
+ now = datetime.now().strftime('%Y-%m-%d')
130
+ sanitized_keyword = keyword.replace(' ', '_')
131
+ filename = f"{now}_{sanitized_keyword}_์—ฐ๊ด€๊ฒ€์ƒ‰์–ด.xlsx"
132
+ file_path = os.path.join(tempfile.gettempdir(), filename)
133
+ df.to_excel(file_path, index=False)
134
+ return file_path
135
+
136
+ def display_search_volumes(keywords):
137
+ keyword_list = [keyword.strip() for keyword in keywords.split(',')]
138
+ results = get_monthly_search_volumes(keyword_list)
139
+ file_path = save_to_excel(results, keywords)
140
+ return results, file_path
141
+
142
+ iface = gr.Interface(
143
+ fn=display_search_volumes,
144
+ inputs=gr.Textbox(placeholder="ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"),
145
+ outputs=[
146
+ gr.Dataframe(headers=["ํ‚ค์›Œ๋“œ", "PC์›”๊ฒ€์ƒ‰๋Ÿ‰", "๋ชจ๋ฐ”์ผ์›”๊ฒ€์ƒ‰๋Ÿ‰", "ํ† ํƒˆ์›”๊ฒ€์ƒ‰๋Ÿ‰", "๋ธ”๋กœ๊ทธ๋ฌธ์„œ์ˆ˜"]),
147
+ gr.File(label="๋‹ค์šด๋กœ๋“œ ์—‘์…€ ํŒŒ์ผ")
148
+ ],
149
+ title="๋„ค์ด๋ฒ„ ์›”๊ฒ€์ƒ‰๋Ÿ‰ ๊ฒ€์ƒ‰๊ธฐ",
150
+ )
151
+
152
+ iface.launch()