Kims12 commited on
Commit
71ba060
Β·
verified Β·
1 Parent(s): 863de1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -47
app.py CHANGED
@@ -75,6 +75,13 @@ def get_blog_count(keyword):
75
  # ν΄λΌμ΄μ–ΈνŠΈ ID와 μ‹œν¬λ¦Ώμ„ ν™˜κ²½ λ³€μˆ˜μ—μ„œ λΆˆλŸ¬μ˜΅λ‹ˆλ‹€.
76
  client_id = CLIENT_ID
77
  client_secret = CLIENT_SECRET
 
 
 
 
 
 
 
78
  encText = urllib.parse.quote(keyword)
79
  url = "https://openapi.naver.com/v1/search/blog?query=" + encText
80
  request = urllib.request.Request(url)
@@ -86,7 +93,7 @@ def get_blog_count(keyword):
86
  if rescode == 200:
87
  response_body = response.read()
88
  data = json.loads(response_body.decode('utf-8'))
89
- return data['total']
90
  else:
91
  return 0
92
  except Exception as e:
@@ -100,54 +107,127 @@ def get_keywords_data_chunk(chunk):
100
  def get_blog_count_parallel(keyword):
101
  return (keyword, get_blog_count(keyword))
102
 
103
- def get_monthly_search_volumes(keywords):
104
- all_data = []
105
- chunk_size = 10 # ν‚€μ›Œλ“œλ₯Ό 10κ°œμ”© λ‚˜λˆ„μ–΄ μš”μ²­
 
 
 
 
 
 
 
 
 
 
106
 
107
- # API 병렬 μš”μ²­
108
- with ThreadPoolExecutor(max_workers=5) as executor:
109
- futures = [executor.submit(get_keywords_data_chunk, keywords[i:i+chunk_size]) for i in range(0, len(keywords), chunk_size)]
110
- for future in futures:
111
- try:
112
- data = future.result()
113
- if 'keywordList' in data:
114
- all_data.extend(data['keywordList'])
115
- except Exception as e:
116
- print(f"Error fetching keywords data chunk: {e}")
117
-
118
- if not all_data:
119
- return [("Error", "데이터가 λ°˜ν™˜λ˜μ§€ μ•Šμ•˜κ±°λ‚˜ API 응닡이 μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.", "", "", "")] # λΈ”λ‘œκ·Έ λ¬Έμ„œ 수 칼럼 μΆ”κ°€
 
 
 
 
 
 
 
 
 
120
 
 
 
121
  results = []
122
- unique_keywords = set()
123
- for item in all_data:
124
- keyword = item['relKeyword']
125
- if keyword not in unique_keywords:
126
- unique_keywords.add(keyword)
127
- monthly_pc = item['monthlyPcQcCnt']
128
- monthly_mobile = item['monthlyMobileQcCnt']
129
-
130
- if isinstance(monthly_pc, str):
131
- monthly_pc = int(monthly_pc.replace(',', '').replace('< 10', '0'))
132
- if isinstance(monthly_mobile, str):
133
- monthly_mobile = int(monthly_mobile.replace(',', '').replace('< 10', '0'))
134
-
135
- total_searches = monthly_pc + monthly_mobile
136
- results.append((keyword, monthly_pc, monthly_mobile, total_searches))
 
137
 
138
- if len(results) >= 100:
139
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # λΈ”λ‘œκ·Έ λ¬Έμ„œ 수 병렬 μš”μ²­
142
  with ThreadPoolExecutor(max_workers=5) as executor:
143
- blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
144
- for i, future in enumerate(blog_futures):
145
- try:
146
- keyword, blog_count = future.result()
147
- results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], blog_count)
148
- except Exception as e:
149
- print(f"Error fetching blog count for keyword '{results[i][0]}': {e}")
150
- results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], "Error")
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  return results
153
 
@@ -160,20 +240,26 @@ def save_to_excel(results, keyword):
160
  df.to_excel(file_path, index=False)
161
  return file_path
162
 
163
- def display_search_volumes(keywords):
164
- keyword_list = [keyword.strip() for keyword in keywords.split(',')]
165
- results = get_monthly_search_volumes(keyword_list)
 
 
166
  file_path = save_to_excel(results, keywords)
167
  return results, file_path
168
 
