2nd commit

This commit is contained in:
9700X_PC 2024-12-13 23:33:41 +09:00
parent 266de84acf
commit e2a33ebbb7
18 changed files with 414 additions and 45 deletions

12
config.ini Normal file
View File

@ -0,0 +1,12 @@
[Naver_API]
client_id = Uq5c9J_WdQYF8e2wOQT4
client_secret = y0CnrADAae
; client_id = 'HBcquewobashdSyPtBbE'
; client_secret = 't3tYyWYj1e'
[GPT_API]
api_key = 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
[Rapid_API]
url = https://taobao-datahub.p.rapidapi.com/item_search_image_2
x-rapidapi-key = cadd2a7246msh0dc206858f6e495p105151jsn7bdf01e8aa3f
x-rapidapi-host = taobao-datahub.p.rapidapi.com

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,12 +16,16 @@ class DBManager:
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
generatedTitle TEXT,
image_url TEXT,
price INTEGER,
Taoid TEXT,
TaoTitle TEXT,
Tao_URL TEXT,
Tao_image_url TEXT,
Tao_price INTEGER,
sold_price INTEGER,
translatedTitle TEXT,
tags TEXT,
category_code TEXT,
memo TEXT,
@ -52,14 +56,25 @@ class DBManager:
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("""
UPDATE products
SET Taoid = ?, Tao_URL = ?, Tao_image_url = ?, Tao_price = ?
WHERE id = ?
""", (
item.get("Taoid"), item.get("Tao_URL"), item.get("Tao_image_url"),
item.get("Tao_price"),item.get("id")
))
# 업데이트할 필드 구성
fields_to_update = {
"Taoid": item.get("Taoid"),
"Tao_URL": item.get("Tao_URL"),
"Tao_image_url": item.get("Tao_image_url"),
"Tao_price": item.get("Tao_price"),
"TaoTitle": item.get("TaoTitle"),
"translatedTitle": item.get("translatedTitle"),
"generatedTitle": item.get("generatedTitle"),
"sold_price": item.get("sold_price")
}
# 유효한 필드만 업데이트 SQL에 추가
set_clause = ", ".join(f"{key} = ?" for key in fields_to_update if fields_to_update[key] is not None)
values = [fields_to_update[key] for key in fields_to_update if fields_to_update[key] is not None]
values.append(item["id"]) # WHERE 조건에 사용
sql = f"UPDATE products SET {set_clause} WHERE id = ?"
cursor.execute(sql, values)
conn.commit()
conn.close()
self.logger.log(f"DB 데이터 업데이트 완료: ID={item['id']}", level=logging.DEBUG)

View File

@ -68,8 +68,8 @@ class ExcelExporter:
row_num = 4 + (index % 50)
self.logger.log(f"{index + 1}번째 행 기록 시작: B{row_num}, C{row_num}, D{row_num}, F{row_num}, G{row_num}, H{row_num}", level=logging.DEBUG) # 셀 위치 로그 추가
ws.range(f'B{row_num}').value = row['Tao_URL']
ws.range(f'C{row_num}').value = row['name']
ws.range(f'D{row_num}').value = row['price']
ws.range(f'C{row_num}').value = row['generatedTitle']
ws.range(f'D{row_num}').value = row['sold_price']
ws.range(f'F{row_num}').value = row['tags']
ws.range(f'G{row_num}').value = row['category_code']
ws.range(f'H{row_num}').value = row['memo']

View File

@ -11,12 +11,6 @@ class GPTClient:
self.model = model
self.temperature = temperature
client_id='Uq5c9J_WdQYF8e2wOQT4'
client_secret='y0CnrADAae'
self.gpt = GPTClient(self.logger, api_key='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')
def ask(self, prompt: str) -> str:
"""프롬프트를 이용하여 GPT 모델로부터 응답을 받습니다."""
try:

View File

