Update app.py
Browse files
app.py
CHANGED
@@ -75,13 +75,13 @@ def get_blog_count(keyword):
|
|
75 |
# ν΄λΌμ΄μΈνΈ IDμ μν¬λ¦Ώμ νκ²½ λ³μμμ λΆλ¬μ΅λλ€.
|
76 |
client_id = CLIENT_ID
|
77 |
client_secret = CLIENT_SECRET
|
78 |
-
|
79 |
# keywordκ° λ°μ΄νΈ νμ
μΌ κ²½μ° λμ½λ©
|
80 |
if isinstance(keyword, bytes):
|
81 |
keyword = keyword.decode('utf-8')
|
82 |
elif not isinstance(keyword, str):
|
83 |
keyword = str(keyword)
|
84 |
-
|
85 |
encText = urllib.parse.quote(keyword)
|
86 |
url = "https://openapi.naver.com/v1/search/blog?query=" + encText
|
87 |
request = urllib.request.Request(url)
|
@@ -107,40 +107,15 @@ def get_keywords_data_chunk(chunk):
|
|
107 |
def get_blog_count_parallel(keyword):
|
108 |
return (keyword, get_blog_count(keyword))
|
109 |
|
110 |
-
def
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
try:
|
120 |
-
data = future.result()
|
121 |
-
if 'keywordList' in data:
|
122 |
-
all_data.extend(data['keywordList'])
|
123 |
-
except Exception as e:
|
124 |
-
print(f"Error fetching keywords data chunk: {e}")
|
125 |
-
else:
|
126 |
-
# μ°κ΄κ²μμ΄λ₯Ό ν¬ν¨νμ§ μμΌλ―λ‘ μ
λ ₯ ν€μλλ§ μ²λ¦¬
|
127 |
-
for keyword in keywords:
|
128 |
-
# κ°μμ λ°μ΄ν° ꡬ쑰μ λ§μΆκΈ° μν΄
|
129 |
-
all_data.append({
|
130 |
-
'relKeyword': keyword,
|
131 |
-
'monthlyPcQcCnt': '0', # μ€μ APIμμ κ°μ κ°μ Έμ€λ €λ©΄ λ³λ μμ² νμ
|
132 |
-
'monthlyMobileQcCnt': '0'
|
133 |
-
})
|
134 |
-
|
135 |
-
if not all_data:
|
136 |
-
return [("Error", "λ°μ΄ν°κ° λ°νλμ§ μμκ±°λ API μλ΅μ΄ μ ν¨νμ§ μμ΅λλ€.", "", "", "")] # λΈλ‘κ·Έ λ¬Έμ μ μΉΌλΌ μΆκ°
|
137 |
-
|
138 |
-
results = []
|
139 |
-
unique_keywords = set()
|
140 |
-
for item in all_data:
|
141 |
-
keyword = item['relKeyword']
|
142 |
-
if keyword not in unique_keywords:
|
143 |
-
unique_keywords.add(keyword)
|
144 |
monthly_pc = item.get('monthlyPcQcCnt', 0)
|
145 |
monthly_mobile = item.get('monthlyMobileQcCnt', 0)
|
146 |
|
@@ -158,14 +133,78 @@ def get_monthly_search_volumes(keywords, include_related_keywords=True):
|
|
158 |
monthly_mobile = 0
|
159 |
|
160 |
total_searches = monthly_pc + monthly_mobile
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
|
166 |
if include_related_keywords:
|
167 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
with ThreadPoolExecutor(max_workers=5) as executor:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
|
170 |
for i, future in enumerate(blog_futures):
|
171 |
try:
|
@@ -174,10 +213,8 @@ def get_monthly_search_volumes(keywords, include_related_keywords=True):
|
|
174 |
except Exception as e:
|
175 |
print(f"Error fetching blog count for keyword '{results[i][0]}': {e}")
|
176 |
results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], "Error")
|
177 |
-
|
178 |
-
|
179 |
-
with ThreadPoolExecutor(max_workers=5) as executor:
|
180 |
-
blog_futures = [executor.submit(get_blog_count_parallel, keyword) for keyword in results]
|
181 |
temp_results = []
|
182 |
for future in blog_futures:
|
183 |
try:
|
@@ -200,7 +237,9 @@ def save_to_excel(results, keyword):
|
|
200 |
return file_path
|
201 |
|
202 |
def display_search_volumes(keywords, include_related):
|
203 |
-
keyword_list = [keyword.strip() for keyword in keywords.split(',')]
|
|
|
|
|
204 |
results = get_monthly_search_volumes(keyword_list, include_related_keywords=include_related)
|
205 |
file_path = save_to_excel(results, keywords)
|
206 |
return results, file_path
|
@@ -208,7 +247,7 @@ def display_search_volumes(keywords, include_related):
|
|
208 |
iface = gr.Interface(
|
209 |
fn=display_search_volumes,
|
210 |
inputs=[
|
211 |
-
gr.Textbox(placeholder="ν€μλλ₯Ό μ
λ ₯νμΈμ"),
|
212 |
gr.Checkbox(label="μ°κ΄κ²μμ΄ ν¬ν¨", value=True) # μ°κ΄κ²μμ΄ ν κΈ μΆκ°
|
213 |
],
|
214 |
outputs=[
|
|
|
75 |
# ν΄λΌμ΄μΈνΈ IDμ μν¬λ¦Ώμ νκ²½ λ³μμμ λΆλ¬μ΅λλ€.
|
76 |
client_id = CLIENT_ID
|
77 |
client_secret = CLIENT_SECRET
|
78 |
+
|
79 |
# keywordκ° λ°μ΄νΈ νμ
μΌ κ²½μ° λμ½λ©
|
80 |
if isinstance(keyword, bytes):
|
81 |
keyword = keyword.decode('utf-8')
|
82 |
elif not isinstance(keyword, str):
|
83 |
keyword = str(keyword)
|
84 |
+
|
85 |
encText = urllib.parse.quote(keyword)
|
86 |
url = "https://openapi.naver.com/v1/search/blog?query=" + encText
|
87 |
request = urllib.request.Request(url)
|
|
|
107 |
def get_blog_count_parallel(keyword):
|
108 |
return (keyword, get_blog_count(keyword))
|
109 |
|
110 |
+
def get_search_volumes(keyword):
|
111 |
+
"""
|
112 |
+
λ¨μΌ ν€μλμ μ κ²μλμ κ°μ Έμ€λ ν¨μ.
|
113 |
+
"""
|
114 |
+
api = NaverAPI(BASE_URL, API_KEY, SECRET_KEY, CUSTOMER_ID)
|
115 |
+
try:
|
116 |
+
data = api.get_keywords_data([keyword])
|
117 |
+
if 'keywordList' in data and len(data['keywordList']) > 0:
|
118 |
+
item = data['keywordList'][0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
monthly_pc = item.get('monthlyPcQcCnt', 0)
|
120 |
monthly_mobile = item.get('monthlyMobileQcCnt', 0)
|
121 |
|
|
|
133 |
monthly_mobile = 0
|
134 |
|
135 |
total_searches = monthly_pc + monthly_mobile
|
136 |
+
return (keyword, monthly_pc, monthly_mobile, total_searches)
|
137 |
+
else:
|
138 |
+
return (keyword, 0, 0, 0)
|
139 |
+
except Exception as e:
|
140 |
+
print(f"Error fetching search volumes for keyword '{keyword}': {e}")
|
141 |
+
return (keyword, 0, 0, 0)
|
142 |
+
|
143 |
+
def get_monthly_search_volumes(keywords, include_related_keywords=True):
|
144 |
+
all_data = []
|
145 |
+
results = []
|
146 |
|
147 |
if include_related_keywords:
|
148 |
+
chunk_size = 10 # ν€μλλ₯Ό 10κ°μ© λλμ΄ μμ²
|
149 |
+
# API λ³λ ¬ μμ²
|
150 |
+
with ThreadPoolExecutor(max_workers=5) as executor:
|
151 |
+
futures = [executor.submit(get_keywords_data_chunk, keywords[i:i+chunk_size]) for i in range(0, len(keywords), chunk_size)]
|
152 |
+
for future in futures:
|
153 |
+
try:
|
154 |
+
data = future.result()
|
155 |
+
if 'keywordList' in data:
|
156 |
+
all_data.extend(data['keywordList'])
|
157 |
+
except Exception as e:
|
158 |
+
print(f"Error fetching keywords data chunk: {e}")
|
159 |
+
|
160 |
+
if not all_data:
|
161 |
+
return [("Error", "λ°μ΄ν°κ° λ°νλμ§ μμκ±°λ API μλ΅μ΄ μ ν¨νμ§ μμ΅λλ€.", "", "", "")]
|
162 |
+
|
163 |
+
unique_keywords = set()
|
164 |
+
for item in all_data:
|
165 |
+
keyword = item['relKeyword']
|
166 |
+
if keyword not in unique_keywords:
|
167 |
+
unique_keywords.add(keyword)
|
168 |
+
monthly_pc = item.get('monthlyPcQcCnt', 0)
|
169 |
+
monthly_mobile = item.get('monthlyMobileQcCnt', 0)
|
170 |
+
|
171 |
+
if isinstance(monthly_pc, str):
|
172 |
+
monthly_pc = monthly_pc.replace(',', '').replace('< 10', '0')
|
173 |
+
try:
|
174 |
+
monthly_pc = int(monthly_pc)
|
175 |
+
except ValueError:
|
176 |
+
monthly_pc = 0
|
177 |
+
if isinstance(monthly_mobile, str):
|
178 |
+
monthly_mobile = monthly_mobile.replace(',', '').replace('< 10', '0')
|
179 |
+
try:
|
180 |
+
monthly_mobile = int(monthly_mobile)
|
181 |
+
except ValueError:
|
182 |
+
monthly_mobile = 0
|
183 |
+
|
184 |
+
total_searches = monthly_pc + monthly_mobile
|
185 |
+
results.append((keyword, monthly_pc, monthly_mobile, total_searches))
|
186 |
+
|
187 |
+
if len(results) >= 100:
|
188 |
+
break
|
189 |
+
|
190 |
+
else:
|
191 |
+
# μ°κ΄κ²μμ΄λ₯Ό ν¬ν¨νμ§ μμΌλ―λ‘ μ
λ ₯ ν€μλλ§ μ²λ¦¬
|
192 |
with ThreadPoolExecutor(max_workers=5) as executor:
|
193 |
+
futures = [executor.submit(get_search_volumes, keyword) for keyword in keywords]
|
194 |
+
for future in futures:
|
195 |
+
try:
|
196 |
+
result = future.result()
|
197 |
+
results.append(result)
|
198 |
+
except Exception as e:
|
199 |
+
print(f"Error fetching search volumes for keyword '{keyword}': {e}")
|
200 |
+
results.append((keyword, 0, 0, 0))
|
201 |
+
|
202 |
+
if not results:
|
203 |
+
return [("Error", "λ°μ΄ν°κ° λ°νλμ§ μμκ±°λ API μλ΅μ΄ μ ν¨νμ§ μμ΅λλ€.", "", "", "")]
|
204 |
+
|
205 |
+
# λΈλ‘κ·Έ λ¬Έμ μ λ³λ ¬ μμ²
|
206 |
+
with ThreadPoolExecutor(max_workers=5) as executor:
|
207 |
+
if include_related_keywords:
|
208 |
blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
|
209 |
for i, future in enumerate(blog_futures):
|
210 |
try:
|
|
|
213 |
except Exception as e:
|
214 |
print(f"Error fetching blog count for keyword '{results[i][0]}': {e}")
|
215 |
results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], "Error")
|
216 |
+
else:
|
217 |
+
blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
|
|
|
|
|
218 |
temp_results = []
|
219 |
for future in blog_futures:
|
220 |
try:
|
|
|
237 |
return file_path
|
238 |
|
239 |
def display_search_volumes(keywords, include_related):
|
240 |
+
keyword_list = [keyword.strip() for keyword in keywords.split(',') if keyword.strip()]
|
241 |
+
if not keyword_list:
|
242 |
+
return [("Error", "μ
λ ₯λ ν€μλκ° μμ΅λλ€.", "", "", "")], None
|
243 |
results = get_monthly_search_volumes(keyword_list, include_related_keywords=include_related)
|
244 |
file_path = save_to_excel(results, keywords)
|
245 |
return results, file_path
|
|
|
247 |
iface = gr.Interface(
|
248 |
fn=display_search_volumes,
|
249 |
inputs=[
|
250 |
+
gr.Textbox(placeholder="ν€μλλ₯Ό μ
λ ₯νμΈμ (μΌνλ‘ κ΅¬λΆ)", lines=2),
|
251 |
gr.Checkbox(label="μ°κ΄κ²μμ΄ ν¬ν¨", value=True) # μ°κ΄κ²μμ΄ ν κΈ μΆκ°
|
252 |
],
|
253 |
outputs=[
|