169
  iface = gr.Interface(
170
  fn=display_search_volumes,
171
- inputs=gr.Textbox(placeholder="ν‚€μ›Œλ“œλ₯Ό μž…λ ₯ν•˜μ„Έμš”"),
 
 
 
172
  outputs=[
173
  gr.Dataframe(headers=["ν‚€μ›Œλ“œ", "PCμ›”κ²€μƒ‰λŸ‰", "λͺ¨λ°”μΌμ›”κ²€μƒ‰λŸ‰", "ν† νƒˆμ›”κ²€μƒ‰λŸ‰", "λΈ”λ‘œκ·Έλ¬Έμ„œμˆ˜"]),
174
  gr.File(label="λ‹€μš΄λ‘œλ“œ μ—‘μ…€ 파일")
175
  ],
176
  title="넀이버 μ›”κ²€μƒ‰λŸ‰ 검색기",
 
177
  )
178
 
179
- iface.launch(share=True) # share=Trueλ₯Ό μΆ”κ°€ν•˜μ—¬ 곡개 링크 생성
 
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)
 
93
  if rescode == 200:
94
  response_body = response.read()
95
  data = json.loads(response_body.decode('utf-8'))
96
+ return data.get('total', 0)
97
  else:
98
  return 0
99
  except Exception as e:
 
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
+ # keywordListμ—μ„œ μž…λ ₯ν•œ ν‚€μ›Œλ“œμ™€ μΌμΉ˜ν•˜λŠ” ν•­λͺ©μ„ μ°ΎμŠ΅λ‹ˆλ‹€.
119
+ for item in data['keywordList']:
120
+ if item['relKeyword'].strip().lower() == keyword.strip().lower():
121
+ monthly_pc = item.get('monthlyPcQcCnt', 0)
122
+ monthly_mobile = item.get('monthlyMobileQcCnt', 0)
123
 
124
+ if isinstance(monthly_pc, str):
125
+ monthly_pc = monthly_pc.replace(',', '').replace('< 10', '0')
126
+ try:
127
+ monthly_pc = int(monthly_pc)
128
+ except ValueError:
129
+ monthly_pc = 0
130
+ if isinstance(monthly_mobile, str):
131
+ monthly_mobile = monthly_mobile.replace(',', '').replace('< 10', '0')
132
+ try:
133
+ monthly_mobile = int(monthly_mobile)
134
+ except ValueError:
135
+ monthly_mobile = 0
136
+
137
+ total_searches = monthly_pc + monthly_mobile
138
+ return (keyword, monthly_pc, monthly_mobile, total_searches)
139
+ # μž…λ ₯ν•œ ν‚€μ›Œλ“œμ™€ μΌμΉ˜ν•˜λŠ” ν•­λͺ©μ΄ 없을 경우
140
+ return (keyword, 0, 0, 0)
141
+ else:
142
+ return (keyword, 0, 0, 0)
143
+ except Exception as e:
144
+ print(f"Error fetching search volumes for keyword '{keyword}': {e}")
145
+ return (keyword, 0, 0, 0)
146
 
147
+ def get_monthly_search_volumes(keywords, include_related_keywords=True):
148
+ all_data = []
149
  results = []
150
+
151
+ if include_related_keywords:
152
+ chunk_size = 10 # ν‚€μ›Œλ“œλ₯Ό 10κ°œμ”© λ‚˜λˆ„μ–΄ μš”μ²­
153
+ # API 병렬 μš”μ²­
154
+ with ThreadPoolExecutor(max_workers=5) as executor:
155
+ futures = [executor.submit(get_keywords_data_chunk, keywords[i:i+chunk_size]) for i in range(0, len(keywords), chunk_size)]
156
+ for future in futures:
157
+ try:
158
+ data = future.result()
159
+ if 'keywordList' in data:
160
+ all_data.extend(data['keywordList'])
161
+ except Exception as e:
162
+ print(f"Error fetching keywords data chunk: {e}")
163
+
164
+ if not all_data:
165
+ return [("Error", "데이터가 λ°˜ν™˜λ˜μ§€ μ•Šμ•˜κ±°λ‚˜ API 응닡이 μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.", "", "", "")]
166
 
167
+ unique_keywords = set()
168
+ for item in all_data:
169
+ keyword = item['relKeyword']
170
+ if keyword not in unique_keywords:
171
+ unique_keywords.add(keyword)
172
+ monthly_pc = item.get('monthlyPcQcCnt', 0)
173
+ monthly_mobile = item.get('monthlyMobileQcCnt', 0)
174
+
175
+ if isinstance(monthly_pc, str):
176
+ monthly_pc = monthly_pc.replace(',', '').replace('< 10', '0')
177
+ try:
178
+ monthly_pc = int(monthly_pc)
179
+ except ValueError:
180
+ monthly_pc = 0
181
+ if isinstance(monthly_mobile, str):
182
+ monthly_mobile = monthly_mobile.replace(',', '').replace('< 10', '0')
183
+ try:
184
+ monthly_mobile = int(monthly_mobile)
185
+ except ValueError:
186
+ monthly_mobile = 0
187
+
188
+ total_searches = monthly_pc + monthly_mobile
189
+ results.append((keyword, monthly_pc, monthly_mobile, total_searches))
190
+
191
+ if len(results) >= 100:
192
+ break
193
 