@ -56,6 +56,19 @@ class KeywordManager(QDialog):
else:
QMessageBox.warning(self, "추가 실패", "금지어를 입력해주세요!")
def get_BAN_List(self):
"""
금지어 리스트를 반환합니다.
:return: 금지어 리스트
"""
try:
keywords = [self.keyword_list.item(i).text().strip() for i in range(self.keyword_list.count())]
self.logger.log(f"금지어 리스트 반환: {keywords}", level=logging.DEBUG)
return keywords
except Exception as e:
self.logger.log(f"금지어 리스트 반환 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
return []
def delete_keyword(self):
selected_items = self.keyword_list.selectedItems()
if selected_items:

View File

@ -1,6 +1,4 @@
from pywinauto import Application, findwindows, timings
from pywinauto.timings import wait_until
from pywinauto import Application, findwindows, timings
from pywinauto.controls.hwndwrapper import HwndWrapper
from typing import Dict, List
import os, sys

View File

@ -1,5 +1,5 @@
import requests
import logging
class NaverSearchAPI:
def __init__(self, client_id: str, client_secret: str, logger=None):
"""
@ -12,13 +12,6 @@ class NaverSearchAPI:
self.client_secret = client_secret
self.logger = logger
client_id='Uq5c9J_WdQYF8e2wOQT4'
client_secret='y0CnrADAae'
self.gpt = GPTClient(self.logger, api_key='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')
def search(self, query: str, display: int = 10, start: int = 1, sort: str = "sim") -> dict:
"""
네이버 검색 API로 검색어를 검색
@ -40,31 +33,34 @@ class NaverSearchAPI:
"sort": sort
}
print(f"self.client_id : {self.client_id}")
print(f"self.client_secret : {self.client_secret}")
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status() # HTTP 에러 발생 시 예외 처리
data = response.json()
if self.logger:
self.logger.info(f"네이버 검색 성공: {query}, 결과 개수: {len(data.get('items', []))}")
self.logger.log(f"네이버 검색 성공: {query}, 결과 개수: {len(data.get('items', []))}", level=logging.DEBUG)
return data
except requests.exceptions.RequestException as e:
if self.logger:
self.logger.error(f"네이버 검색 실패: {e}", exc_info=True)
self.logger.log(f"네이버 검색 실패: {e}", level=logging.DEBUG, exc_info=True)
return {"error": str(e)}
n_search = NaverSearchAPI(client_id='Uq5c9J_WdQYF8e2wOQT4', client_secret='y0CnrADAae')
# n_search = NaverSearchAPI(client_id='Uq5c9J_WdQYF8e2wOQT4', client_secret='y0CnrADAae')
query = "섬유 시편 원단 수동 절단기 컷팅기 샘플러 나이프"
search_results = n_search.search(query, display=20, start=1, sort="sim")
# query = "섬유 시편 원단 수동 절단기 컷팅기 샘플러 나이프"
# search_results = n_search.search(query, display=20, start=1, sort="sim")
if "error" in search_results:
print("검색 실패:", search_results["error"])
else:
for item in search_results.get("items", []):
print(f"{item}")
# print(f"상품명: {item['title']}, 가격: {item['lprice']}, 링크: {item['link']}")
# if "error" in search_results:
# print("검색 실패:", search_results["error"])
# else:
# for item in search_results.get("items", []):
# print(f"{item}")
# # print(f"상품명: {item['title']}, 가격: {item['lprice']}, 링크: {item['link']}")

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
Response URL: https://api.scopic.naver.com/whale?msgpad=1734050078279&md=KCQvMCC4%2Fv5NDFRPPWrGKehP3zU%3D
Status Code: 200
Headers: Headers[(b'date', b'Fri, 13 Dec 2024 00:34:41 GMT'), (b'content-type', b'application/json; charset=utf-8'), (b'content-length', b'1904'), (b'strict-transport-security', b'max-age=31536000; includeSubDomains')]
Body: {"id":"aHR0cHM6Ly9zYmlueC1waGluZi5wc3RhdGljLm5ldC9NakF5TkRFeU1UTmZPVElnL01EQXhOek0wTURVd01EZ3dNak0wLmU2UmlkNkpVeVJkYnQyY2plamQxU2pfQ0R0VFlPamJ6M2JzSzIydnVVVklnLldhZE9KdFFieGVjWDFxNVBvX3JtR3podDF5OXdISGttai1KV0FfQ0ZqTndnLlBORy9pbWFnZS5wbmc=","url":"https://m.search.naver.com/search.naver?sm=mob_len&qdt=0&query=%EC%95%85%EA%B8%B0%20%EC%BC%80%EC%9D%B4%EC%8A%A4%20%EA%B0%80%EB%B0%A9%20%ED%95%98%EB%93%9C%20%EC%86%8C%ED%94%84%ED%8A%B8%20%EC%B4%88%EA%B2%BD%EB%9F%89%20%EC%BA%90%EB%A6%AC%EC%96%B4%20%EC%83%89%EC%86%8C%ED%8F%B0%20%EB%B0%B1%ED%8C%A9%20%EC%A4%91%20%EC%88%98%EB%82%A9%20E%EC%8A%A4%ED%94%BC%EC%BB%A4%20%EC%82%AD%EC%8A%A4%20%EB%B0%B1%20%EC%88%84%EB%8D%94%20%EC%8A%A4%ED%80%98%EC%96%B4%20%EB%B0%B4%EB%93%9C%20%EC%9D%B8%ED%83%80%EC%9D%B4%EC%96%B4&x_sbi=%7B%22coord%22%3A%22x%3A15%2Cy%3A108%2Cw%3A179%2Ch%3A378%22%2C%22from%22%3A%22nx_shpcamera%22%2C%22query%22%3A%22%EC%95%85%EA%B8%B0%20%EC%BC%80%EC%9D%B4%EC%8A%A4%20%EA%B0%80%EB%B0%A9%20%ED%95%98%EB%93%9C%20%EC%86%8C%ED%94%84%ED%8A%B8%20%EC%B4%88%EA%B2%BD%EB%9F%89%20%EC%BA%90%EB%A6%AC%EC%96%B4%20%EC%83%89%EC%86%8C%ED%8F%B0%20%EB%B0%B1%ED%8C%A9%20%EC%A4%91%20%EC%88%98%EB%82%A9%20E%EC%8A%A4%ED%94%BC%EC%BB%A4%20%EC%82%AD%EC%8A%A4%20%EB%B0%B1%20%EC%88%84%EB%8D%94%20%EC%8A%A4%ED%80%98%EC%96%B4%20%EB%B0%B4%EB%93%9C%20%EC%9D%B8%ED%83%80%EC%9D%B4%EC%96%B4%22%2C%22querytype%22%3A%22shopping%22%2C%22sbiid%22%3A%22aHR0cHM6Ly9zYmlueC1waGluZi5wc3RhdGljLm5ldC9NakF5TkRFeU1UTmZPVElnL01EQXhOek0wTURVd01EZ3dNak0wLmU2UmlkNkpVeVJkYnQyY2plamQxU2pfQ0R0VFlPamJ6M2JzSzIydnVVVklnLldhZE9KdFFieGVjWDFxNVBvX3JtR3podDF5OXdISGttai1KV0FfQ0ZqTndnLlBORy9pbWFnZS5wbmc%3D%22%7D&x_image=%7B%22NDI%22%3A1%7D&mra=QkRS%5ETE5F%5EU1BI%5EUkxF%5EVWJHX0xSbQ%3D%3D","imageUrl":"https://sbinx-phinf.pstatic.net/MjAyNDEyMTNfOTIg/MDAxNzM0MDUwMDgwMjM0.e6Rid6JUyRdbt2cjejd1Sj_CDtTYOjbz3bsK22vuUVIg.WadOJtQbxecX1q5Po_rmGzht1y9wHHkmj-JWA_CFjNwg.PNG/image.png","target":"real","status":"ok"}

