kuaishou.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # -*- coding: utf-8 -*-
  2. """
  3. 快手视频发布器
  4. 参考: matrix/ks_uploader/main.py
  5. """
  6. import asyncio
  7. import os
  8. from datetime import datetime
  9. from .base import BasePublisher, PublishParams, PublishResult
  10. class KuaishouPublisher(BasePublisher):
  11. """
  12. 快手视频发布器
  13. 使用 Playwright 自动化操作快手创作者中心
  14. """
  15. platform_name = "kuaishou"
  16. login_url = "https://cp.kuaishou.com/"
  17. publish_url = "https://cp.kuaishou.com/article/publish/video"
  18. cookie_domain = ".kuaishou.com"
  19. async def set_schedule_time(self, publish_date: datetime):
  20. """设置定时发布"""
  21. if not self.page:
  22. return
  23. # 选择定时发布
  24. label_element = self.page.locator("label.radio--4Gpx6:has-text('定时发布')")
  25. await label_element.click()
  26. await asyncio.sleep(1)
  27. # 输入时间
  28. publish_date_str = publish_date.strftime("%Y-%m-%d %H:%M")
  29. await self.page.locator('.semi-input[placeholder="日期和时间"]').click()
  30. await self.page.keyboard.press("Control+KeyA")
  31. await self.page.keyboard.type(str(publish_date_str))
  32. await self.page.keyboard.press("Enter")
  33. await asyncio.sleep(1)
  34. async def upload_cover(self, cover_path: str):
  35. """上传封面图"""
  36. if not self.page or not cover_path or not os.path.exists(cover_path):
  37. return
  38. try:
  39. await self.page.get_by_role("button", name="编辑封面").click()
  40. await asyncio.sleep(1)
  41. await self.page.get_by_role("tab", name="上传封面").click()
  42. preview_div = self.page.get_by_role("tabpanel", name="上传封面").locator("div").nth(1)
  43. async with self.page.expect_file_chooser() as fc_info:
  44. await preview_div.click()
  45. preview_chooser = await fc_info.value
  46. await preview_chooser.set_files(cover_path)
  47. await self.page.get_by_role("button", name="确认").click()
  48. await asyncio.sleep(3)
  49. print(f"[{self.platform_name}] 封面上传成功")
  50. except Exception as e:
  51. print(f"[{self.platform_name}] 封面上传失败: {e}")
  52. async def publish(self, cookies: str, params: PublishParams) -> PublishResult:
  53. """发布视频到快手"""
  54. self.report_progress(5, "正在初始化浏览器...")
  55. # 初始化浏览器
  56. await self.init_browser()
  57. # 解析并设置 cookies
  58. cookie_list = self.parse_cookies(cookies)
  59. await self.set_cookies(cookie_list)
  60. if not self.page:
  61. raise Exception("Page not initialized")
  62. # 检查视频文件
  63. if not os.path.exists(params.video_path):
  64. raise Exception(f"视频文件不存在: {params.video_path}")
  65. self.report_progress(10, "正在打开上传页面...")
  66. # 访问上传页面
  67. await self.page.goto(self.publish_url)
  68. await self.page.wait_for_url(self.publish_url, timeout=30000)
  69. self.report_progress(15, "正在选择视频文件...")
  70. # 点击上传按钮
  71. upload_btn = self.page.get_by_role("button", name="上传视频")
  72. async with self.page.expect_file_chooser() as fc_info:
  73. await upload_btn.click()
  74. file_chooser = await fc_info.value
  75. await file_chooser.set_files(params.video_path)
  76. await asyncio.sleep(1)
  77. # 关闭可能的弹窗
  78. known_btn = self.page.get_by_role("button", name="我知道了")
  79. if await known_btn.count():
  80. await known_btn.click()
  81. self.report_progress(20, "正在填充标题...")
  82. # 填写标题
  83. await asyncio.sleep(1)
  84. title_input = self.page.get_by_placeholder('添加合适的话题和描述,作品能获得更多推荐~')
  85. if await title_input.count():
  86. await title_input.click()
  87. await title_input.fill(params.title[:30])
  88. self.report_progress(30, "等待视频上传完成...")
  89. # 等待上传完成
  90. for _ in range(120):
  91. try:
  92. count = await self.page.locator('span:has-text("上传成功")').count()
  93. if count > 0:
  94. print(f"[{self.platform_name}] 视频上传完毕")
  95. break
  96. await asyncio.sleep(3)
  97. except:
  98. await asyncio.sleep(3)
  99. self.report_progress(50, "正在上传封面...")
  100. # 上传封面
  101. await self.upload_cover(params.cover_path)
  102. # 定时发布(快手暂不支持或选择器有变化)
  103. # if params.publish_date:
  104. # await self.set_schedule_time(params.publish_date)
  105. self.report_progress(80, "正在发布...")
  106. # 点击发布
  107. for _ in range(30):
  108. try:
  109. publish_btn = self.page.get_by_role('button', name="发布", exact=True)
  110. if await publish_btn.count():
  111. await publish_btn.click()
  112. await self.page.wait_for_url(
  113. "https://cp.kuaishou.com/article/manage/video*",
  114. timeout=5000
  115. )
  116. self.report_progress(100, "发布成功")
  117. return PublishResult(
  118. success=True,
  119. platform=self.platform_name,
  120. message="发布成功"
  121. )
  122. except:
  123. current_url = self.page.url
  124. if "manage/video" in current_url:
  125. self.report_progress(100, "发布成功")
  126. return PublishResult(
  127. success=True,
  128. platform=self.platform_name,
  129. message="发布成功"
  130. )
  131. await asyncio.sleep(1)
  132. raise Exception("发布超时")