demo init
This commit is contained in:
commit
0b10533b10
337
douyin_publisher.py
Normal file
337
douyin_publisher.py
Normal file
@ -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)
|
||||
# <button class="semi-button semi-button-primary container-drag-btn-k6XmB4 semi-button-with-icon" type="button"><span class="semi-button-content"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20"><rect width="16.333" height="13" x="1.833" y="3.5" stroke="#fff" stroke-width="2" rx="2"></rect><path stroke="#fff" stroke-linecap="round" stroke-width="2" d="M10 7.5v5M12.5 10h-5"></path></svg><span class="semi-button-content-right">上传视频</span></span></button>
|
||||
|
||||
# 上传视频按钮
|
||||
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()
|
Loading…
x
Reference in New Issue
Block a user