26
src/res/res.py Normal file
View File

@ -0,0 +1,26 @@
from mitmproxy import http
import os
OUTPUT_DIR = "captured_data"
# 디렉토리 생성
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
def request(flow: http.HTTPFlow):
# 요청 URL 저장
with open(os.path.join(OUTPUT_DIR, "requests.txt"), "a", encoding="utf-8") as f:
f.write(f"Request URL: {flow.request.url}\n")
f.write(f"Headers: {flow.request.headers}\n")
f.write(f"Body: {flow.request.content}\n")
f.write("\n")
def response(flow: http.HTTPFlow):
# 특정 URL에 대한 응답 데이터 저장
if "api.scopic.naver.com" in flow.request.url:
with open(os.path.join(OUTPUT_DIR, "responses.txt"), "a", encoding="utf-8") as f:
f.write(f"Response URL: {flow.request.url}\n")
f.write(f"Status Code: {flow.response.status_code}\n")
f.write(f"Headers: {flow.response.headers}\n")
f.write(f"Body: {flow.response.text}\n")
f.write("\n")

View File

@ -4,6 +4,9 @@ from PySide6.QtWidgets import (
QPushButton, QTableWidget, QTableWidgetItem, QTextEdit, QMessageBox, QCheckBox
)
from PySide6.QtCore import Qt
import configparser
import math
from deep_translator import GoogleTranslator
from src.export_xls import ExcelExporter
from src.db_manager import DBManager
@ -12,12 +15,24 @@ import pandas as pd
from src.keyword_manager import KeywordManager
from src.categoryManager import CategoryManager
from src.tables import CustomTableWidget
from src.naverAPI import NaverSearchAPI
from src.gpt_Client import GPTClient
import requests
class UIManager(QMainWindow):
def __init__(self, logger):
super().__init__()
self.logger = logger
# Config 파일 읽기
self.config = self.load_config("config.ini")
self.naver_client_id = self.config.get("Naver_API", "client_id")
self.naver_client_secret = self.config.get("Naver_API", "client_secret")
self.gpt_api_key = self.config.get("GPT_API", "api_key")
self.rapid_api_url = self.config.get("Rapid_API", "url")
self.rapid_api_key = self.config.get("Rapid_API", "x-rapidapi-key")
self.rapid_api_host = self.config.get("Rapid_API", "x-rapidapi-host")
self.logger.log("UI Manager 초기화 중...", level=logging.DEBUG)
# 윈도우 설정
@ -31,6 +46,10 @@ class UIManager(QMainWindow):
baseXLS_path = os.path.join("resources", "baseXLS_Percenty.xlsx")
self.excel_exporter = ExcelExporter(self.logger, self.db_manager, base_excel_path=baseXLS_path)
self.category_manager = CategoryManager(logger=self.logger, excel_path=baseXLS_path)
self.naverAPI = NaverSearchAPI(client_id=self.naver_client_id, client_secret=self.naver_client_secret, logger=self.logger)
self.gpt = GPTClient(logger=self.logger, api_key=self.gpt_api_key)
self.keyword_manager = KeywordManager(self.logger, self)
self.gtranslator = GoogleTranslator(source="zh-CN", target="ko")
# 메인 레이아웃 설정
self.central_widget = QWidget()
@ -41,6 +60,7 @@ class UIManager(QMainWindow):
# 버튼 설정
self.folder_button = QPushButton("폴더 선택")
self.api_button = QPushButton("API 호출")
self.post_button = QPushButton("후처리")
self.export_button = QPushButton("엑셀 출력")
self.keyword_button = QPushButton("금지어 관리")
@ -61,6 +81,7 @@ class UIManager(QMainWindow):
button_layout = QHBoxLayout()
button_layout.addWidget(self.folder_button)
button_layout.addWidget(self.api_button)
button_layout.addWidget(self.post_button)
button_layout.addWidget(self.export_button)
button_layout.addWidget(self.keyword_button)
@ -72,6 +93,7 @@ class UIManager(QMainWindow):
# 버튼 이벤트 연결
self.folder_button.clicked.connect(self.select_folder)
self.api_button.clicked.connect(self.call_api)
self.post_button.clicked.connect(self.post_data)
self.export_button.clicked.connect(self.export_data)
self.keyword_button.clicked.connect(self.manage_keywords)
@ -106,6 +128,18 @@ class UIManager(QMainWindow):
self.logger.log(f"엑셀 파일 처리 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
QMessageBox.critical(self, "폴더 선택", "엑셀 파일 처리 중 오류가 발생했습니다!")
def load_config(self, file_path: str) -> configparser.ConfigParser:
"""
config.ini 파일을 읽어서 ConfigParser 객체로 반환
"""
config = configparser.ConfigParser()
try:
config.read(file_path)
self.logger.log(f"Config 파일 '{file_path}' 로드 성공", level=logging.INFO)
except Exception as e:
self.logger.log(f"Config 파일 로드 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
return config
def load_keywords(self):
"""
금지어 목록을 파일에서 로드합니다.
@ -219,14 +253,13 @@ class UIManager(QMainWindow):
product_id = int(self.table.item(row, 1).text()) # ID 값은 1번째 열
# API 호출
url = "https://taobao-datahub.p.rapidapi.com/item_search_image_2"
querystring = {"imgUrl": image_url, "pageSize": "10"}
headers = {
"x-rapidapi-key": "cadd2a7246msh0dc206858f6e495p105151jsn7bdf01e8aa3f", # RapidAPI 키를 입력하세요
"x-rapidapi-host": "taobao-datahub.p.rapidapi.com"
"x-rapidapi-key": self.rapid_api_key, # RapidAPI 키를 입력하세요
"x-rapidapi-host": self.rapid_api_host
}
response = requests.get(url, headers=headers, params=querystring)
response = requests.get(self.rapid_api_url, headers=headers, params=querystring)
response.raise_for_status()
# 응답 데이터 파싱
@ -244,6 +277,10 @@ class UIManager(QMainWindow):
self.logger.log(f"선택된 상품: {top_item}", level=logging.INFO)
self.log_text.append(f"선택된 상품 ID={tao_id}, 가격={top_item['price']}, 이미지 URL={top_item['image']}")
translatedTitle = self.translate_name(top_item["title"])
self.logger.log(f"원본 상품명: {top_item["title"]}", level=logging.DEBUG)
self.logger.log(f"번역된 상품: {translatedTitle}", level=logging.DEBUG)
# 결과를 DB에 저장
self.db_manager.update_item({
"id": product_id, # ID 추가
@ -251,6 +288,8 @@ class UIManager(QMainWindow):
"Tao_URL": tao_url,
"Tao_image_url": top_item["image"],
"Tao_price": top_item["price"],
"TaoTitle": top_item["title"],
"translatedTitle": translatedTitle,
})
# 테이블 업데이트
self.table.setItem(row, 5, QTableWidgetItem(f"ID={tao_id}, 가격={top_item['price']}"))
@ -263,6 +302,142 @@ class UIManager(QMainWindow):
self.table.setItem(row, 5, QTableWidgetItem("API 호출 실패"))
self.log_text.append(f"API 호출 실패: 이미지 URL={image_url}")
def translate_name(self, text: str) -> str:
"""
중국어 텍스트를 한국어로 번역하는 메서드
:param text: 번역할 텍스트
:return: 번역된 한국어 텍스트
"""
if not text.strip():
self.logger.log(f"빈 텍스트가 입력되었습니다.", level=logging.WARNING)
return ""
try:
# 번역 수행
result = self.gtranslator.translate(text)
self.logger.log(f"번역 성공: {text} -> {result}", level=logging.DEBUG)
return result
except Exception as e:
self.logger.log(f"번역 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
return "번역 실패"
def is_valid_word(self, word: str) -> bool:
"""숫자로만 이루어진 단어 또는 영어와 숫자로만 이루어진 단어를 검증하는 함수."""
return not (word.isdigit() or re.fullmatch(r'[A-Za-z0-9]+', word))
def extract_special_words(self, original_name: str) -> list:
"""원본 상품명에서 숫자로만 이루어진 단어와 영어와 숫자로만 이루어진 단어를 추출하는 함수."""
return [word for word in original_name.split() if word.isdigit() or re.fullmatch(r'[A-Za-z0-9]+', word)]
def filter_invalid_words(self, words: list) -> list:
"""영어만 이루어진 단어와 영어와 숫자로 이루어진 단어를 제외하는 함수."""
return [word for word in words if not re.fullmatch(r'[A-Za-z0-9]+', word)]
def clean_text(self, text):
"""
입력 문자열에서 특수문자를 제거하고 정리된 문자열 반환.
"""
# 정규식으로 특수문자를 공백으로 치환
return re.sub(r"[^\w\s]", " ", text)
def post_data(self):
"""
DB에서 데이터를 가져와 NaverSearchAPI를 사용하여 후처리.
상품명을 생성하고 판매 가격을 계산하여 DB에 업데이트.
"""
try:
# DB에서 모든 데이터 가져오기
data = self.db_manager.fetch_all()
if data.empty:
self.logger.log("DB에서 가져온 데이터가 없습니다.", level=logging.WARNING)
return
for _, row in data.iterrows():
item_id = row["id"]
query = row["name"]
originalTitle = row["TaoTitle"]
# 검색 키워드 설정: 첫 4개의 단어 추출
search_keywords = " ".join(query.split()[:4])
self.logger.log(f"검색 실행: {search_keywords} (ID: {item_id})", level=logging.INFO)
# 네이버 API 호출
search_results = self.naverAPI.search(query=search_keywords)
items = search_results.get("items", [])
if not items:
self.logger.log(f"검색 결과가 없습니다: {search_keywords}", level=logging.WARNING)
continue
# 상품명 리스트 처리
titles = [self.strip_tags(item["title"]) for item in items]
# 특수문자 제거 및 단어 분리
cleaned_titles = [self.clean_text(title) for title in titles]
# 단어 단위로 분리 후 중복 제거
keyword_title = set(" ".join(cleaned_titles).split())
# 숫자나 영어 또는 숫자로만 이루어진 단어 필터링
keyword_title = [word for word in keyword_title if self.is_valid_word(word)]
self.logger.log(f"keyword_title after filtering invalid words : {keyword_title}", level=logging.DEBUG)
# 7. 원본 상품명에서 숫자 또는 영어와 숫자로만 이루어진 단어 추출 및 포함
special_words = self.extract_special_words(originalTitle)
self.logger.log(f"special_words from original_name: {special_words}", level=logging.DEBUG)
keyword_title.extend(special_words)
# 금지어 필터링
ban_keyword = self.keyword_manager.get_BAN_List()
self.logger.log(f"ban_keyword: {ban_keyword}", level=logging.DEBUG)
filtered_words = [word for word in keyword_title if word not in ban_keyword]
# GPT를 사용한 상품명 생성
generated_name = self.gpt.generate_product_name_next(filtered_words, originalTitle, titles, unique_first_two_words=special_words)
self.logger.log(f"생성된 상품명: {generated_name} (ID: {item_id})", level=logging.INFO)
# 2. 가격 계산
prices = [float(item["lprice"]) for item in items if item["lprice"].isdigit()]
prices.append(float(row["price"])) # 기존 DB의 가격 포함
avg_price = sum(prices) / len(prices)
median_price = sorted(prices)[len(prices) // 2]
final_price = max(avg_price, median_price) # 평균값과 중간값 중 큰 값
# 1000원 단위로 올림
final_price = math.ceil(final_price / 1000) * 1000
avg_price = math.ceil(avg_price / 1000) * 1000
median_price = math.ceil(median_price / 1000) * 1000
self.logger.log(f"계산된 판매 가격: {final_price} (ID: {item_id})", level=logging.INFO)
# DB 업데이트
self.db_manager.update_item({
"id": item_id,
"generatedTitle": generated_name,
"sold_price": final_price
})
self.logger.log("후처리 완료.", level=logging.INFO)
except Exception as e:
self.logger.log(f"후처리 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
def strip_tags(self, html: str) -> str:
"""
HTML 태그를 제거하여 순수 텍스트만 반환.
"""
import re
return re.sub(r"<.*?>", "", html)
def get_banned_words(self):
"""
금지어 목록 반환 (: 파일이나 DB에서 불러올 있음).
"""
return ["금지어1", "금지어2"] # 실제 금지어 목록으로 대체
def export_data(self):
success = self.excel_exporter.save_to_excel()
if success:
@ -272,8 +447,7 @@ class UIManager(QMainWindow):
def manage_keywords(self):
self.logger.log("금지어 관리 버튼 클릭됨", level=logging.DEBUG)
keyword_manager = KeywordManager(self.logger, self)
keyword_manager.exec()
self.keyword_manager.exec()
# def populate_table(self):
# # 테이블 초기화
@ -352,6 +526,7 @@ class UIManager(QMainWindow):
items = []
for entry in result_list:
item = entry.get("item", {})
# title = entry.get("title", {})
sales_str = entry.get("item", {}).get("sales", "0").replace("+", "") # "+" 제거
sales = self.parse_sales(sales_str) # 판매량 변환
@ -367,6 +542,7 @@ class UIManager(QMainWindow):
items.append({
"itemId": item.get("itemId"),
"image": item.get("image"),
"title": item.get("title"),
"price": price,
"promotionPrice": promotion_price,
"sales": sales
@ -381,7 +557,8 @@ class UIManager(QMainWindow):
return {
"itemId": top_item["itemId"],
"image": f"https:{top_item['image']}", # URL 앞에 "https:" 추가
"price": top_item["price"]
"price": top_item["price"],
"title": top_item["title"]
}
return None # 유효한 상품이 없으면 None 반환