|
@@ -276,36 +276,117 @@ class XiaohongshuPublisher(BasePublisher):
|
|
|
|
|
|
|
|
current_url = self.page.url
|
|
current_url = self.page.url
|
|
|
print(f"[{self.platform_name}] 当前 URL: {current_url}")
|
|
print(f"[{self.platform_name}] 当前 URL: {current_url}")
|
|
|
|
|
+
|
|
|
|
|
+ async def wait_for_manual_login(timeout_seconds: int = 300) -> bool:
|
|
|
|
|
+ if not self.page:
|
|
|
|
|
+ return False
|
|
|
|
|
+ self.report_progress(12, "检测到需要登录,请在浏览器窗口完成登录...")
|
|
|
|
|
+ try:
|
|
|
|
|
+ await self.page.bring_to_front()
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+ waited = 0
|
|
|
|
|
+ while waited < timeout_seconds:
|
|
|
|
|
+ try:
|
|
|
|
|
+ url = self.page.url
|
|
|
|
|
+ if "login" not in url and "passport" not in url and "creator.xiaohongshu.com" in url:
|
|
|
|
|
+ return True
|
|
|
|
|
+ await asyncio.sleep(2)
|
|
|
|
|
+ waited += 2
|
|
|
|
|
+ except:
|
|
|
|
|
+ await asyncio.sleep(2)
|
|
|
|
|
+ waited += 2
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ async def wait_for_manual_captcha(timeout_seconds: int = 180) -> bool:
|
|
|
|
|
+ waited = 0
|
|
|
|
|
+ while waited < timeout_seconds:
|
|
|
|
|
+ try:
|
|
|
|
|
+ ai_captcha = await self.ai_check_captcha()
|
|
|
|
|
+ if not ai_captcha.get("has_captcha"):
|
|
|
|
|
+ return True
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+ await asyncio.sleep(3)
|
|
|
|
|
+ waited += 3
|
|
|
|
|
+ return False
|
|
|
|
|
|
|
|
# 检查登录状态
|
|
# 检查登录状态
|
|
|
if "login" in current_url or "passport" in current_url:
|
|
if "login" in current_url or "passport" in current_url:
|
|
|
- screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
- return PublishResult(
|
|
|
|
|
- success=False,
|
|
|
|
|
- platform=self.platform_name,
|
|
|
|
|
- error="登录已过期,请重新登录",
|
|
|
|
|
- screenshot_base64=screenshot_base64,
|
|
|
|
|
- page_url=current_url,
|
|
|
|
|
- status='need_captcha',
|
|
|
|
|
- need_captcha=True,
|
|
|
|
|
- captcha_type='login'
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ if not self.headless:
|
|
|
|
|
+ logged_in = await wait_for_manual_login()
|
|
|
|
|
+ if logged_in:
|
|
|
|
|
+ try:
|
|
|
|
|
+ if self.context:
|
|
|
|
|
+ cookies_after = await self.context.cookies()
|
|
|
|
|
+ await self.sync_cookies_to_node(cookies_after)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+ await self.page.goto(publish_url)
|
|
|
|
|
+ await asyncio.sleep(3)
|
|
|
|
|
+ current_url = self.page.url
|
|
|
|
|
+ else:
|
|
|
|
|
+ screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
+ return PublishResult(
|
|
|
|
|
+ success=False,
|
|
|
|
|
+ platform=self.platform_name,
|
|
|
|
|
+ error="需要登录:请在浏览器窗口完成登录后重试",
|
|
|
|
|
+ screenshot_base64=screenshot_base64,
|
|
|
|
|
+ page_url=current_url,
|
|
|
|
|
+ status='need_captcha',
|
|
|
|
|
+ need_captcha=True,
|
|
|
|
|
+ captcha_type='login'
|
|
|
|
|
+ )
|
|
|
|
|
+ else:
|
|
|
|
|
+ screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
+ return PublishResult(
|
|
|
|
|
+ success=False,
|
|
|
|
|
+ platform=self.platform_name,
|
|
|
|
|
+ error="登录已过期,请重新登录",
|
|
|
|
|
+ screenshot_base64=screenshot_base64,
|
|
|
|
|
+ page_url=current_url,
|
|
|
|
|
+ status='need_captcha',
|
|
|
|
|
+ need_captcha=True,
|
|
|
|
|
+ captcha_type='login'
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
# 使用 AI 检查验证码
|
|
# 使用 AI 检查验证码
|
|
|
ai_captcha = await self.ai_check_captcha()
|
|
ai_captcha = await self.ai_check_captcha()
|
|
|
if ai_captcha['has_captcha']:
|
|
if ai_captcha['has_captcha']:
|
|
|
print(f"[{self.platform_name}] AI检测到验证码: {ai_captcha['captcha_type']}", flush=True)
|
|
print(f"[{self.platform_name}] AI检测到验证码: {ai_captcha['captcha_type']}", flush=True)
|
|
|
- screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
- return PublishResult(
|
|
|
|
|
- success=False,
|
|
|
|
|
- platform=self.platform_name,
|
|
|
|
|
- error=f"检测到{ai_captcha['captcha_type']}验证码,需要使用有头浏览器完成验证",
|
|
|
|
|
- screenshot_base64=screenshot_base64,
|
|
|
|
|
- page_url=current_url,
|
|
|
|
|
- status='need_captcha',
|
|
|
|
|
- need_captcha=True,
|
|
|
|
|
- captcha_type=ai_captcha['captcha_type']
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ if not self.headless:
|
|
|
|
|
+ solved = await wait_for_manual_captcha()
|
|
|
|
|
+ if solved:
|
|
|
|
|
+ try:
|
|
|
|
|
+ if self.context:
|
|
|
|
|
+ cookies_after = await self.context.cookies()
|
|
|
|
|
+ await self.sync_cookies_to_node(cookies_after)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+ else:
|
|
|
|
|
+ screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
+ return PublishResult(
|
|
|
|
|
+ success=False,
|
|
|
|
|
+ platform=self.platform_name,
|
|
|
|
|
+ error=f"需要验证码:请在浏览器窗口完成验证后重试",
|
|
|
|
|
+ screenshot_base64=screenshot_base64,
|
|
|
|
|
+ page_url=current_url,
|
|
|
|
|
+ status='need_captcha',
|
|
|
|
|
+ need_captcha=True,
|
|
|
|
|
+ captcha_type=ai_captcha['captcha_type']
|
|
|
|
|
+ )
|
|
|
|
|
+ else:
|
|
|
|
|
+ screenshot_base64 = await self.capture_screenshot()
|
|
|
|
|
+ return PublishResult(
|
|
|
|
|
+ success=False,
|
|
|
|
|
+ platform=self.platform_name,
|
|
|
|
|
+ error=f"检测到{ai_captcha['captcha_type']}验证码,需要使用有头浏览器完成验证",
|
|
|
|
|
+ screenshot_base64=screenshot_base64,
|
|
|
|
|
+ page_url=current_url,
|
|
|
|
|
+ status='need_captcha',
|
|
|
|
|
+ need_captcha=True,
|
|
|
|
|
+ captcha_type=ai_captcha['captcha_type']
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
self.report_progress(20, "正在上传视频...")
|
|
self.report_progress(20, "正在上传视频...")
|
|
|
|
|
|
|
@@ -495,6 +576,23 @@ class XiaohongshuPublisher(BasePublisher):
|
|
|
print(f"[{self.platform_name}] 选择器 {selector} 错误: {e}")
|
|
print(f"[{self.platform_name}] 选择器 {selector} 错误: {e}")
|
|
|
|
|
|
|
|
if not publish_clicked:
|
|
if not publish_clicked:
|
|
|
|
|
+ try:
|
|
|
|
|
+ suggest = await self.ai_suggest_playwright_selector("点击小红书发布按钮")
|
|
|
|
|
+ if suggest.get("has_selector") and suggest.get("selector"):
|
|
|
|
|
+ sel = suggest.get("selector")
|
|
|
|
|
+ btn = self.page.locator(sel).first
|
|
|
|
|
+ if await btn.count() > 0 and await btn.is_visible() and await btn.is_enabled():
|
|
|
|
|
+ try:
|
|
|
|
|
+ await btn.click()
|
|
|
|
|
+ except:
|
|
|
|
|
+ box = await btn.bounding_box()
|
|
|
|
|
+ if box:
|
|
|
|
|
+ await self.page.mouse.click(box['x'] + box['width']/2, box['y'] + box['height']/2)
|
|
|
|
|
+ publish_clicked = True
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"[{self.platform_name}] AI 点击发布按钮失败: {e}", flush=True)
|
|
|
|
|
+
|
|
|
|
|
+ if not publish_clicked:
|
|
|
# 保存截图用于调试
|
|
# 保存截图用于调试
|
|
|
screenshot_path = f"debug_publish_failed_{self.platform_name}.png"
|
|
screenshot_path = f"debug_publish_failed_{self.platform_name}.png"
|
|
|
await self.page.screenshot(path=screenshot_path, full_page=True)
|
|
await self.page.screenshot(path=screenshot_path, full_page=True)
|