194
+ else:
195
+ # 연관검색어λ₯Ό ν¬ν•¨ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μž…λ ₯ ν‚€μ›Œλ“œλ§Œ 처리
196
+ with ThreadPoolExecutor(max_workers=5) as executor:
197
+ futures = [executor.submit(get_search_volumes, keyword) for keyword in keywords]
198
+ for future in futures:
199
+ try:
200
+ result = future.result()
201
+ results.append(result)
202
+ except Exception as e:
203
+ print(f"Error fetching search volumes for keyword '{keyword}': {e}")
204
+ results.append((keyword, 0, 0, 0))
205
+
206
+ if not results:
207
+ return [("Error", "데이터가 λ°˜ν™˜λ˜μ§€ μ•Šμ•˜κ±°λ‚˜ API 응닡이 μœ νš¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.", "", "", "")]
208
+
209
  # λΈ”λ‘œκ·Έ λ¬Έμ„œ 수 병렬 μš”μ²­
210
  with ThreadPoolExecutor(max_workers=5) as executor:
211
+ if include_related_keywords:
212
+ blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
213
+ for i, future in enumerate(blog_futures):
214
+ try:
215
+ keyword, blog_count = future.result()
216
+ results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], blog_count)
217
+ except Exception as e:
218
+ print(f"Error fetching blog count for keyword '{results[i][0]}': {e}")
219
+ results[i] = (results[i][0], results[i][1], results[i][2], results[i][3], "Error")
220
+ else:
221
+ blog_futures = [executor.submit(get_blog_count_parallel, result[0]) for result in results]
222
+ temp_results = []
223
+ for future in blog_futures:
224
+ try:
225
+ keyword, blog_count = future.result()
226
+ temp_results.append((keyword, results[0][1], results[0][2], results[0][3], blog_count))
227
+ except Exception as e:
228
+ print(f"Error fetching blog count for keyword '{keyword}': {e}")
229
+ temp_results.append((keyword, results[0][1], results[0][2], results[0][3], "Error"))
230
+ results = temp_results
231
 
232
  return results
233
 
 
240
  df.to_excel(file_path, index=False)
241
  return file_path
242
 
243
+ def display_search_volumes(keywords, include_related):
244
+ keyword_list = [keyword.strip() for keyword in keywords.split(',') if keyword.strip()]
245
+ if not keyword_list:
246
+ return [("Error", "μž…λ ₯된 ν‚€μ›Œλ“œκ°€ μ—†μŠ΅λ‹ˆλ‹€.", "", "", "")], None
247
+ results = get_monthly_search_volumes(keyword_list, include_related_keywords=include_related)
248
  file_path = save_to_excel(results, keywords)
249
  return results, file_path
250
 
251
  iface = gr.Interface(
252
  fn=display_search_volumes,
253
+ inputs=[
254
+ gr.Textbox(placeholder="ν‚€μ›Œλ“œλ₯Ό μž…λ ₯ν•˜μ„Έμš” (μ‰Όν‘œλ‘œ ꡬ뢄)", lines=2),
255
+ gr.Checkbox(label="연관검색어 포함", value=True) # 연관검색어 ν† κΈ€ μΆ”κ°€
256
+ ],
257
  outputs=[
258
  gr.Dataframe(headers=["ν‚€μ›Œλ“œ", "PCμ›”κ²€μƒ‰λŸ‰", "λͺ¨λ°”μΌμ›”κ²€μƒ‰λŸ‰", "ν† νƒˆμ›”κ²€μƒ‰λŸ‰", "λΈ”λ‘œκ·Έλ¬Έμ„œμˆ˜"]),
259
  gr.File(label="λ‹€μš΄λ‘œλ“œ μ—‘μ…€ 파일")
260
  ],
261
  title="넀이버 μ›”κ²€μƒ‰λŸ‰ 검색기",
262
+ description="ν‚€μ›Œλ“œμ˜ μ›” κ²€μƒ‰λŸ‰κ³Ό λΈ”λ‘œκ·Έ λ¬Έμ„œ 수λ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 연관검색어λ₯Ό 포함할지 μ„ νƒν•˜μ„Έμš”.",
263
  )
264
 
265
+ iface.launch(share=True) # share=Trueλ₯Ό μΆ”κ°€ν•˜μ—¬ 곡개 링크 생성