删除部分图文发布的日志打印

This commit is contained in:
sini_chen 2025-10-14 18:21:12 +08:00
parent 377e34c651
commit 36e3940410

View File

@ -476,26 +476,18 @@ class XiaoHongShuImage(object):
async def upload_images(self, page):
"""上传图片"""
xiaohongshu_logger.info(f'[+]正在上传图片,共{len(self.image_paths)}')
from pathlib import Path
xiaohongshu_logger.info(f'[+] 正在上传图片,共{len(self.image_paths)}')
# 直接访问了图文页面,等待页面元素加载
xiaohongshu_logger.info(" [-] 等待图文上传页面加载...")
# 等待页面加载
await asyncio.sleep(3)
# 点击上传图片按钮 - 使用更精确的选择器
xiaohongshu_logger.info(" [-] 查找上传图片按钮...")
# 尝试多种可能的选择器基于实际的HTML结构和截图信息
# 查找上传元素(简化选择器,移除详细日志)
upload_selectors = [
"input[class='upload-input'][type='file'][multiple]", # 最精确的选择器
"input[accept='.jpg,.jpeg,.png,.webp']", # 根据accept属性
"div[class^='upload-wrapper'] input[type='file']", # 上传包装器内的文件输入
"div[class^='drag-over'] input[type='file']", # 拖拽区域内的文件输入
"input[class='upload-input']", # 基本类名选择器
"input[type='file'][multiple]", # 通用文件输入选择器
# 基于截图中可能的新选择器
"input[type='file']", # 最通用的文件输入
"div[class*='upload'] input[type='file']", # 包含upload的div内的文件输入
"input[class='upload-input'][type='file'][multiple]",
"input[accept='.jpg,.jpeg,.png,.webp']",
"input[type='file'][multiple]",
"input[type='file']",
]
upload_input = None
@ -503,137 +495,95 @@ class XiaoHongShuImage(object):
try:
upload_input = await page.wait_for_selector(selector, timeout=3000)
if upload_input:
xiaohongshu_logger.info(f" [-] 找到上传按钮: {selector}")
break
except:
continue
if not upload_input:
# 尝试点击"上传图片"按钮来触发文件选择
xiaohongshu_logger.info(" [-] 未找到input元素尝试点击上传图片按钮...")
# 尝试点击上传按钮
try:
# 只保留带文字校验的上传按钮选择器
upload_button = None
try:
# 方法1精确匹配"上传图片"文字
upload_button = await page.wait_for_selector('button:has-text("上传图片")', timeout=3000)
xiaohongshu_logger.info(" [-] 找到'上传图片'按钮")
except:
try:
# 方法2div元素匹配"上传图片"文字
upload_button = await page.wait_for_selector('div:has-text("上传图片")', timeout=3000)
xiaohongshu_logger.info(" [-] 找到'上传图片'区域")
except:
xiaohongshu_logger.warning(" [-] 未找到'上传图片'按钮")
upload_button = await page.wait_for_selector('button:has-text("上传图片")', timeout=3000)
if not upload_button:
upload_button = await page.wait_for_selector('div:has-text("上传图片")', timeout=3000)
if upload_button:
await upload_button.click()
await asyncio.sleep(2)
# 再次尝试查找input元素
upload_input = await page.wait_for_selector("input[type='file']", timeout=3000)
if not upload_input:
raise Exception("点击上传按钮后仍未找到文件输入元素")
else:
raise Exception("未找到任何上传按钮")
if not upload_input:
raise Exception("未找到图片上传元素")
except Exception as e:
raise Exception(f"未找到图片上传按钮或输入元素: {e}")
# 一次性上传所有图片
xiaohongshu_logger.info(f" [-] 开始上传 {len(self.image_paths)} 张图片...")
for i, path in enumerate(self.image_paths, 1):
xiaohongshu_logger.info(f" {i}. {path}")
raise Exception(f"图片上传失败: {e}")
# 上传图片(显示文件名而不是完整路径)
file_names = [Path(p).name for p in self.image_paths]
xiaohongshu_logger.info(f" [-] 上传文件: {', '.join(file_names)}")
await upload_input.set_input_files(self.image_paths)
# 等待图片上传完成
xiaohongshu_logger.info(" [-] 等待图片上传完成...")
# 等待上传完成
await asyncio.sleep(2)
# 检查图片上传状态
await self.wait_for_images_upload_complete(page)
async def wait_for_images_upload_complete(self, page):
"""等待图片上传完成"""
xiaohongshu_logger.info(" [-] 检查图片上传状态...")
max_wait_time = 60 # 最大等待60秒
max_wait_time = 60
wait_count = 0
while wait_count < max_wait_time:
try:
# 检查是否有"添加"按钮,使用更精确的选择器
# 简化检查逻辑,移除详细日志
# 检查添加按钮
add_selectors = [
'div.entry:has-text("添加")', # 基于截图中的div.entry
'div[class*="entry"]:has-text("添加")',
'div.entry:has-text("添加")',
'div:has-text("添加")',
'[class*="upload"]:has-text("添加")',
'[class*="add"]:has-text("添加")'
]
add_button_found = False
for selector in add_selectors:
try:
add_button = await page.query_selector(selector)
if add_button:
xiaohongshu_logger.info(f" [-] 发现'添加'按钮 ({selector}),图片上传完成")
add_button_found = True
break
xiaohongshu_logger.success(" [-] 图片上传完成")
return
except:
continue
if add_button_found:
break
# 检查图片预览
try:
images = await page.query_selector_all('img')
valid_images = []
for img in images:
src = await img.get_attribute('src')
if src and ('data:image' in src or 'blob:' in src or len(src) > 50):
valid_images.append(img)
if len(valid_images) >= len(self.image_paths):
xiaohongshu_logger.success(f" [-] 图片上传完成 ({len(valid_images)}张)")
await asyncio.sleep(2)
return
except:
pass
# 检查是否有图片预览区域 (基于截图中的结构)
preview_selectors = [
'div[class*="img-preview-area"] img',
'div[class*="preview"] img',
'img[class*="icon"]',
'img'
]
image_count = 0
for selector in preview_selectors:
try:
images = await page.query_selector_all(selector)
# 过滤掉可能的图标或其他小图片
valid_images = []
for img in images:
src = await img.get_attribute('src')
if src and ('data:image' in src or 'blob:' in src or len(src) > 50):
valid_images.append(img)
if len(valid_images) >= len(self.image_paths):
xiaohongshu_logger.info(f" [-] 发现 {len(valid_images)} 个有效图片预览,上传可能完成")
image_count = len(valid_images)
break
except:
continue
if image_count >= len(self.image_paths):
await asyncio.sleep(2) # 再等待确保完全加载
break
# 检查是否有上传进度或加载状态
loading_elements = await page.query_selector_all('[class*="loading"], [class*="uploading"], [class*="progress"]')
# 检查加载状态
loading_elements = await page.query_selector_all('[class*="loading"], [class*="uploading"]')
if not loading_elements:
xiaohongshu_logger.info(" [-] 未发现加载状态,图片可能已上传完成")
break
xiaohongshu_logger.success(" [-] 图片上传完成")
return
xiaohongshu_logger.info(f" [-] 图片仍在上传中... ({wait_count + 1}/{max_wait_time})")
await asyncio.sleep(1)
wait_count += 1
# 减少日志频率每15秒输出一次进度
if wait_count % 15 == 0 and wait_count > 0:
xiaohongshu_logger.info(f" [-] 等待图片上传... ({wait_count}/{max_wait_time}秒)")
await asyncio.sleep(3)
wait_count += 3
except Exception as e:
xiaohongshu_logger.warning(f" [-] 检查上传状态时出错: {e}")
await asyncio.sleep(1)
wait_count += 1
xiaohongshu_logger.debug(f" [-] 检查上传状态出错: {e}")
await asyncio.sleep(3)
wait_count += 3
if wait_count >= max_wait_time:
xiaohongshu_logger.warning(" [-] 等待图片上传超时,继续执行后续步骤")
else:
xiaohongshu_logger.success(" [-] 图片上传完成,可以填写内容了")
xiaohongshu_logger.warning(" [-] 图片上传等待超时,继续流程")
async def locate_content_editor(self, page):
"""定位正文编辑区域"""
@ -784,136 +734,87 @@ class XiaoHongShuImage(object):
await page.keyboard.press("Enter")
await asyncio.sleep(0.3)
# 🔧 参考视频标签添加使用HumanTypingWrapper进行标签输入
xiaohongshu_logger.info(" [-] 开始智能输入标签...")
# 标签输入(参考视频标签添加方式)
xiaohongshu_logger.info(f" [-] 开始输入标签 ({len(self.tags)}个)...")
# 创建专门用于标签输入的人类化输入包装(参考视频配置)
# 创建标签输入器
from utils.human_typing_wrapper import HumanTypingWrapper
tag_config = {
'min_delay': 400, # 标签输入稍快于视频400ms vs 500ms
'max_delay': 700, # 最大延迟700ms
'pause_probability': 0.25, # 25%概率暂停(比视频稍低)
'pause_min': 400, # 暂停最少400ms
'pause_max': 1000, # 暂停最多1秒
'correction_probability': 0.02, # 2%概率打错字
'backspace_probability': 0.01, # 1%概率退格重输
'min_delay': 400, 'max_delay': 700, 'pause_probability': 0.25,
'pause_min': 400, 'pause_max': 1000, 'correction_probability': 0.02,
'backspace_probability': 0.01,
}
tag_typer = HumanTypingWrapper(page, tag_config)
xiaohongshu_logger.info(" [-] 已创建标签专用人类化输入器")
# 🔧 参考视频标签的输入方式:逐个标签输入,每个标签后都有停顿
# 输入标签(简化日志)
success = True
for i, tag in enumerate(self.tags):
tag_text = f"#{tag}"
xiaohongshu_logger.info(f" [-] 输入标签: {tag_text} ({i+1}/{len(self.tags)})")
# 标签间的思考时间(第一个标签除外)
# 标签间思考时间
if i > 0:
import random
think_time = random.uniform(0.8, 1.5) # 0.8-1.5秒思考时间
xiaohongshu_logger.debug(f" [-] 思考下一个标签... ({think_time:.1f}秒)")
await asyncio.sleep(think_time)
await asyncio.sleep(random.uniform(0.8, 1.5))
# 使用人类化输入器输入标签(参考视频方式)
# 输入标签
tag_success = await tag_typer.type_text_human(
css_selector,
tag_text,
clear_first=False # 不清空,追加内容
css_selector, f"#{tag}", clear_first=False
)
if not tag_success:
xiaohongshu_logger.warning(f" [-] 标签 {tag} 人类化输入失败,使用备用方式")
success = False
break
# 🔧 处理标签建议(如果有的话)
# 处理标签建议
await self._handle_tag_suggestions_after_input(page, tag)
# 标签间分隔(参考视频:使用空格而不是换行)
# 标签间分隔
if i < len(self.tags) - 1:
await page.keyboard.type(" ")
# 空格后的短暂停顿
import random
space_pause = random.uniform(0.2, 0.5)
await asyncio.sleep(space_pause)
xiaohongshu_logger.info(f" [-] 标签输入完成: {tag} ({i+1}/{len(self.tags)})")
await asyncio.sleep(random.uniform(0.2, 0.5))
# 🔧 如果人类化输入失败,使用备用方式(参考视频的备用逻辑)
# 备用输入方式
if not success:
xiaohongshu_logger.warning(" [-] 标签人类化输入失败,使用传统方式")
xiaohongshu_logger.warning(" [-] 使用备用标签输入方式")
await self._fallback_tag_input(page, css_selector)
xiaohongshu_logger.info(f' [-] 总共添加了{len(self.tags)}个标签')
xiaohongshu_logger.success(f' [-] 标签输入完成 ({len(self.tags)}个)')
async def _handle_tag_suggestions_after_input(self, page: Page, tag: str) -> None:
"""
标签输入后处理建议选择简化版专注于核心功能
Args:
page: Playwright页面对象
tag: 标签内容
"""
"""标签输入后处理建议选择"""
try:
import random
await asyncio.sleep(random.uniform(0.5, 1.0))
# 等待建议出现(随机时间)
wait_time = random.uniform(0.5, 1.0)
await asyncio.sleep(wait_time)
# 尝试查找并选择建议(简化逻辑)
suggestion_found = await self._handle_tag_suggestions(page, tag)
if suggestion_found:
xiaohongshu_logger.debug(f" [-] 已选择标签建议: {tag}")
else:
# 没有建议时,按回车确认(模拟用户行为)
hesitate_time = random.uniform(0.2, 0.5)
await asyncio.sleep(hesitate_time)
if not suggestion_found:
await asyncio.sleep(random.uniform(0.2, 0.5))
await page.keyboard.press("Enter")
xiaohongshu_logger.debug(f" [-] 无建议,已确认标签: {tag}")
except Exception as e:
xiaohongshu_logger.debug(f" [-] 处理标签建议时出错: {e}")
xiaohongshu_logger.debug(f" [-] 标签建议处理出错: {e}")
async def _fallback_tag_input(self, page: Page, css_selector: str) -> None:
"""
备用标签输入方法参考视频的备用逻辑
Args:
page: Playwright页面对象
css_selector: 内容区域选择器
"""
"""备用标签输入方法"""
try:
import random
xiaohongshu_logger.info(" [-] 使用备用方式输入标签...")
# 点击内容区域
await page.click(css_selector)
await asyncio.sleep(0.5)
for index, tag in enumerate(self.tags, start=1):
xiaohongshu_logger.info(f" [-] 备用方式输入标签: #{tag} ({index}/{len(self.tags)})")
# 输入#号
# 输入标签(移除详细日志)
await page.keyboard.type("#")
await asyncio.sleep(random.uniform(0.1, 0.3))
# 逐字符输入标签(参考视频的慢速输入)
for char in tag:
await page.keyboard.type(char, delay=random.randint(300, 600))
await asyncio.sleep(random.uniform(0.8, 1.2)) # 参考视频的1000ms等待
await asyncio.sleep(random.uniform(0.8, 1.2))
# 标签间分隔
if index < len(self.tags):
await page.keyboard.type(" ")
await asyncio.sleep(random.uniform(0.3, 0.6))
xiaohongshu_logger.info(f" [-] 备用方式完成标签: {tag}")
except Exception as e:
xiaohongshu_logger.error(f" [-] 备用标签输入失败: {e}")
@ -933,9 +834,8 @@ class XiaoHongShuImage(object):
try:
import random
# 按段落分割文本
# 按段落分割文本(简化日志)
paragraphs = content_text.split('\n\n')
xiaohongshu_logger.info(f" [-] 分割为 {len(paragraphs)} 个段落")
# 清空输入区域
await content_typer.clear_element(css_selector)
@ -944,14 +844,10 @@ class XiaoHongShuImage(object):
for i, paragraph in enumerate(paragraphs, 1):
if not paragraph.strip():
continue
xiaohongshu_logger.info(f" [-] 输入第 {i}/{len(paragraphs)} 段落 ({len(paragraph)} 字符)")
# 输入段落内容
# 输入段落内容(移除详细日志)
success = await content_typer.type_text_human(
css_selector,
paragraph,
clear_first=False # 不清空,追加内容
css_selector, paragraph, clear_first=False
)
if not success:
@ -962,11 +858,7 @@ class XiaoHongShuImage(object):
if i < len(paragraphs):
await page.keyboard.press("Enter")
await page.keyboard.press("Enter")
# 段落间的思考暂停1-3秒
think_time = random.uniform(1.0, 3.0)
xiaohongshu_logger.debug(f" [-] 段落间思考暂停 {think_time:.1f}")
await asyncio.sleep(think_time)
await asyncio.sleep(random.uniform(1.0, 3.0))
xiaohongshu_logger.success(" [-] 分段输入完成")
return True
@ -994,15 +886,14 @@ class XiaoHongShuImage(object):
delay = random.randint(50, 120) # 50-120ms随机延迟
await asyncio.sleep(delay / 1000)
# 偶尔暂停,模拟思考
# 偶尔暂停,模拟思考(移除详细日志)
if random.random() < 0.05: # 5%概率暂停
pause_time = random.randint(300, 800)
xiaohongshu_logger.debug(f" [-] 思考暂停 {pause_time}ms")
await asyncio.sleep(pause_time / 1000)
# 每50个字符显示进度
if char_count % 50 == 0:
xiaohongshu_logger.debug(f" [-] 输入 {char_count}/{len(content_text)} 字符")
# 减少进度日志频率每100个字符显示一次
if char_count % 100 == 0:
xiaohongshu_logger.debug(f" [-] 输入进度: {char_count}/{len(content_text)}")
async def _input_single_tag(self, page: Page, tag: str, current: int, total: int) -> None:
"""