删除部分图文发布的日志打印
This commit is contained in:
parent
377e34c651
commit
36e3940410
@ -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:
|
||||
# 方法2:div元素匹配"上传图片"文字
|
||||
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:
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user