추가수정

This commit is contained in:
R5600U_PC 2024-04-09 16:12:09 +09:00
parent 25b6e7ba63
commit 8f96b7198d
13 changed files with 756 additions and 457 deletions

View File

@ -1,5 +1,4 @@
from playwright.sync_api import sync_playwright
<<<<<<< HEAD
import random
import logging
@ -11,23 +10,25 @@ def trans_text(original_text):
try:
# Playwright 브라우저 인스턴스 생성 (헤드리스 모드)
browser = p.chromium.launch(headless=True) # 여기서 headless=False로 설정하면 GUI 모드로 실행
page = browser.new_page()
# PC 사용자 에이전트 중 하나를 랜덤하게 선택
USER_AGENTS = [
# 동영상 녹화 설정을 포함하여 브라우저 컨텍스트 생성
context = browser.new_context(
user_agent=random.choice([
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/85.0.0.0"
]
random_user_agent = random.choice(USER_AGENTS)
context = browser.new_context(user_agent=random_user_agent)
]),
# # 동영상 녹화 설정 추가
# record_video_dir="videos/", # 동영상이 저장될 디렉토리 지정
# record_video_size={"width": 1280, "height": 720} # 동영상 크기 지정
)
page = context.new_page()
# DeepL 웹사이트 접속
page.goto('https://www.deepl.com/ko/translator')
# page.goto('https://www.deepl.com/ko/translator')
page.goto('https://www.deepl.com/translator#zh/ko/'+ original_text)
# JavaScript를 사용하여 편집 가능한 div에 텍스트 입력
page.evaluate("""(text) => {
@ -42,7 +43,9 @@ def trans_text(original_text):
# "visible": 요소가 DOM에 삽입되어 있으며 렌더링된 상태(화면에 보이는 상태)임을 의미합니다. CSS를 통해 숨겨진 요소는 visible 상태에 해당하지 않습니다.
# "hidden": 요소가 DOM에 존재하지 않거나 렌더링되지 않아 화면에 보이지 않음을 의미합니다. 이는 요소가 아예 존재하지 않거나, CSS 등을 통해 숨겨진 경우에 해당합니다.
# timeout=10000 (10초 내에 해당요소가 "state" 될때까지 대기)
page.wait_for_function('document.querySelector("[data-testid="translator-target-input"]").textContent.length > 0')
# page.wait_for_function('document.querySelector("[data-testid="translator-target-input"]").textContent.length > 0')
# page.wait_for_function('document.querySelector(\'[data-testid="translator-target-input"]\').textContent.length > 0')
page.wait_for_function("document.querySelector(\"[data-testid='translator-target-input']\").textContent.length > 0")
page.wait_for_selector('[data-testid="translator-target-input"]', state="visible", timeout=10000)
translated_text = page.text_content('[data-testid="translator-target-input"]')
@ -68,10 +71,75 @@ def trans_text(original_text):
return "에러발생으로 인한 번역 실패."
finally:
if browser: # browser가 초기화되었는지 확인
if context: # context가 초기화되었는지 확인하고, 종료
context.close()
if browser: # browser가 초기화되었는지 확인하고, 종료
browser.close()
logger.info("playwright Browser 닫힘.")
return translated_text
=======
>>>>>>> 4b4ff58484a1cc6a2080061367ea02ec8d38e8b7
def trans_list_text(original_texts):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # 여기서 headless=False로 설정하면 GUI 모드로 실행
# 동영상 녹화 설정을 포함하여 브라우저 컨텍스트 생성
context = browser.new_context(
user_agent=random.choice([
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 OPR/85.0.0.0"
]),
# # 동영상 녹화 설정 추가
# record_video_dir="videos/", # 동영상이 저장될 디렉토리 지정
# record_video_size={"width": 1280, "height": 720} # 동영상 크기 지정
)
page = context.new_page()
page.goto('https://www.deepl.com/translator#zh/ko/')
translated_texts = [] # 번역된 텍스트를 저장할 리스트
for text in original_texts:
# contenteditable 속성을 가진 div에 텍스트를 직접 설정
# page.evaluate("""(text) => {
# const editor = document.querySelector('[data-testid="translator-source-input"] div[contenteditable="true"]');
# editor.textContent = text;
# }""", text)
page.evaluate("""(text) => {
const editor = document.querySelector('[data-testid="translator-source-input"] div[contenteditable="true"]');
editor.textContent = text;
const inputEvent = new Event('input', { bubbles: true });
editor.dispatchEvent(inputEvent);
}""", text)
# 번역이 완료될 때까지 기다림
page.wait_for_function("document.querySelector(\"[data-testid='translator-target-input']\").textContent.length > 0")
page.wait_for_selector('[data-testid="translator-target-input"]', state="visible", timeout=10000)
# 번역된 텍스트 추출
translated_text = page.text_content('[data-testid="translator-target-input"]')
translated_texts.append(translated_text.strip())
browser.close()
return translated_texts
# ttt = '''
# 贴片款(小号) 240*300mm\n\n
# 贴片款(中号) 440*315mm\n\n
# 贴片款(大号) 590*440mm\n\n
# '''
# tttt = trans_text(ttt)
# # test = []
# # test.append('贴片款(小号) 240*300mm')
# # test.append('贴片款(中号) 440*315mm')
# # test.append('贴片款(大号) 590*440mm')
# # translated_text = trans_list_text(test)
# print(f"번역된 글자 : {ttt}")

View File

@ -240,6 +240,17 @@ def find_delivery_fee(weight, delv_collection):
# return product_info_text
def original_html(current_html):
# BeautifulSoup 객체 생성
soup = BeautifulSoup(current_html, 'html.parser')
# "img class='image_resized'" 태그만 추출
resized_images = soup.find_all('img', class_='image_resized')
# 추출된 태그들로 새로운 HTML 문자열 생성
original_html_text = ''.join(str(tag) for tag in resized_images)
return original_html_text
def NS_info_with_HTML(products):
# 상품 정보를 담을 5x1 표 생성
@ -534,16 +545,17 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
try:
# # data-value 속성 값을 가져옵니다.
current_value = textarea.get_attribute("data-value")
original_html_tags = original_html(current_value)
# logger.debug(f"현재 속성값 :{current_value}")
product_info.current_value = current_value
product_info.current_value = original_html_tags
logger.debug("현재 속성값 수집 완료")
# # ============번역을 위한 사전작업============
# 이미지 Url 수집
# translated_image_urls = [] # 번역된 이미지 URL들을 저장할 리스트
detail_images = fetch_image_urls(current_value)
logger.debug(f"detail_images URLs \n {detail_images}")
detail_images = fetch_image_urls(original_html_tags)
# logger.debug(f"detail_images URLs \n {detail_images}")
product_info.detail_image_urls = detail_images
# 원본 URL을 빈문자열로 대체
@ -554,13 +566,12 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
# # ============번역을 위한 사전작업============
logger.debug("product_info_card 결합.")
new_value = product_info_card + cost_add_text + current_value
new_value = product_info_card +'<br><br>' + cost_add_text +'<br><br>' +original_html_tags
# textarea.send_keys(product_info_card)
time.sleep(0.2)
logger.debug("결합.")
# 결합된 값을 다시 textarea에 설정
try:
# # data-value 속성을 새로운 값으로 설정합니다.
driver.execute_script("arguments[0].setAttribute('data-value', arguments[1]);", textarea, new_value)
@ -572,8 +583,7 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
# driver.execute_script(script, textarea, new_value)
time.sleep(0.5)
logger.debug("새로운 값이 성공적으로 설정됨.")
except Exception as e:
logger.error(f"새로운 값 설정 중 오류 발생: {e}", exc_info=True)
time.sleep(0.2)
# textarea.send_keys(Keys.ENTER)
@ -626,8 +636,10 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
trans_img_tag = login_info["whether_modifyImageTanslation"]
logger.debug(f"whether_modifyImageTanslation : {trans_img_tag}")
if login_info.whether_modifyImageTanslation:
if login_info["whether_modifyImageTanslation"]:
logger.debug("상세페이지 이미지 번역 시작")
try:
for i, detail_image in enumerate(detail_images):
@ -650,9 +662,6 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
logger.debug("====번역이미지 붙여넣기 완료=====")
logger.debug("상세페이지 편집 저장")
click_element(driver, "XPATH", save_button_xpath, 5, 'js')

View File

@ -10,7 +10,7 @@ import sys, re
import numpy as np
from naver_search import parse_naver_shopping
from edit.naver_code import find_naver_code
from edit.action_elements import click_element, return_element
from edit.action_elements import click_element, return_element, click_and_confirm_tab
from img_trans.image_trans import image_trans
import logging
from bs4 import BeautifulSoup
@ -22,6 +22,7 @@ logger = logging.getLogger('default_logger')
avg_price = 0
def paste_image_in_editor(driver, editor_element):
action = ActionChains(driver)
action.click(editor_element) # 에디터를 클릭하여 포커스를 맞춥니다.
@ -72,27 +73,25 @@ def fetch_image_urls(html_content):
return image_urls
def safe_generate_content(gemini, image_src, product_title, max_retries=3, initial_wait=1):
def safe_generate_content(gemini, product_info, max_retries=3, initial_wait=1):
retry_count = 0
wait_time = initial_wait
while retry_count < max_retries:
try:
return gemini.generate_description(image_src, product_title)
return gemini.generate_description(product_info)
# except InternalServerError as e:
# logger.debug(f"Retry {retry_count + 1}/{max_retries} for InternalServerError")
# time.sleep(wait_time)
# wait_time *= 2 # Exponential backoff
# retry_count += 1
except Exception as e:
logger.debug(f"예외 발생 : {e}", exc_info=True)
logger.debug(f"예외 발생으로 재시도 : {retry_count + 1}/{max_retries}")
time.sleep(wait_time)
wait_time *= 2 # Exponential backoff
retry_count += 1
# Final attempt without catching the exception
return gemini.generate_content(image_src, product_title)
def selling_price(tao_bao_price, shipping_fee=6500, target_margin_rate=0.29, market_fee_rate=0.13,
card_fee_rate=0.035, exchange_rate=200):
"""
@ -186,65 +185,76 @@ def find_delivery_fee(weight, delv_collection):
return fees[closest_weight_index]
#네이버쇼핑 함수
def NS_info(products):
# 각 상품 정보에 접근하여 텍스트로 가공
product_info_text = ""
global avg_price
avg_price = 0
prices = []
# def NS_info(products):
# # 각 상품 정보에 접근하여 텍스트로 가공
# product_info_text = ""
# global avg_price
# avg_price = 0
# prices = []
for index, product in enumerate(products):
idx = index + 1
product_info_text += '<div class="card">\n' # 카드 시작 태그
product_info_text += f"=================={idx} 번째 네이버 상품========================"
# 이미지 태그
product_info_text += f'<img src="{product["imageUrl"]}" width="200" alt="상품 이미지">\n'
# for index, product in enumerate(products):
# idx = index + 1
# product_info_text += '<div class="card">\n' # 카드 시작 태그
# product_info_text += f"=================={idx} 번째 네이버 상품========================"
# # 이미지 태그
# product_info_text += f'<img src="{product["imageUrl"]}" width="200" alt="상품 이미지">\n'
# 상품 세부 정보 태그 시작
product_info_text += '<div class="product-details">\n'
# # 상품 세부 정보 태그 시작
# product_info_text += '<div class="product-details">\n'
# 상품명 태그
# product_info_text += f'<div class="product-name"><strong>상품명 : {product["productTitle"]}</strong></div>\n'
product_info_text += f'<div class="product-name"><h3>상품명 : {product["productTitle"]}</h3></div>\n'
# 가격 태그
# 상품 가격을 숫자로 변환하고 포맷
if isinstance(product["price"], str):
# 문자열인 경우 숫자로 변환
price = int(product["price"].replace(",", "")) # 쉼표 제거 후 정수 변환
else:
price = product["price"] # 이미 숫자인 경우 변환 없음
# # 상품명 태그
# # product_info_text += f'<div class="product-name"><strong>상품명 : {product["productTitle"]}</strong></div>\n'
# product_info_text += f'<div class="product-name"><h3>상품명 : {product["productTitle"]}</h3></div>\n'
# # 가격 태그
# # 상품 가격을 숫자로 변환하고 포맷
# if isinstance(product["price"], str):
# # 문자열인 경우 숫자로 변환
# price = int(product["price"].replace(",", "")) # 쉼표 제거 후 정수 변환
# else:
# price = product["price"] # 이미 숫자인 경우 변환 없음
prices.append(price)
formatted_price = format(price, ",") + "" # 천 단위 구분으로 포맷
product_info_text += f'<div class="price">가격: {formatted_price}</div>'
# prices.append(price)
# formatted_price = format(price, ",") + "원" # 천 단위 구분으로 포맷
# product_info_text += f'<div class="price">가격: {formatted_price}</div>'
# 순위 태그
product_info_text += f'<div class="price">순위: {product["rank"]}</div>\n'
# # 순위 태그
# product_info_text += f'<div class="price">순위: {product["rank"]}</div>\n'
product_info_text += "=================================================================="
# product_info_text += "=================================================================="
# 상품 세부 정보 태그 종료
product_info_text += '</div>\n'
# # 상품 세부 정보 태그 종료
# product_info_text += '</div>\n'
product_info_text += '</div>\n' # 카드 종료 태그
avg_price += int(product["price"])
# product_info_text += '</div>\n' # 카드 종료 태그
# avg_price += int(product["price"])
# # avg_price = round(avg_price/len(products),0)
# if products: # products가 비어 있지 않은 경우에만 평균 가격 계산
# avg_price = round(avg_price / len(products), 0)
# low_price = min(prices)
# high_price = max(prices)
# product_info_text += f'네이버 상품의 최저 가격은 [{low_price}]'
# product_info_text += f'네이버 상품의 평균 가격은 [{avg_price}]'
# product_info_text += f'네이버 상품의 최고 가격은 [{high_price}]'
if products: # products가 비어 있지 않은 경우에만 평균 가격 계산
avg_price = round(avg_price / len(products), 0)
low_price = min(prices)
high_price = max(prices)
product_info_text += f'네이버 상품의 최저 가격은 [{low_price}]'
product_info_text += f'네이버 상품의 평균 가격은 [{avg_price}]'
product_info_text += f'네이버 상품의 최고 가격은 [{high_price}]'
# return product_info_text
return product_info_text
def original_html(current_html):
# BeautifulSoup 객체 생성
soup = BeautifulSoup(current_html, 'html.parser')
# "img class='image_resized'" 태그만 추출
resized_images = soup.find_all('img', class_='image_resized')
# 추출된 태그들로 새로운 HTML 문자열 생성
original_html_text = ''.join(str(tag) for tag in resized_images)
return original_html_text
def NS_info_with_HTML(products):
# 상품 정보를 담을 5x1 표 생성
product_info_text = "<table><tr>"
product_info_table = "<table><tr>"
global avg_price
avg_price = 0
@ -257,44 +267,18 @@ def NS_info_with_HTML(products):
# 각 상품 카드를 생성하고 테이블의 셀로 추가
product_card = create_product_card(product["productTitle"], product["imageUrl"], formatted_price, product["rank"], product["purchase"], product["review"])
product_info_text += f"<td style='width: 170px; height: 170px;'>{product_card}</td>"
product_info_table += f"<td style='width: 170px; height: 170px;'>{product_card}</td>"
avg_price += price
product_info_text += "</tr></table>"
product_info_table += "</tr></table>"
if products:
avg_price = round(avg_price / len(products), 0)
product_info_text += f'<div><h3>네이버 상품의 평균 가격은 {avg_price:,.0f}원입니다.</h3></div>'
product_info_table += f'<div><h3>네이버 상품의 평균 가격은 {avg_price:,.0f}원입니다.</h3></div>'
return product_info_text
return product_info_table
#네이버쇼핑 함수 HTML
def NS_info_with_HTML_ori(products):
product_info_text = ""
global avg_price
avg_price = 0
for product in products:
if isinstance(product["price"], str):
price = int(product["price"].replace(",", ""))
else:
price = product["price"]
formatted_price = format(price, ",") + ""
# 각 상품 카드를 생성하여 테이블의 셀로 추가
product_card = create_product_card(product["productTitle"], product["imageUrl"], formatted_price, product["rank"])
product_info_text += f"<td>{product_card}</td>"
avg_price += price
product_info_text += "</tr></table>"
if products:
avg_price = round(avg_price / len(products), 0)
product_info_text += f'<div>네이버 상품의 평균 가격은 {avg_price}원입니다.</div>'
return product_info_text
def naver_prices(products):
prices = []
for product in products:
@ -337,64 +321,51 @@ def create_product_card(product_name, image_url, price, rank, purchase, review):
return product_card
def create_product_card_ori(product_name, image_url, price, rank):
# 이미지 크기를 직접 지정
html_text = f"""
<table style="width: 400px; border-collapse: collapse;">
<tr>
<td rowspan="3" style="height: 400px; vertical-align: top;"><img src="{image_url}" style="width: 100%; max-width: 400px; height: auto;" alt="상품 이미지"></td>
<td style="border: 1px solid #dddddd; text-align: left; padding: 8px;">가격: {price}</td>
</tr>
<tr>
<td style="border: 1px solid #dddddd; text-align: left; padding: 8px;">순위: {rank}</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td colspan="2" style="border: 1px solid #dddddd; text-align: center; vertical-align: middle; font-weight: bold;">{product_name}</td>
</tr>
</table>
"""
return html_text
# #네이버쇼핑 함수 마크다운
# def NS_info_markdown(products):
# product_info_md = ""
# global avg_price
# avg_price = 0
# for index, product in enumerate(products):
# idx = index + 1
# # 제품명을 헤더로 표시
# product_info_md += f"### {idx}번상품. {product['productTitle']}\n"
# # 이미지 추가
# product_info_md += f"![상품 이미지]({product['imageUrl']})\n\n"
# # 가격과 순위 정보
# if isinstance(product["price"], str):
# price = int(product["price"].replace(",", "")) # 쉼표 제거 후 정수 변환
# else:
# price = product["price"]
# formatted_price = format(price, ",") + "원"
# product_info_md += f"- **가격:** {formatted_price}\n"
# product_info_md += f"- **순위:** {product['rank']}\n\n"
# avg_price += price # 평균 가격 계산을 위해 가격 추가
# if products: # products가 비어 있지 않은 경우에만 평균 가격 계산
# avg_price = round(avg_price / len(products), 0)
# product_info_md += f"**네이버 상품의 평균 가격은 {avg_price}원입니다.**\n"
# return product_info_md
def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver_codes, login_info):
detail_css = ".ant-tabs-tab:nth-child(6)"
thumb_data_note = "5"
click_and_confirm_tab(driver, thumb_data_note, 10)
#네이버쇼핑 함수 마크다운
def NS_info_markdown(products):
product_info_md = ""
global avg_price
avg_price = 0
for index, product in enumerate(products):
idx = index + 1
# 제품명을 헤더로 표시
product_info_md += f"### {idx}번상품. {product['productTitle']}\n"
# 이미지 추가
product_info_md += f"![상품 이미지]({product['imageUrl']})\n\n"
# 가격과 순위 정보
if isinstance(product["price"], str):
price = int(product["price"].replace(",", "")) # 쉼표 제거 후 정수 변환
else:
price = product["price"]
formatted_price = format(price, ",") + ""
product_info_md += f"- **가격:** {formatted_price}\n"
product_info_md += f"- **순위:** {product['rank']}\n\n"
avg_price += price # 평균 가격 계산을 위해 가격 추가
if products: # products가 비어 있지 않은 경우에만 평균 가격 계산
avg_price = round(avg_price / len(products), 0)
product_info_md += f"**네이버 상품의 평균 가격은 {avg_price}원입니다.**\n"
return product_info_md
def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver_codes):
product_title = product_info.init_title
product_low_cost = product_info.tao_low_price
product_high_cost = product_info.tao_high_price
product_keyword = product_info.keyword_title
# product_low_cost = product_info.tao_low_price
# product_high_cost = product_info.tao_high_price
product_low_cost = product_info.option_low_price
product_high_cost = product_info.option_high_price
image_src = product_info.main_image_url
try:
@ -409,6 +380,30 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
logger.debug(f"카테고리 코드 검색 중 예외 발생 : {e}", exc_info=True)
naver_code = ""
try:
logger.debug("네이버쇼핑 파싱 중")
products = parse_naver_shopping(product_keyword, naver_code, isOverseas=1, sortcount=5)
logger.debug("네이버쇼핑 파싱 완료")
# logger.debug(f"네이버 파싱된 상품 리스트 \n {products}")
product_info.naver_products = products
# 네이버 상품가격 담기
naver_price = naver_prices(products)
product_info.naver_low_price = naver_price[0]
product_info.naver_avg_price = naver_price[1]
product_info.naver_high_price = naver_price[2]
# product_info_text = NS_info(products)
product_info_card = NS_info_with_HTML(products)
# logger.debug(f"수집된 정보 \n {product_info_card} \n")
logger.debug("네이버쇼핑 파싱 완료")
except Exception as e:
logger.debug(f"네이버쇼핑 파싱 중 에러발생 : {e}", exc_info=True)
# click_element('XPATH', '/html/body/div[7]/div/div[3]/div/div[2]/div[1]/div/div[2]/div[8]/div/div/div[2]/div[1]/div/div/span[2]/div/div')
# testt = find_delivery_fee(7,delv_collection)
@ -430,8 +425,8 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
except Exception as e:
logger.debug(f"상세페이지 탭으로 이동 중 오류 발생: 요소를 찾을 수 없습니다. : {e}", exc_info=True)
# detail_tab = driver.find_element(By.CSS_SELECTOR, ".ant-tabs-tab:nth-child(6)")
detail_tab.click()
time.sleep(2) # 페이지 로딩 대기
# detail_tab.click()
time.sleep(0.2) # 페이지 로딩 대기
# 상세페이지 내용 수정
try:
@ -446,11 +441,10 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
try:
ActionChains(driver).move_to_element(detail_content).click().perform()
time.sleep(1)
logger.debug("AI 이미지 처리중")
# contents = bard_img(image_src)
# contents = gemini.generate_description(image_src, product_title)
aicontents = safe_generate_content(gemini, image_src, product_title)
aicontents = safe_generate_content(gemini, product_info)
logger.debug(f"{aicontents}")
product_info.ai_contents = aicontents
logger.debug("AI 이미지 처리 완료")
@ -467,30 +461,54 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
logger.debug(f"추가포장비 추정 : {packing_fee}")
product_info.packing_fee = packing_fee
logger.debug("네이버쇼핑 파싱 중")
products = parse_naver_shopping(product_title, naver_code, isOverseas=1, sortcount=5)
logger.debug(f"네이버 파싱된 상품 리스트 \n {products}")
product_info.naver_products = products
# 네이버 상품가격 담기
naver_price = naver_prices(products)
product_info.naver_low_price = naver_price[0]
product_info.naver_avg_price = naver_price[1]
product_info.naver_high_price = naver_price[2]
# product_info_text = NS_info(products)
product_info_text = NS_info_with_HTML(products)
# logger.debug(f"수집된 정보 \n {product_info_text} \n")
logger.debug("네이버쇼핑 파싱 완료")
except Exception as e:
logger.debug(f"상세페이지 편집 중 에러발생 : {e}", exc_info=True)
try:
# 가격 정보 계산
low_cost, low_margin = selling_price(product_low_cost, delv_fee, 0.29)
high_cost, high_margin = selling_price(product_high_cost, delv_fee, 0.29)
low_delv_fee = avg_price - low_cost
high_delv_fee = avg_price - high_cost
# 마진율 계산
low_margin_r = round((low_margin / low_cost) * 100, 2)
high_margin_r = round((high_margin / high_cost) * 100, 2)
# 텍스트 조합
cost_add_text = f"""
<h1>==== 가격과 마진율 ====</h1><br>
해당 제품의 네이버 평균가격은 <span style="font-size:16px;"><strong><u>{avg_price:,.0f}</u></strong></span>원입니다.<br>
해당 제품의 무게배송비는 <span style="font-size:16px;"><strong><u>{delv_fee:,.0f}</u></strong></span>원입니다.<br>
**마진율 확보를 위한 판매가 범위:** {low_cost:,.0f} ~ {high_cost:,.0f}<br>
<h3>**저가 중심 계산:**</h3><br>
* 무게 배송비 대비: {low_delv_fee:,.0f} {('낮은' if low_delv_fee < 0 else '높은')} <br>
* 마진율: {low_margin_r:,.2f}%<br>
<h3>**고가중심 계산:**</h3><br>
* 무게 배송비 대비: {high_delv_fee:,.0f} {('낮은' if high_delv_fee < 0 else '높은')} <br>
* 마진율: {high_margin_r:,.2f}%<br>
<h3>**추가 정보:**</h3><br>
<h2>* 해당 제품의 파손 여부 무게 오차를 고려하여 더하기 마진을 설정하세요.</h2><br>
<h3>=======================================</h3><br><br>
"""
# time.sleep(2)
# detail_content.send_keys(cost_add_text)
except Exception as e:
logger.debug(f"가격정보 생성 중 에러 : {e}", exc_info=True)
try:
logger.debug("HTML 수정 버튼 클릭 .")
html_btn_by_contains_xpath="//button[contains(.,'소스')]"
html_btn_css = "ck.ck-button.ck-source-editing-button.ck-off.ck-button_with-text"
html_btn_xpath="//div[@id='productMainContentContainerId']/div/div/div[2]/div[2]/div/div/div[2]/div/div/button[8]"
click_element(driver, 'XPATH', html_btn_xpath, 5, 'js')
click_element(driver, 'XPATH', html_btn_xpath, 5, 'ac')
# html_btn = WebDriverWait(driver, 10).until(
# # EC.presence_of_element_located((By.CSS_SELECTOR, ".ck-source-editing-button"))
# EC.presence_of_element_located(By.CLASS_NAME, html_btn_xpath)
@ -498,7 +516,6 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
# )
# logger.debug("HTML 수정 버튼을 성공적으로 찾았습니다.")
# html_btn.click()
logger.debug("HTML 수정 버튼 클릭 .")
except Exception as e:
logger.debug(f"HTML 수정 버튼 요소를 찾을 수 없습니다. : {e}", exc_info=True)
@ -507,62 +524,78 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
try:
# textarea_css = "ck-source-editing-area"
# click_element(driver, 'CSS_SELECTOR', textarea_css, 10, 'js')
textarea = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.CLASS_NAME, "ck-source-editing-area"))
)
logger.debug("textarea버튼을 성공적으로 찾았습니다.")
sys.stdout.flush()
textarea.click()
time.sleep(0.2)
actions = ActionChains(driver)
actions.move_to_element(textarea).perform() # 요소로 스크롤
logger.debug("'textarea' 요소로 스크롤 실행")
time.sleep(0.2)
actions.click(textarea).perform()
logger.debug("'textarea' 요소 클릭 실행")
# textarea.click()
except Exception as e:
logger.debug(f"textarea버튼 요소를 찾을 수 없습니다. : {e}", exc_info=True)
try:
# # data-value 속성 값을 가져옵니다.
current_value = textarea.get_attribute("data-value")
original_html_tags = original_html(current_value)
# logger.debug(f"현재 속성값 :{current_value}")
product_info.current_value = current_value
product_info.current_value = original_html_tags
logger.debug("현재 속성값 수집 완료")
# # ============번역을 위한 사전작업============
# 이미지 Url 수집
# translated_image_urls = [] # 번역된 이미지 URL들을 저장할 리스트
detail_images = fetch_image_urls(current_value)
logger.debug(f"detail_images URLs \n {detail_images}")
detail_images = fetch_image_urls(original_html_tags)
# logger.debug(f"detail_images URLs \n {detail_images}")
product_info.detail_image_urls = detail_images
# 원본 URL을 빈문자열로 대체
logger.debug("원본 URL을 빈 문자열로 대체")
for original_url in detail_images:
current_value = current_value.replace(original_url, "")
# logger.debug("원본 URL을 빈 문자열로 대체")
# for original_url in detail_images:
# current_value = current_value.replace(original_url, "")
# logger.debug("새로운 data-value 값으로 설정되었습니다.")
# # ============번역을 위한 사전작업============
# # # 새로운 data-value 값을 생성합니다.
# new_value = product_info_text + "\n" + current_value
# # logger.debug(f"new_value \n {new_value}")
# product_info.new_value = new_value
# logger.debug("새로운 data-value 값 생성")
# # # data-value 속성을 새로운 값으로 설정합니다.
# driver.execute_script("arguments[0].setAttribute('data-value', arguments[1]);", textarea, new_value)
# # driver.execute_script("arguments[0].innerHTML = arguments[1]", textarea, new_value)
# time.sleep(1)
# # driver.execute_script("arguments[0].innerHTML = arguments[1]", detail_content, new_value);
logger.debug("새로운 data-value 값으로 설정되었습니다.")
# save_button.click()
click_element(driver, 'XPATH', save_button_xpath, 5, 'js')
logger.debug("product_info_card 결합.")
new_value = product_info_card +'<br><br>' + cost_add_text +'<br><br>' +original_html_tags
# textarea.send_keys(product_info_card)
time.sleep(0.2)
logger.debug("결합.")
# 결합된 값을 다시 textarea에 설정
try:
# # data-value 속성을 새로운 값으로 설정합니다.
driver.execute_script("arguments[0].setAttribute('data-value', arguments[1]);", textarea, new_value)
# textarea.send_keys(product_info_text)
# logger.debug("detail_content 전송.")
# # driver.execute_script("arguments[0].innerHTML = arguments[1]", textarea, new_value)
# # driver.execute_script("arguments[0].innerHTML = arguments[1]", detail_content, new_value);
# # JavaScript를 사용하여 textarea 값 설정
# script = "arguments[0].value = arguments[1];"
# driver.execute_script(script, textarea, new_value)
time.sleep(0.5)
logger.debug("새로운 값이 성공적으로 설정됨.")
except Exception as e:
logger.error(f"새로운 값 설정 중 오류 발생: {e}", exc_info=True)
time.sleep(0.2)
# textarea.send_keys(Keys.ENTER)
# textarea.send_keys(Keys.ENTER)
# logger.debug("엔터키 전송.")
click_element(driver, 'XPATH', save_button_xpath, 5, 'js')
time.sleep(0.2)
logger.debug("저장버튼 전송.")
# html_btn.click()
click_element(driver, 'XPATH', html_btn_xpath, 5, 'js')
@ -588,6 +621,8 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
# contents 변수의 값이 None이 아닐 때만 send_keys 메서드를 호출합니다.
if aicontents is not None:
detail_content.send_keys(aicontents)
logger.debug(f"AI 컨텐츠 입력완료")
else:
# contents 변수가 None일 때의 대체 처리
# 예: detail_content.send_keys("") 또는 아무 동작도 수행하지 않음
@ -602,6 +637,9 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
logger.error(f"AI 컨텐츠 입력 중 에러발생 : {e}", exc_info=True)
if login_info.whether_modifyImageTanslation:
logger.debug("상세페이지 이미지 번역 시작")
try:
for i, detail_image in enumerate(detail_images):
@ -621,74 +659,11 @@ def modify_detail_page(driver, product_info, gemini, delv_collection, json_naver
except Exception as e:
logger.error(f"이미지 번역 중 에러발생 : {e}", exc_info=True)
logger.debug("====번역이미지 붙여넣기 완료=====")
# 인용버튼 클릭
# quote_button = driver.find_element(By.XPATH, "//div[@id='productMainContentContainerId']/div/div/div[2]/div[2]/div/div/div[2]/div/div/button[6]")
# quote_button = driver.find_element(By.CSS_SELECTOR, ".ck:nth-child(16)")
# try:
# quote_button = WebDriverWait(driver, 10).until(
# EC.presence_of_element_located((By.CSS_SELECTOR, ".ck:nth-child(16)"))
# )
# logger.debug("인용버튼을 성공적으로 찾았습니다.")
# except:
# logger.debug("인용버튼 요소를 찾을 수 없습니다.")
# quote_button.click()
# time.sleep(0.5)
try:
# 가격 정보 계산
low_cost, low_margin = selling_price(product_low_cost, delv_fee, 0.29)
high_cost, high_margin = selling_price(product_high_cost, delv_fee, 0.29)
low_delv_fee = avg_price - low_cost
high_delv_fee = avg_price - high_cost
# 마진율 계산
low_margin_r = round((low_margin / low_cost) * 100, 2)
high_margin_r = round((high_margin / high_cost) * 100, 2)
# 텍스트 조합
add_text = f"""
============= 가격과 마진율 =============
해당 제품의 네이버 평균가격은 {avg_price:,.0f}원입니다.
해당 제품의 무게배송비는 {delv_fee:,.0f}원입니다.
**마진율 확보를 위한 판매가 범위:** {low_cost:,.0f} ~ {high_cost:,.0f}
**저가:**
* 무게 배송비 대비: {low_delv_fee:,.0f} {('낮은' if low_delv_fee < 0 else '높은')}
* 마진율: {low_margin_r:,.2f}%
**고가:**
* 무게 배송비 대비: {high_delv_fee:,.0f} {('낮은' if high_delv_fee < 0 else '높은')}
* 마진율: {high_margin_r:,.2f}%
**적정 배송비:** {low_delv_fee:,.0f} ~ {high_delv_fee:,.0f}
**추가 정보:**
* 해당 제품의 파손 여부 무게 오차를 고려하여 더하기 마진을 설정하세요.
=======================================
"""
detail_content.send_keys(add_text)
time.sleep(2)
except Exception as e:
logger.debug(f"가격정보 생성 중 에러 : {e}", exc_info=True)
# 저장 버튼 클릭
# try:
# save_button = WebDriverWait(driver, 10).until(
# EC.presence_of_element_located((By.XPATH, "//button[contains(.,'저장하기')]"))
# )
# logger.debug("저장 버튼을 성공적으로 찾았습니다.")
# except Exception as e:
# logger.debug(f"저장 버튼 요소를 찾을 수 없습니다. : {e}", exc_info=True)
# save_button = driver.find_element(By.XPATH, "//button[contains(.,'저장하기')]")
# save_button.click()
logger.debug("상세페이지 편집 저장")

188
edit/ns.py Normal file
View File

@ -0,0 +1,188 @@
from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup
import requests, json
def run(playwright, keyword):
browser = playwright.chromium.launch(headless=False) # 헤드리스 모드 비활성화
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
locale="en-US", # 언어 설정
timezone_id="America/New_York" # 시간대 설정
)
page = context.new_page()
# navigator.webdriver 비활성화
page.evaluate("navigator.webdriver = undefined")
print("브라우저 열기 및 사용자 에이전트 설정 완료")
page.goto(f"https://search.shopping.naver.com/search/all?query={keyword}&bt=-1&frm=NVSCPRO")
print("페이지 로딩 완료")
# 접근 시간 지연
page.wait_for_timeout(1000)
print("페이지 로딩 완료")
# 페이지의 HTML 가져오기
html = page.content()
print(html)
soup = BeautifulSoup(html, 'html.parser')
products = extract_product_info(soup)
for product in products:
print(product.text)
browser.close()
def extract_product_info(soup):
# 상품 정보를 담을 리스트 초기화
product_info_list = []
# 각 상품에 대한 정보 추출
products = soup.find_all('div', class_='basicList_info_area__17Xyo')
print(f"products : {products}")
for i, product in enumerate(products, 1):
# 상품명
title = product.find('a', class_='product_link__TrAac').get('title')
print(f"{i}번째 상품 title : {title}")
# 썸네일 URL
thumbnail_element = product.find('a', class_='thumbnail_thumb__Bxb6Z')
thumbnail_url = thumbnail_element.find('img').get('src') if thumbnail_element else None
print(f"{i}번째 상품 thumbnail_url : {thumbnail_url}")
# 가격과 배송비
price_area = product.find('div', class_='product_price_area__eTg7I')
price = price_area.find('span', class_='price_num__S2p_v').text.strip() if price_area else None
print(f"{i}번째 상품 price : {price}")
delivery_fee = price_area.find('span', class_='price_delivery__yw_We').text.strip() if price_area else None
print(f"{i}번째 상품 delivery_fee : {delivery_fee}")
# 카테고리
categories = [cat.text for cat in product.find_all('span', class_='product_category__l4FWz')]
print(f"{i}번째 상품 categories : {categories}")
# 리뷰, 구매건수, 등록일, 찜하기
etc_info = product.find('div', class_='product_etc_box__ElfVA')
review_count = etc_info.find('a', text='리뷰').find('em').text if etc_info and etc_info.find('a', text='리뷰') else '0'
print(f"{i}번째 상품 review_count : {review_count}")
purchase_count = etc_info.find('span', text='구매건수').find('em').text if etc_info and etc_info.find('span', text='구매건수') else '0'
print(f"{i}번째 상품 purchase_count : {purchase_count}")
registration_date = etc_info.find('span', text='등록일').text.replace('등록일 ', '') if etc_info and etc_info.find('span', text='등록일') else None
print(f"{i}번째 상품 registration_date : {registration_date}")
zzim_count = etc_info.find('a', class_='product_btn_zzim__MQ17u').find('em').text if etc_info and etc_info.find('a', class_='product_btn_zzim__MQ17u') else '0'
print(f"{i}번째 상품 zzim_count : {zzim_count}")
# 사전에 정보 저장
product_info = {
'title': title,
'thumbnail_url': thumbnail_url,
'price': price,
'delivery_fee': delivery_fee,
'categories': categories,
'review_count': review_count,
'purchase_count': purchase_count,
'registration_date': registration_date,
'zzim_count': zzim_count
}
product_info_list.append(product_info)
print(f"{i}번째 상품 정보 추가 완료")
return product_info_list
def ns(keyword):
# 네이버 쇼핑 URL 설정
urlBase = "https://search.shopping.naver.com/search/all?query="
# urlEnd = f"&cat_id={naver_code}&frm=NVSHATC&pagingIndex=1&pagingSize=40&&productSet=overseas&sort=rel&timestamp=&viewType=list"
urlEnd = "&frm=NVSHATC&pagingIndex=1&pagingSize=40&&productSet=overseas&sort=rel&timestamp=&viewType=list"
url = urlBase + keyword + urlEnd
# print(f"네이버 카테코드는 [{naver_code}] 입니다.")
print("네이버 카테코드는 [생략]] 입니다.")
print(f"대상키워드는 [{keyword}] 입니다.")
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"DNT": "1", # Do Not Track 요청 헤더 (사용자의 추적을 거부)
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1", # https로의 업그레이드를 요청
"Cache-Control": "max-age=0", # 캐시된 콘텐츠를 재사용하지 않도록 요청
}
# # 네이버 쇼핑에 접속하여 HTML 받아오기
# response = requests.get(url, headers=headers)
# soup = BeautifulSoup(response.text, 'html.parser')
# 네이버 쇼핑에 접속하여 HTML 받아오기
try:
response = requests.get(url, headers=headers)
html = response.text
print(f"response : {response}")
# print(f"html : {html}")
response.raise_for_status() # 만약 요청이 실패하면 예외 발생
soup = BeautifulSoup(response.text, 'html.parser')
next_data_str = soup.find("script", {"id": "__NEXT_DATA__"}).string
next_data_json = json.loads(next_data_str)
products_list = next_data_json["props"]["pageProps"]["initialState"]["products"]["list"]
products_info = []
for product in products_list:
price = product.get("item", {}).get("price")
productTitle = product.get("item", {}).get("productTitle")
category1Name = product.get("item", {}).get("category1Name")
category2Name = product.get("item", {}).get("category2Name")
category3Name = product.get("item", {}).get("category3Name")
category4Name = product.get("item", {}).get("category4Name")
openDate = product.get("item", {}).get("openDate")
mallCount = product.get("item", {}).get("mallCount")
keepCnt = product.get("item", {}).get("keepCnt")
overseaTp = product.get("item", {}).get("overseaTp")
reviewCount = product.get("item", {}).get("reviewCount")
reviewCountSum = product.get("item", {}).get("reviewCountSum")
scoreInfo = product.get("item", {}).get("scoreInfo")
naverPayAdAccumulatedDisplayValue = product.get("item", {}).get("naverPayAdAccumulatedDisplayValue")
mobileLowPrice = product.get("item", {}).get("mobileLowPrice")
lowPrice = product.get("item", {}).get("lowPrice")
deliveryFeeContent = product.get("item", {}).get("deliveryFeeContent")
dlvryLowPrice = product.get("item", {}).get("dlvryLowPrice")
imageUrl = product.get("item", {}).get("imageUrl")
imgSz = product.get("item", {}).get("imgSz")
searchKeyword = product.get("item", {}).get("searchKeyword")
mallProductUrl = product.get("item", {}).get("mallProductUrl")
mallPcUrl = product.get("item", {}).get("mallPcUrl")
mallName = product.get("item", {}).get("mallName")
manuTag = product.get("item", {}).get("manuTag")
#mallInfoCache = product.get("item", {}).get("mallInfoCache")
purchaseCnt = product.get("item", {}).get("purchaseCnt")
rank = product.get("item", {}).get("rank")
# 상품 정보를 딕셔너리로 만들어 리스트에 추가
product_info = {
"productTitle": productTitle,
"price": price,
"imageUrl": imageUrl,
"rank": rank,
"purchase" : purchaseCnt,
"review" : reviewCountSum
}
products_info.append(product_info)
print(f"키워드 검색 결과 상품 [{keyword}]에 대한 [{len(products_info)}]개의 상품정보수집 완료")
print(f"products_info \n {products_info}")
except Exception as e:
print(f"Exception : {e}")
keywrod = "방폭등"
ns(keywrod)
# with sync_playwright() as playwright:
# run(playwright, keywrod)

View File

@ -6,7 +6,7 @@ from selenium.webdriver.common.keys import Keys
import time
from edit.action_elements import click_element, return_element, click_and_confirm_tab
from ai.deepl import trans
from ai.deepl_with_playwright import trans_text
from ai.deepl_with_playwright import trans_text, trans_list_text
# from ai.compare import find_most_similar_image_by_one
import re
import logging
@ -251,31 +251,35 @@ def option_name_trans(driver, product_info, option_type_number, option_count, al
ori_optionName_element = driver.find_element(By.XPATH, ori_optionName_xpath)
ori_optionName = ori_optionName_element.text.strip()
ori_optionNames.append(ori_optionName)
cleaned_ori_optionName = replace_or_remove_special_chars(ori_optionName, allowed_special_chars, special_char_replacements)
ori_optionNames.append(cleaned_ori_optionName)
except Exception as e:
logger.debug(f"원본옵션명 처리중 에러발생 : {e}", exc_info=True)
# 원본 옵션명을 하나의 텍스트로 합치기
combined_ori_optionNames = '\n\n'.join(ori_optionNames)
# combined_ori_optionNames = '\n\n'.join(ori_optionNames)
logger.debug("원본 텍스트의 특수문자 제거 및 대체")
cleaned_ori_text = replace_or_remove_special_chars(combined_ori_optionNames, allowed_special_chars, special_char_replacements)
logger.debug(f"원본옵션명 집합 \n {cleaned_ori_text}")
# logger.debug("원본 텍스트의 특수문자 제거 및 대체")
# cleaned_ori_text = replace_or_remove_special_chars(combined_ori_optionNames, allowed_special_chars, special_char_replacements)
# logger.debug(f"원본옵션명 집합 \n {cleaned_ori_text}")
logger.debug("번역 시행")
# trans_optionNames_text = trans_text(cleaned_ori_text) # DeepL 번역 함수
trans_optionNames_text = trans(cleaned_ori_text) # DeepL 번역 함수
deepl_trans_optionNames = trans_list_text(ori_optionNames) # DeepL 번역 함수
# trans_optionNames_text = trans_text(cleaned_ori_text) # DeepL_with_playwright 번역 함수
logger.debug(f"번역된 텍스트 \n {trans_optionNames_text} ")
# trans_optionNames_text = trans(cleaned_ori_text) # DeepL 번역 함수
logger.debug(f"번역된 텍스트 \n {deepl_trans_optionNames} ")
logger.debug("번역 텍스트의 특수문자 제거 및 대체")
cleaned_ori_text = replace_or_remove_special_chars(trans_optionNames_text, allowed_special_chars, special_char_replacements)
trans_optionNames = []
for deepl_trans_optionName in deepl_trans_optionNames:
cleand_trans_optionName = replace_or_remove_special_chars(deepl_trans_optionName, allowed_special_chars, special_char_replacements)
trans_optionNames.append(cleand_trans_optionName)
trans_optionNames = trans_optionNames_text.split('\n\n')
logger.debug("번역 텍스트 나누기")
# trans_optionNames = trans_optionNames_text.split('\n\n')
# logger.debug("번역 텍스트 나누기")
logger.debug("product_info 옵션명 업데이트")
try:

View File

@ -20,14 +20,16 @@ def modify_price_page(driver, product_infos):
# 가격 탭으로 이동
logger.debug("가격탭으로 이동")
option_tab_XPATH = "//div[@id='rc-tabs-0-tab-3']"
keyword_tab_CSS = ".ant-tabs-tab:nth-child(3)"
click_element(driver, 'CSS_SELECTOR', keyword_tab_CSS, 10, 'js')
# option_tab_XPATH = "//div[@id='rc-tabs-0-tab-3']"
# keyword_tab_CSS = ".ant-tabs-tab:nth-child(3)"
# click_element(driver, 'CSS_SELECTOR', keyword_tab_CSS, 10, 'js')
logger.debug("가격탭으로 이동 완료")
logger.debug("페이지 로딩 대기")
time.sleep(2) # 페이지 로딩 대기.
try:
option_high_price = product_infos.option_high_price
option_low_price = product_infos.option_low_price
@ -49,8 +51,10 @@ def modify_price_page(driver, product_infos):
"ns_high_price": naver_high_price
}
logger.debug(f"가격계산 INPUT 요소 : {inputs}")
except Exception as e:
logger.error(f"가격계산 INPUT 요소 계산 중 에러 발생 {e}", exc_info=True)
try:
outputs = calculate_margin_and_price(inputs)
logger.debug(f"가격계산 OUTPUT 요소 : {outputs}")
@ -60,7 +64,7 @@ def modify_price_page(driver, product_infos):
plus_margin = outputs["plus_margin"]
ns_avg_price = outputs["ns_avg_price"]
return_fee = selling_price/2
return_fee = round((selling_price*0.4) / 1000) * 1000
init_delv_fee = seller_cost
exchange_fee = return_fee + init_delv_fee
@ -70,21 +74,24 @@ def modify_price_page(driver, product_infos):
product_infos.init_delv_fee = init_delv_fee
product_infos.exchange_fee = exchange_fee
print(f"결정된 상품가격: {selling_price}원, 최종 마진율: {final_margin_rate:.2f}%")
print(f"판매자 원가: {seller_cost}")
print(f"더하기 마진: {plus_margin}")
print(f"네이버 평균가: {ns_avg_price}")
logger.debug(f"결정된 상품가격: {selling_price}원, 최종 마진율: {final_margin_rate:.2f}%")
logger.debug(f"판매자 원가: {seller_cost}")
logger.debug(f"더하기 마진: {plus_margin}")
logger.debug(f"네이버 평균가: {ns_avg_price}")
except Exception as e:
logger.error(f"가격계산 OUTPUT 요소 계산 중 에러 발생 {e}", exc_info=True)
# 가격 탭으로 이동
logger.debug("내부함수 가격 탭으로 이동")
thumb_tab_CSS = '.ant-tabs-tab:nth-child(3)'
click_element(driver, 'CSS_SELECTOR', thumb_tab_CSS, 10, 'js')
logger.debug("내부함수 가격 탭으로 이동 완료")
logger.debug("페이지 로딩 대기")
time.sleep(2) # 페이지 로딩 대기.
# # 가격 탭으로 이동
# logger.debug("내부함수 가격 탭으로 이동")
# thumb_tab_CSS = '.ant-tabs-tab:nth-child(3)'
# click_element(driver, 'CSS_SELECTOR', thumb_tab_CSS, 10, 'js')
# logger.debug("내부함수 가격 탭으로 이동 완료")
# logger.debug("페이지 로딩 대기")
# time.sleep(2) # 페이지 로딩 대기.
try:
logger.debug("더하기마진 수정")
plus_fee_xpath="//div[@id='productMainContentContainerId']/div/div/div/div/div[2]/div/div/div[8]/div/div/div[3]/div/div/div/div/div[2]/input"
plus_fee_element = return_element(driver, 'XPATH', plus_fee_xpath, 10)
@ -93,7 +100,10 @@ def modify_price_page(driver, product_infos):
logger.debug("기존가격 삭제")
plus_fee_element.send_keys(plus_margin) # 새 가격 입력
logger.debug(f"더하기마진 수정 완료 : {plus_margin}")
except Exception as e:
logger.error(f"더하기마진 수정 중 에러 발생 {e}", exc_info=True)
try:
logger.debug("해외배송비 수정")
fore_delv_fee_xpath="//div[@id='productMainContentContainerId']/div/div/div/div/div[2]/div/div/div[10]/div/div/div/div/div[2]/input"
fore_delv_fee_element = return_element(driver, 'XPATH', fore_delv_fee_xpath, 10)
@ -102,7 +112,10 @@ def modify_price_page(driver, product_infos):
logger.debug("기존가격 삭제")
fore_delv_fee_element.send_keys(w_delv_fee) # 새 가격 입력
logger.debug(f"해외배송비 수정 완료 : {w_delv_fee}")
except Exception as e:
logger.error(f"해외배송비 수정 중 에러 발생 {e}", exc_info=True)
try:
logger.debug("반품비 수정")
return_fee_xpath = "//div[@id='productMainContentContainerId']/div/div/div/div/div[4]/div/div/div[3]/div/div/div/div/div[2]/input"
return_fee_element = return_element(driver, 'XPATH', return_fee_xpath, 10)
@ -111,7 +124,10 @@ def modify_price_page(driver, product_infos):
logger.debug("기존가격 삭제")
return_fee_element.send_keys(return_fee) # 새 가격 입력
logger.debug(f"반품비 수정 완료 : {return_fee}")
except Exception as e:
logger.error(f"반품비 수정 중 에러 발생 {e}", exc_info=True)
try:
logger.debug("초도배송비 수정")
first_delv_fee_xpath = "//div[@id='productMainContentContainerId']/div/div/div/div/div[4]/div/div/div[4]/div/div[2]/div/div/div[2]/input"
first_delv_fee_element = return_element(driver, 'XPATH', first_delv_fee_xpath, 10)
@ -120,7 +136,10 @@ def modify_price_page(driver, product_infos):
logger.debug("기존가격 삭제")
first_delv_fee_element.send_keys(init_delv_fee) # 새 가격 입력
logger.debug(f"초도배송비 수정 완료 : {init_delv_fee}")
except Exception as e:
logger.error(f"초도배송비 수정 중 에러 발생 {e}", exc_info=True)
try:
logger.debug("교환비 수정")
exchange_fee_xpath = "//div[@id='productMainContentContainerId']/div/div/div/div/div[4]/div/div/div[5]/div/div/div/div/div[2]/input"
exchange_fee_element = return_element(driver, 'XPATH', exchange_fee_xpath, 10)
@ -128,7 +147,9 @@ def modify_price_page(driver, product_infos):
driver.execute_script("arguments[0].value = '';", exchange_fee_element) # 기존 가격 삭제 JS
logger.debug("기존가격 삭제")
exchange_fee_element.send_keys(exchange_fee) # 새 가격 입력
logger.debug(f"교환비 수정 완료 : {exchange_fee}")
logger.debug(f"교환비 수정 완료 : {exchange_fee}`")
except Exception as e:
logger.error(f"교환비 수정 중 에러 발생 {e}", exc_info=True)
# logger.debug("기본마진율 수정")
# earning_rate_xpath = "//div[@id='productMainContentContainerId']/div/div/div/div/div[2]/div/div/div[8]/div/div/div/div/div/div/div/div[2]/input"
@ -142,6 +163,9 @@ def modify_price_page(driver, product_infos):
# 백그라운드 컬러로 빨간 가격탭 찾기
# background: rgb(255, 77, 79); box-shadow: none; color: rgb(255, 255, 255);
try:
save_xpath="//button[contains(.,'저장하기')]"
click_element(driver, 'XPATH', save_xpath, 10)
logger.debug("옵션 정리 후 저장버튼 클릭 완료")
logger.debug("가격 정리 후 저장버튼 클릭 완료")
except Exception as e:
logger.error(f"가격 정리 저장버튼 클릭 중 에러 발생 {e}", exc_info=True)

View File

@ -16,12 +16,14 @@ def calculate_margin_and_price(inputs):
plus_margin = 5000 # 기본값
# 계산 로직
ns_avg_price = (ns_low_price + ns_high_price) / 2
ns_avg_price = round(((ns_low_price + ns_high_price) / 2) / 100) * 100
logger.debug(f"ns_avg_price : {ns_avg_price}")
option_avg_price = (option_low_price + option_high_price) / 2
option_avg_price = round(((option_low_price + option_high_price) / 2) / 100) * 100
logger.debug(f"option_avg_price : {option_avg_price}")
tao_cost = lambda price: price * 190 * 1.035
base_margin = lambda cost: cost * 0.12
# tao_cost = lambda price: price * 190 * 1.035
tao_cost = lambda price: round(price * 1.035 / 100) * 100
base_margin = lambda cost: round(cost * 0.12 / 100) * 100
def adjust_plus_margin_for_min_margin(seller_cost, mall_cost, selling_price):
nonlocal plus_margin
@ -32,16 +34,18 @@ def calculate_margin_and_price(inputs):
if final_margin_rate < target_margin_rate:
plus_margin += 100 # 더하기 마진 증가
selling_price = seller_cost + plus_margin + mall_cost
mall_cost = selling_price * 0.13
mall_cost = round(selling_price * 0.13 / 100) * 100
else:
break
logger.debug(f"final_margin_rate : {final_margin_rate}")
return selling_price, final_margin_rate
seller_cost = tao_cost(option_avg_price) + delv_fee + packing_fee
logger.debug(f"seller_cost : {seller_cost}")
mall_cost = seller_cost * 0.13
mall_cost = round((seller_cost * 0.13)/100) * 100
selling_price = seller_cost + plus_margin + mall_cost
selling_price, final_margin_rate = adjust_plus_margin_for_min_margin(seller_cost, mall_cost, selling_price)

View File

@ -68,8 +68,10 @@ def image_trans(image_url, convert_type):
# 번역된 텍스트 추출 및 삽입
texts_to_translate = [text for _, text, _, _, _ in detected_texts]
logger.debug(f"원본 텍스트: {texts_to_translate}")
translated_texts = translate_texts_translatepy(texts_to_translate)
logger.debug(f"DEEPL 번역시작")
translated_texts = translate_texts_deepl(texts_to_translate)
if not translated_texts: # 빈 리스트 체크
logger.debug(f"DEEPL 번역실패로 translatepy 시작")
translated_texts = translate_texts_translatepy(texts_to_translate)
logger.debug(f"번역 텍스트: {texts_to_translate}")
# translated_image = insert_text(inpainted_image_path, translated_texts, detected_texts)

View File

@ -1,6 +1,7 @@
from googletrans import Translator
# from img_trans.src.deepl_ori import trans
from ai.deepl import trans
from ai.deepl_with_playwright import trans_list_text, trans_text
from translatepy import Translator
import logging
@ -21,7 +22,7 @@ def translate_texts_google(texts, src_lang='zh-cn', dest_lang='ko'):
return translated_texts
def translate_texts_deepl(texts):
def translate_texts_deepl_ori(texts):
"""텍스트 리스트를 지정된 언어에서 다른 언어로 번역"""
# 텍스트 리스트를 엔터로 구분된 하나의 문자열로 합침
combined_text = "\n".join(texts)
@ -29,18 +30,34 @@ def translate_texts_deepl(texts):
# DeepL로 전체 텍스트 번역
try:
translated_combined_text = trans(combined_text)
# translated_combined_text = trans(combined_text)
translated_combined_text = trans_list_text(combined_text)
for translation in translated_combined_text:
# "가격"이 포함된 경우 빈 문자열로 대체
translated_texts.append(translation.text if "가격" not in translation.text else "")
# 번역된 전체 텍스트를 엔터를 기준으로 분리하여 리스트로 만듦
translated_texts = translated_combined_text.split("\n")
except AttributeError as e:
logger.error(f"번역 실패: {e}")
logger.error(f"번역 실패: {e}", exc_info=True)
translated_texts = []
return translated_texts
def translate_texts_deepl(texts):
"""텍스트 리스트를 지정된 언어에서 다른 언어로 번역"""
translated_texts = []
# DeepL로 전체 텍스트 번역
try:
translated_texts = trans_list_text(texts)
# "가격"이 포함된 경우 빈 문자열로 대체
translated_texts = [text if "가격" not in text else "" for text in translated_texts]
except AttributeError as e:
logger.error(f"번역 실패: {e}", exc_info=True)
translated_texts = []
return translated_texts
def translate_texts_translatepy(texts, src_lang='zh-cn', dest_lang='ko'):
"""translatepy 라이브러리를 사용하여 텍스트 리스트를 번역합니다."""

View File

@ -51,7 +51,7 @@ class LoginWidget(QtWidgets.QWidget):
# self.setGeometry(780, 420, 240, 200)
# 위젯의 크기를 설정합니다.
self.resize(800, 800)
self.resize(400, 600)
self.center() # 화면 가운데에 위치시키는 메서드
# 레이아웃 설정
@ -125,6 +125,10 @@ class LoginWidget(QtWidgets.QWidget):
self.loginButton = QtWidgets.QPushButton("로그인")
self.loginButton.clicked.connect(self.login)
self.DeleteDB_by_ID = QtWidgets.QLineEdit()
self.DeleteDB_by_ID.setPlaceholderText("상품ID 입력시 해당 DB 삭제")
self.alwaysOnTopSwitch = ToggleSwitch(self)
self.alwaysOnTopSwitch.move(10, 10)
self.alwaysOnTopSwitch.setChecked(True) # 기본 상태는 ON
@ -220,13 +224,13 @@ class LoginWidget(QtWidgets.QWidget):
# label = QtWidgets.QLabel(label_text)
# setting_layout.addWidget(label) # 설명 라벨은 2열(인덱스 1)에 배치
setting_layout.addLayout(self.modifyProductNameSwitch_layout)
setting_layout.addLayout(self.modifyProductOptionsSwitch_layout)
setting_layout.addLayout(self.modifyProductPriceSwitch_layout)
setting_layout.addLayout(self.modifyProductTagSwitch_layout)
setting_layout.addLayout(self.modifyProductThumbSwitch_layout)
setting_layout.addLayout(self.modifyProductOptionsSwitch_layout)
setting_layout.addLayout(self.modifyProductDetailSwitch_layout)
setting_layout.addLayout(self.modifyImageTranslationSwitch_layout)
setting_layout.addLayout(self.modifyProductPriceSwitch_layout)
setting_layout.addLayout(self.modifyProductNameSwitch_layout)
setting_layout.addLayout(self.uploadToMarketSwitch_layout)
setting_layout.addLayout(self.alwaysOnTopSwitch_layout)
setting_layout.addLayout(self.shutdownSwitch_layout)

View File

@ -5,7 +5,7 @@ from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service #웨일
# from webdriver_manager.chrome import ChromeDriverManager #웨일
import time
import datetime
from datetime import datetime
import ctypes
import atexit
import platform, os, sys
@ -115,6 +115,9 @@ def DB_setting():
"login_result": login_widget.result,
}
tag = login_info["whether_modifyImageTanslation"]
logger.debug(f"whether_modifyImageTanslation : {tag}")
return login_info, result, mongo_config
def main():
@ -127,7 +130,7 @@ def main():
atexit.register(restore_sleep_mode)
atexit.register(record_logout_time)
if login_info.whether_shutdownAfterComplete:
if login_info["whether_shutdownAfterComplete"]:
atexit.register(shutdown_system)
atexit.register(send_exit_message)

View File

@ -182,6 +182,18 @@ def modify_products(driver, gemini, mongo_config, login_info, set_num_modify):
product_infos.append(ProductInfo())
# 1번 상품과 나머지 상품들에 대한 XPATH 처리
# 상품 수정 관련 작업을 조건에 따라 수행하는 로직
step_conditions = {
'tag_modification': login_info["whether_modifyProductTag"],
'thumbnail_modification': login_info["whether_modifyProductThumb"],
'option_modification': login_info["whether_modifyProductOptions"],
'detail_page_modification': login_info["whether_modifyProductDetail"],
'price_modification': login_info["whether_modifyProductPrice"],
'title_modification': login_info["whether_modifyProductName"],
# 'trans_detailImage': login_info["whether_modifyImageTanslation"],
'upload_to_market': login_info["whether_uploadToMarket"],
}
steps_and_actions = [
('tag_modification', edit_tag, (driver, product_infos[i-1])),
('thumbnail_modification', modify_thumb_page, (driver, product_infos[i-1])),
@ -189,21 +201,10 @@ def modify_products(driver, gemini, mongo_config, login_info, set_num_modify):
('detail_page_modification', modify_detail_page, (driver, product_infos[i-1], gemini, delv_collection, json_naver_codes, login_info)),
('price_modification', modify_price_page, (driver, product_infos[i-1])),
('title_modification', modify_product_title, (driver, product_infos[i-1])),
('trans_detailImage', tran_detail_image, (driver, product_infos[i-1])),
# ('trans_detailImage', tran_detail_image, (driver, product_infos[i-1])),
('upload_to_market', upload_to_market, (driver, product_infos[i-1])),
]
# 상품 수정 관련 작업을 조건에 따라 수행하는 로직
step_conditions = {
'tag_modification': login_info.whether_modifyProductTag,
'thumbnail_modification': login_info.whether_modifyProductThumb,
'option_modification': login_info.whether_modifyProductOptions,
'detail_page_modification': login_info.whether_modifyProductDetail,
'price_modification': login_info.whether_modifyProductPrice,
'title_modification': login_info.whether_modifyProductName,
'trans_detailImage': login_info.whether_modifyImageTanslation,
'upload_to_market': login_info.whether_uploadToMarket,
}
# 상품ID 복사
try:

View File

@ -56,11 +56,11 @@ def parse_naver_shopping(keyword, naver_code, isOverseas=1, sortcount=10):
logger.debug("NEXT_DATA JSON을 파싱하는 중 오류 발생:", e)
# 예외 처리 코드 추가
# "__NEXT_DATA__" 파싱하기
logger.debug("NEXT_DATA 파싱 완료")
# # "__NEXT_DATA__" 파싱하기
# logger.debug("NEXT_DATA 파싱 완료")
next_data_str = soup.find("script", {"id": "__NEXT_DATA__"}).string
next_data_json = json.loads(next_data_str)
# next_data_str = soup.find("script", {"id": "__NEXT_DATA__"}).string
# next_data_json = json.loads(next_data_str)
# products 리스트 가져오기
logger.debug("products 리스트 가져오기")