fix(tencent): 图文发布改用独立创建页 finderNewLifeCreate(不再在视频表单里切换模式);全面拉长 timeout 适配慢网络;清理调试代码
This commit is contained in:
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 232 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -23,6 +23,8 @@ TENCENT_LOGIN_URL = "https://channels.weixin.qq.com"
|
||||
TENCENT_HOME_URL = "https://channels.weixin.qq.com/platform"
|
||||
TENCENT_UPLOAD_URL = "https://channels.weixin.qq.com/platform/post/create"
|
||||
TENCENT_MANAGE_URL = "https://channels.weixin.qq.com/platform/post/list"
|
||||
# 图文发布有独立创建页,不需要在视频表单里切换模式
|
||||
TENCENT_NOTE_CREATE_URL = "https://channels.weixin.qq.com/platform/post/finderNewLifeCreate"
|
||||
TENCENT_PUBLISH_STRATEGY_IMMEDIATE = "immediate"
|
||||
TENCENT_PUBLISH_STRATEGY_SCHEDULED = "scheduled"
|
||||
|
||||
@@ -697,28 +699,59 @@ class TencentBaseUploader(BaseVideoUploader):
|
||||
if any("open.weixin.qq.com/connect/qrconnect" in fr.url for fr in page.frames):
|
||||
raise RuntimeError("视频号 cookie 已失效(被跳转到登录页),请重新扫码登录后再发布")
|
||||
try:
|
||||
await page.wait_for_load_state("networkidle", timeout=15000)
|
||||
await page.wait_for_load_state("networkidle", timeout=30000)
|
||||
except Exception:
|
||||
pass
|
||||
# 注意:get_by_text("发表视频") 会命中一个隐藏的说明 <p>(不可点);
|
||||
# 首页真正可点的入口是 button.weui-desktop-btn。
|
||||
publish_entry = page.locator("button.weui-desktop-btn", has_text="发表视频").first
|
||||
# 注意:「发表视频」按钮在首页的 post-card.html iframe 里,不在顶层文档,
|
||||
# 必须用 frame_locator 进入该 iframe 才能点到;用 page.locator 只搜顶层会找不到,
|
||||
# 导致走兜底直接 goto post/create,表单 iframe 只挂载空壳(Vue 不渲染)。
|
||||
clicked = False
|
||||
try:
|
||||
await publish_entry.wait_for(state="visible", timeout=30000)
|
||||
publish_entry = page.frame_locator('iframe[src*="post-card"]').locator(
|
||||
"button.weui-desktop-btn", has_text="发表视频"
|
||||
).first
|
||||
await publish_entry.wait_for(state="visible", timeout=60000)
|
||||
await publish_entry.click()
|
||||
clicked = True
|
||||
except Exception:
|
||||
# 兜底:按钮没点到时退回老逻辑直接跳转(可能仍是空壳,但保持向后兼容)
|
||||
# 兜底:遍历所有 frame 找「发表视频」按钮
|
||||
for fr in page.frames:
|
||||
try:
|
||||
entry = fr.locator("button.weui-desktop-btn", has_text="发表视频").first
|
||||
if await entry.count() and await entry.is_visible():
|
||||
await entry.click()
|
||||
clicked = True
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
if not clicked:
|
||||
# 最后兜底:按钮没点到时退回老逻辑直接跳转(可能仍是空壳,但保持向后兼容)
|
||||
tencent_logger.warning(_msg("⚠️", "未在首页找到「发表视频」入口,退回直接打开发布页"))
|
||||
await page.goto(TENCENT_UPLOAD_URL, timeout=120000, wait_until="domcontentloaded")
|
||||
else:
|
||||
tencent_logger.info(_msg("🖱️", "已点击首页「发表视频」入口"))
|
||||
try:
|
||||
await page.wait_for_url("**/platform/post/create", timeout=120000)
|
||||
except Exception:
|
||||
pass
|
||||
# 追踪:点击后各 frame 状态,确认表单是否真正挂载
|
||||
try:
|
||||
frame_info = []
|
||||
for fr in page.frames:
|
||||
try:
|
||||
fi = await fr.locator('input[type="file"]').count()
|
||||
frame_info.append(f"{fr.url[:45]}(file_input={fi})")
|
||||
except Exception:
|
||||
frame_info.append(f"{fr.url[:45]}(err)")
|
||||
tencent_logger.info(_msg("🔍", f"打开发布页后 frame 状态: {frame_info}"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 上传表单在 micro/content/post/create 这个 iframe 里,domcontentloaded 时它还是空的。
|
||||
# 不等网络静默就去找 input[type=file],会误报「未找到视频号文件上传框」——
|
||||
# 失败截图上左栏渲染正常、主内容区一片空白,看起来完全不像加载没完成。
|
||||
try:
|
||||
await page.wait_for_load_state("networkidle", timeout=30000)
|
||||
await page.wait_for_load_state("networkidle", timeout=60000)
|
||||
except Exception:
|
||||
pass # 静默不了就算了,下面还有重试兜底
|
||||
|
||||
@@ -735,7 +768,7 @@ class TencentBaseUploader(BaseVideoUploader):
|
||||
|
||||
fi = await find_file_input()
|
||||
clicked_publish = False
|
||||
for _ in range(60):
|
||||
for _ in range(120):
|
||||
if fi is not None:
|
||||
break
|
||||
if not clicked_publish:
|
||||
@@ -1288,33 +1321,13 @@ class TencentNote(TencentBaseUploader):
|
||||
self.image_paths = normalized_image_paths
|
||||
|
||||
async def switch_to_note_mode(self, page: Page) -> None:
|
||||
"""切换到图文发布模式。
|
||||
"""切换到图文发布模式(已废弃)。
|
||||
|
||||
视频号发布页(/platform/post/create)默认是视频模式,图文需切到图片模式。
|
||||
优先点「发表图片」入口,再尝试页面内「图片/图文」tab,找不到则按当前页面继续。
|
||||
图文发布有独立创建页 platform/post/finderNewLifeCreate,
|
||||
open_note_page 已直接导航到图文表单,不需要再在视频表单里切换模式。
|
||||
保留此方法仅为向后兼容,实际不再被调用。
|
||||
"""
|
||||
for label in ["发表图片", "发布图片", "图片动态"]:
|
||||
try:
|
||||
entry = page.locator("button", has_text=label).first
|
||||
if await entry.count():
|
||||
await entry.wait_for(state="visible", timeout=8000)
|
||||
await entry.click()
|
||||
await page.wait_for_timeout(1500)
|
||||
tencent_logger.info(_msg("🖼️", f"已点击「{label}」切换到图文模式"))
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
for text in ["图片", "图文"]:
|
||||
try:
|
||||
tab = page.locator('[role="tab"]', has_text=text).first
|
||||
if await tab.count():
|
||||
await tab.click(timeout=5000)
|
||||
await page.wait_for_timeout(1000)
|
||||
tencent_logger.info(_msg("🖼️", f"已点击「{text}」tab 切换到图文模式"))
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
tencent_logger.warning(_msg("⚠️", "未找到明确的图文入口,按当前页面继续尝试上传图片"))
|
||||
pass
|
||||
|
||||
async def upload_note_images(self, page: Page) -> None:
|
||||
"""上传图文图片(优先 accept 含 image 的 file input,兜底任意 file input)。"""
|
||||
@@ -1366,10 +1379,36 @@ class TencentNote(TencentBaseUploader):
|
||||
await self.apply_original_statement(page)
|
||||
|
||||
async def upload_note_content(self, page: Page) -> None:
|
||||
await self.switch_to_note_mode(page)
|
||||
# 图文发布有独立创建页(finderNewLifeCreate),open_note_page 已直接导航到图文表单,
|
||||
# 不需要再在视频表单里切换模式
|
||||
await self.upload_note_images(page)
|
||||
await self.prepare_note_for_publish(page)
|
||||
|
||||
async def open_note_page(self, page: Page) -> None:
|
||||
"""打开图文发布页(独立路径,不需要在视频表单里切换模式)。
|
||||
|
||||
图文发布有独立创建页 platform/post/finderNewLifeCreate,直接导航即可。
|
||||
网络慢时表单挂载较慢,拉长等待时间。
|
||||
"""
|
||||
await page.goto(TENCENT_NOTE_CREATE_URL, timeout=180000, wait_until="domcontentloaded")
|
||||
# cookie 失效时前端 JS 会跳转到登录页, 提前发现并报明确的错误
|
||||
try:
|
||||
await page.wait_for_url("**/login.html**", timeout=10000)
|
||||
raise RuntimeError("视频号 cookie 已失效(被跳转到登录页),请重新扫码登录后再发布")
|
||||
except TimeoutError:
|
||||
pass # 10 秒内未跳转, 正常
|
||||
except RuntimeError:
|
||||
raise
|
||||
except Exception:
|
||||
pass
|
||||
if any("open.weixin.qq.com/connect/qrconnect" in fr.url for fr in page.frames):
|
||||
raise RuntimeError("视频号 cookie 已失效(被跳转到登录页),请重新扫码登录后再发布")
|
||||
# 等表单挂载,网络慢时拉长等待
|
||||
try:
|
||||
await page.wait_for_load_state("networkidle", timeout=60000)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def upload(self, playwright: Playwright) -> None:
|
||||
tencent_logger.info(_msg("🧍", "小人先检查 cookie、图文图片和发布时间"))
|
||||
await self.validate_upload_args()
|
||||
@@ -1381,7 +1420,7 @@ class TencentNote(TencentBaseUploader):
|
||||
|
||||
try:
|
||||
page = await context.new_page()
|
||||
await self.open_upload_page(page)
|
||||
await self.open_note_page(page)
|
||||
tencent_logger.info(_msg("🏃", f"小人开始搬运图文,共 {len(self.image_paths)} 张图片"))
|
||||
|
||||
await self.upload_note_content(page)
|
||||
|
||||
Reference in New Issue
Block a user