From 0b10533b1040d69affbb4c38e3e1e9b5d31f3718 Mon Sep 17 00:00:00 2001 From: jinye_huang Date: Fri, 30 May 2025 11:25:46 +0800 Subject: [PATCH] demo init --- douyin_publisher.py | 337 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 douyin_publisher.py diff --git a/douyin_publisher.py b/douyin_publisher.py new file mode 100644 index 0000000..872f98b --- /dev/null +++ b/douyin_publisher.py @@ -0,0 +1,337 @@ +import selenium +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +import json +import base64 +import time + +class DouyinPublisher(): + def __init__(self, driver, cookies_path): + self.driver = driver + self.cookies_path = cookies_path + self.cookies = json.loads(open(self.cookies_path, "r").read()) + + # 先访问抖音网站 + self.driver.get("https://creator.douyin.com/creator-micro/content/upload?enter_from=dou_web") + time.sleep(3) # 等待页面加载 + + # 然后加载cookies + self.load_cookies() + + self.WEB_URL = "https://creator.douyin.com/creator-micro/content/upload?enter_from=dou_web" + self.driver.get(self.WEB_URL) + + def load_cookies(self): + try: + for cookie in self.cookies: + # 移除可能导致问题的属性 + for attr in ['sameSite', 'expiry']: + if attr in cookie: + del cookie[attr] + try: + self.driver.add_cookie(cookie) + except Exception as e: + print(f"添加cookie失败: {e}") + + print("cookies加载完成") + # 刷新页面使cookies生效 + self.driver.refresh() + time.sleep(3) # 等待刷新完成 + + except Exception as e: + print(f"添加cookies过程中发生错误: {e}") + return True + + def open_web(self): + self.driver.get(self.WEB_URL) + # 等待页面加载完成 + time.sleep(5) + return True + + def select_upload_type(self, upload_type): + # 注意:以下XPath选择器需要根据实际网页结构调整 + if upload_type == "image": + # 图文 + try: + self.driver.find_element(By.XPATH, "//div[contains(text(), '图文')]").click() + except: + print("无法找到图文上传按钮,请检查XPath") + elif upload_type == "video": + # 视频 + try: + self.driver.find_element(By.XPATH, "//div[contains(text(), '视频')]").click() + except: + print("无法找到视频上传按钮,请检查XPath") + return True + + def upload_image(self, image_path): + # 注意:以下XPath选择器需要根据实际网页结构调整 + try: + # 找到文件上传输入框 + file_input = self.driver.find_element(By.XPATH, "//input[@type='file' and @accept='.jpg,.jpeg,.png']") + file_input.send_keys(image_path) + except Exception as e: + print(f"上传图片失败: {e}") + + # 等待上传完成 + time.sleep(5) + return True + + def upload_video(self, video_path): + # 注意:以下XPath选择器需要根据实际网页结构调整 + try: + # 找到文件上传输入框 + # 首先尝试点击上传视频按钮(如果需要) + try: + # 尝试通过文本内容定位上传视频按钮 + upload_btn = self.driver.find_element(By.XPATH, "//span[contains(text(), '上传视频')]") + upload_btn.click() + time.sleep(1) # 等待文件选择框出现 + except Exception as e: + print(f"点击上传视频按钮失败,尝试直接查找文件输入框: {e}") + + # 然后找到文件输入框并上传文件 + file_input = self.driver.find_element(By.XPATH, "//input[@type='file' and @accept='.mp4,.mov,.wmv,.avi,.m4v']") + file_input.send_keys(video_path) + except Exception as e: + print(f"上传视频失败: {e}") + + # 等待上传完成 + time.sleep(10) # 视频上传可能需要更长时间 + return True + + def publish(self, title, content): + # 注意:以下XPath选择器需要根据实际网页结构调整 + try: + # 输入标题 + title_input = self.driver.find_element(By.XPATH, "//input[@placeholder='请输入标题']") + title_input.clear() + title_input.send_keys(title) + + # 输入内容/描述 + content_input = self.driver.find_element(By.XPATH, "//div[contains(@class, 'editor')]") + content_input.clear() + content_input.send_keys(content) + except Exception as e: + print(f"输入标题和内容失败: {e}") + + return True + + def click_publish(self): + # 注意:以下XPath选择器需要根据实际网页结构调整 + try: + # 找到并点击发布按钮 + publish_button = self.driver.find_element(By.XPATH, "//button[contains(text(), '发布')]") + publish_button.click() + + # 等待发布完成 + time.sleep(5) + + # 有时候可能会有确认弹窗 + try: + confirm_button = self.driver.find_element(By.XPATH, "//button[contains(text(), '确定')]") + confirm_button.click() + except: + pass # 如果没有确认弹窗,则忽略 + except Exception as e: + print(f"点击发布按钮失败: {e}") + + return True + + def publish_article(self, title, content, image_path): + self.select_upload_type("image") + self.upload_image(image_path) + self.publish(title, content) + self.click_publish() + return True + + def publish_video(self, title, content, video_path): + self.select_upload_type("video") + self.upload_video(video_path) + self.publish(title, content) + self.click_publish() + return True + + def work(self, type, title, content, image_path=None, video_path=None): + try: + self.open_web() + self.driver.maximize_window() + self.driver.implicitly_wait(10) + + if type == "article" and image_path: + self.publish_article(title, content, image_path) + elif type == "video" and video_path: + self.publish_video(title, content, video_path) + else: + raise ValueError("Invalid type or missing file path") + + print("发布完成!") + + except Exception as e: + print(f"发布失败: {e}") + finally: + # 可以选择不立即退出,以便查看结果 + # self.driver.quit() + pass + + return True + +if __name__ == "__main__": + # 使用Safari浏览器 + driver = webdriver.Safari() + + # 也可以根据需要选择其他浏览器 + # driver = webdriver.Chrome() + # driver = webdriver.Firefox() + + # 设置浏览器全屏 + driver.maximize_window() + + # 设置页面加载超时时间 + driver.set_page_load_timeout(30) + + # cookies路径,需要先获取登录后的cookies + cookies_path = "cookies.json" + + # 创建抖音发布器实例 + publisher = DouyinPublisher(driver, cookies_path) + time.sleep(10) + # + + # 上传视频按钮 + video_path = "/Users/yarrow/autoPublisher/8970_1747905081.mp4" + file_input = driver.find_element(By.XPATH, "//input[@style='display: none;']") + file_input.send_keys(video_path) + time.sleep(10) + print("视频上传完成") + # input("按任意键继续...") + + title_input = driver.find_element(By.XPATH, "//input[@placeholder='填写作品标题,为作品获得更多流量']") + title_input.send_keys("测试标题") + + content_input = driver.find_element(By.XPATH, "//div[@data-placeholder='添加作品简介']") + content_input.send_keys("测试内容") + print("内容输入完成") + # input("按任意键继续...") + + # 下拉框选择 + tab_selector = driver.find_element(By.XPATH, "//div[@class='semi-select select-lJTtRL semi-select-single']") + # 方法1:使用JavaScript执行点击 + driver.execute_script("arguments[0].click();", tab_selector) + + # 如果上面方法不生效,可以尝试以下备选方法: + # 方法2:使用Actions类进行点击 + # from selenium.webdriver.common.action_chains import ActionChains + # ActionChains(driver).move_to_element(tab_selector).click().perform() + + # 方法3:使用显式等待确保元素可点击 + # WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='semi-select select-lJTtRL semi-select-single']"))).click() + + time.sleep(2) + print("下拉框选择完成") + # input("按任意键继续...") + tab_selector_option = driver.find_element(By.XPATH, "//div[@class='semi-select-option-list semi-select-option-list-chosen']") + + ## 选择团购 + tab_selector_option = driver.find_element(By.XPATH, "//div[@data-code='13010' and @class='select-dropdown-option-video']") + driver.execute_script("arguments[0].click();", tab_selector_option) + time.sleep(2) + print("团购选择完成") + # input("按任意键继续...") + + ## 点击新的下拉框 + product_selector = driver.find_element(By.XPATH, "//div[@class='semi-select select-Qm4u8S semi-select-single semi-select-filterable']") + driver.execute_script("arguments[0].click();", product_selector) + time.sleep(2) + print("新的下拉框选择完成") + # input("按任意键继续...") + + product_input = driver.find_element(By.XPATH, "//input[@class='semi-input semi-input-default' and @placeholder='']") + product_input.send_keys("古龙峡漂流|国际(勇猛)赛道全程漂流票 成人票") + print("产品输入完成") + # input("按任意键继续...") + time.sleep(5) + + ## 下拉框选择这里有问题 找不到下拉框 + # 添加等待和重试机制 + max_retries = 10 + for attempt in range(max_retries): + # 使用JavaScript直接查找并点击元素,与控制台操作相同 + clicked = driver.execute_script(""" + // 尝试精确匹配类名 + let elements = document.getElementsByClassName('semi-select-option semi-select-option-focused option-v2-U5PXMk'); + if (elements.length > 0) { + elements[0].click(); + return true; + } + + // 备选方案1:使用更宽泛的类名查找 + elements = document.querySelectorAll('.semi-select-option'); + for (let el of elements) { + if (el.textContent.includes('古龙峡漂流')) { + el.click(); + return true; + } + } + + // 备选方案2:使用aria-role查找 + elements = document.querySelectorAll('[role="option"]'); + for (let el of elements) { + if (el.textContent.includes('古龙峡漂流')) { + el.click(); + return true; + } + } + + return false; + """) + + if clicked: + print(f"成功点击产品选项,尝试次数: {attempt+1}") + break + else: + print(f"等待产品选项出现,尝试次数: {attempt+1}/{max_retries}") + time.sleep(1) # 等待1秒后重试 + + # 等待一会,让点击生效 + time.sleep(2) + print("产品选择完成") + # input("按任意键继续...") + + product_info_input = driver.find_element(By.XPATH, "//input[@class='semi-input semi-input-default' and @placeholder='如:海底捞超值双人套餐']") + product_info_input.send_keys("古龙峡漂流成人票") + print("产品信息输入完成") + # input("按任意键继续...") + + confirm_button = driver.find_element(By.XPATH, "//div[@class='footer-button-DL8zDh']") + driver.execute_script("arguments[0].click();", confirm_button) + time.sleep(2) + print("确认完成") + # input("按任意键继续...") + + # 例如选择"定时发布"选项 + schedule_label = driver.find_element(By.XPATH, "//label[contains(@class, 'radio-d4zkru')]//span[contains(text(), '定时发布')]/ancestor::label") + driver.execute_script("arguments[0].click();", schedule_label) + # driver.execute_script("arguments[0].click();", time_selector_label) + time.sleep(2) + print("定时发布切换完成") + time_inputor = driver.find_element(By.XPATH, "//input[@class='semi-input semi-input-default' and @type='text' and @placeholder='日期和时间']") + time_inputor.send_keys("2025-05-27 10:00") + + time.sleep(10) + print("定时发布选择完成") + input("按任意键继续...") + + + # 发布图文 + # publisher.work(type="article", title="测试标题", content="测试内容 #测试话题", image_path="/path/to/your/image.jpg") + + # 发布视频 + # publisher.work(type="video", title="测试视频", content="测试视频内容 #测试话题", video_path="/Users/mac/Desktop/test.mp4") + + # 发布后保持浏览器窗口开启,方便检查结果 + input("按任意键退出...") + driver.quit() \ No newline at end of file