新增测试工具,修改复制粘贴功能使其实现(初版
This commit is contained in:
parent
b954c8adcf
commit
3b58e22f91
206
test_typing.py
Normal file
206
test_typing.py
Normal file
@ -0,0 +1,206 @@
|
||||
import asyncio
|
||||
import random
|
||||
from playwright.async_api import async_playwright
|
||||
from utils.enhanced_human_typing import EnhancedHumanTypingSimulator
|
||||
from utils.paste_typing import PasteTypingSimulator
|
||||
|
||||
async def xhs_tag_input(page, tags: list, selector: str):
|
||||
"""模拟小红书的标签输入逻辑"""
|
||||
element = await page.wait_for_selector(selector)
|
||||
await element.click()
|
||||
|
||||
for i, tag in enumerate(tags):
|
||||
# 输入#号
|
||||
await page.keyboard.press("Shift")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
await page.keyboard.press("3")
|
||||
await page.keyboard.up("Shift")
|
||||
await asyncio.sleep(random.uniform(0.2, 0.4))
|
||||
|
||||
# 输入标签文本
|
||||
for char in tag:
|
||||
await page.keyboard.type(char, delay=random.randint(300, 500))
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
|
||||
# 输入回车并等待
|
||||
await page.keyboard.press("Enter")
|
||||
await asyncio.sleep(random.uniform(0.5, 0.8))
|
||||
|
||||
# 标签间额外停顿
|
||||
if i < len(tags) - 1:
|
||||
await asyncio.sleep(random.uniform(0.8, 1.2))
|
||||
|
||||
async def xhs_type_text(page, text: str, selector: str):
|
||||
"""模拟小红书的文本输入逻辑"""
|
||||
# 定位元素
|
||||
element = await page.wait_for_selector(selector)
|
||||
await element.click()
|
||||
|
||||
# 按段落分割
|
||||
paragraphs = text.split('\n\n')
|
||||
for i, paragraph in enumerate(paragraphs):
|
||||
if not paragraph.strip():
|
||||
continue
|
||||
|
||||
# 逐字符输入
|
||||
for j, char in enumerate(paragraph):
|
||||
# 特殊字符处理
|
||||
if char in ',。!?、':
|
||||
# 中文标点输入稍慢
|
||||
await page.keyboard.type(char, delay=random.randint(200, 300))
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
elif char in ',.!?':
|
||||
# 英文标点输入较快
|
||||
await page.keyboard.type(char, delay=random.randint(150, 250))
|
||||
await asyncio.sleep(random.uniform(0.08, 0.15))
|
||||
else:
|
||||
# 普通字符正常速度
|
||||
await page.keyboard.type(char, delay=random.randint(100, 200))
|
||||
await asyncio.sleep(random.uniform(0.05, 0.1))
|
||||
|
||||
# 每输入15-25个字符后可能停顿思考
|
||||
if j > 0 and j % random.randint(15, 25) == 0:
|
||||
await asyncio.sleep(random.uniform(0.3, 0.8))
|
||||
|
||||
# 段落间添加换行和思考时间
|
||||
if i < len(paragraphs) - 1:
|
||||
# 段落结束,停顿思考
|
||||
await asyncio.sleep(random.uniform(0.5, 1.0))
|
||||
# 输入两个换行
|
||||
await page.keyboard.press("Enter")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
await page.keyboard.press("Enter")
|
||||
# 准备输入下一段
|
||||
await asyncio.sleep(random.uniform(0.8, 1.5))
|
||||
|
||||
async def test_typing():
|
||||
test_text = """这是一段测试文本,用来展示人类化输入效果。
|
||||
|
||||
这是第二段落,包含一些标点符号:,。!?
|
||||
以及一些英文字符和数字 Hello World 123。
|
||||
|
||||
最后一段用来测试段落之间的停顿效果。
|
||||
|
||||
✨【交通指南】
|
||||
✅7号线直达施园站,步行5分钟入园
|
||||
✅自驾导航「北京环球城市大道」,停车场直通园区
|
||||
⏰建议早9点开园前排队,热门项目可节省1小时等待
|
||||
|
||||
🎢【必玩项目清单】
|
||||
🔥哈利波特:对角巷买黄油啤酒,探索霍格沃茨城堡内部奥秘(需提前线上预约)
|
||||
🔥侏罗纪世界:大冒险激流勇进必玩,恐龙特效超震撼
|
||||
🔥变形金刚:霸天虎过山车速度与激情现场版
|
||||
🔥小黄人乐园:适合带娃拍照,旋转扫把项目萌趣满分
|
||||
|
||||
🍽️【美食玄学】
|
||||
✔️好莱坞街区「霓虹街市集」汉堡配奶昔
|
||||
✔️功夫熊猫「平先生面馆」云吞面地道
|
||||
⚠️景区内餐标偏高,建议自带水杯续水
|
||||
"""
|
||||
|
||||
async with async_playwright() as playwright:
|
||||
# 启动浏览器,添加剪贴板权限
|
||||
browser = await playwright.chromium.launch(headless=False) # 设置为False以便观察
|
||||
context = await browser.new_context(permissions=['clipboard-read', 'clipboard-write'])
|
||||
page = await context.new_page()
|
||||
|
||||
# 创建一个简单的HTML页面
|
||||
await page.set_content('''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>输入测试对比</title>
|
||||
<style>
|
||||
body { padding: 20px; font-family: Arial, sans-serif; }
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.input-box {
|
||||
flex: 1;
|
||||
}
|
||||
.textarea {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
margin-top: 10px;
|
||||
}
|
||||
h2 { margin-bottom: 5px; }
|
||||
.description {
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>正文输入测试</h2>
|
||||
<div class="container">
|
||||
<div class="input-box">
|
||||
<h3>优化版输入</h3>
|
||||
<div class="description">使用jieba分词的智能输入</div>
|
||||
<textarea id="enhanced-area" class="textarea" placeholder="优化版输入区域..."></textarea>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<h3>小红书版输入</h3>
|
||||
<div class="description">模拟小红书的输入逻辑</div>
|
||||
<textarea id="xhs-area" class="textarea" placeholder="小红书版输入区域..."></textarea>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<h3>复制粘贴版输入</h3>
|
||||
<div class="description">模拟用户复制粘贴行为</div>
|
||||
<textarea id="paste-area" class="textarea" placeholder="复制粘贴版输入区域..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
''')
|
||||
|
||||
# 创建输入模拟器实例
|
||||
enhanced_typer = EnhancedHumanTypingSimulator(page)
|
||||
paste_typer = PasteTypingSimulator(page)
|
||||
|
||||
# 执行正文输入测试
|
||||
print("\n=== 开始正文输入测试 ===")
|
||||
print("1. 开始复制粘贴版输入测试...")
|
||||
# 找到目标输入框并聚焦
|
||||
text_area = await page.wait_for_selector("#paste-area")
|
||||
await text_area.click()
|
||||
|
||||
# 使用 keyboard API 直接模拟输入
|
||||
# 先全选当前内容(如果有的话)
|
||||
await page.keyboard.press("Control+A")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
|
||||
# 输入文本
|
||||
await page.keyboard.type(test_text)
|
||||
print("复制粘贴版输入完成!")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("\n2. 开始优化版输入测试...")
|
||||
await enhanced_typer.type_text(test_text, "#enhanced-area")
|
||||
print("优化版输入完成!")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("\n3. 开始小红书版输入测试...")
|
||||
await xhs_type_text(page, test_text, "#xhs-area")
|
||||
print("小红书版输入完成!")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 关闭浏览器
|
||||
await browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_typing())
|
||||
142
utils/paste_typing.py
Normal file
142
utils/paste_typing.py
Normal file
@ -0,0 +1,142 @@
|
||||
import random
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
class PasteTypingSimulator:
|
||||
"""模拟用户复制粘贴行为的输入模拟器"""
|
||||
def __init__(self, page=None):
|
||||
self.page = page
|
||||
self.config = {
|
||||
'pre_paste_delay': (0.5, 1.2), # 粘贴前的停顿时间
|
||||
'post_paste_delay': (0.8, 1.5), # 粘贴后的停顿时间
|
||||
'review_probability': 0.7, # 检查内容的概率
|
||||
'review_time': (1.5, 3.0), # 检查内容的时间
|
||||
'adjust_probability': 0.4, # 调整格式的概率
|
||||
'adjust_delay': (0.3, 0.8), # 调整时的停顿
|
||||
'scroll_probability': 0.6, # 滚动查看的概率
|
||||
'scroll_delay': (0.5, 1.0), # 滚动时的停顿
|
||||
}
|
||||
|
||||
async def paste_text(self, text: str, selector: str = None) -> bool:
|
||||
"""模拟用户粘贴文本的行为"""
|
||||
try:
|
||||
if selector:
|
||||
# 找到目标输入框并聚焦
|
||||
element = await self.page.wait_for_selector(selector)
|
||||
await element.click()
|
||||
await asyncio.sleep(random.uniform(0.2, 0.4))
|
||||
|
||||
# 全选当前内容(如果有的话)
|
||||
await self.page.keyboard.press("Control+A")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
|
||||
# 模拟快速输入(类似粘贴的效果)
|
||||
await self.page.keyboard.type(text, delay=10) # 使用很小的延迟来模拟粘贴的快速输入
|
||||
|
||||
# 模拟粘贴后的检查动作
|
||||
await self._post_paste_actions()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"粘贴文本时出错: {e}")
|
||||
return False
|
||||
|
||||
async def _prepare_input(self, selector: str):
|
||||
"""准备输入区域"""
|
||||
try:
|
||||
# 等待元素出现并点击
|
||||
element = await self.page.wait_for_selector(selector, timeout=5000)
|
||||
await element.click()
|
||||
|
||||
# 模拟点击后的短暂停顿
|
||||
await asyncio.sleep(random.uniform(0.3, 0.6))
|
||||
|
||||
# 清空现有内容
|
||||
await self.page.keyboard.press("Control+A")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
await self.page.keyboard.press("Delete")
|
||||
await asyncio.sleep(random.uniform(0.2, 0.4))
|
||||
|
||||
except Exception as e:
|
||||
print(f"准备输入区域失败: {e}")
|
||||
raise
|
||||
|
||||
async def _pre_paste_actions(self):
|
||||
"""模拟粘贴前的准备动作"""
|
||||
# 模拟思考和准备时间
|
||||
await asyncio.sleep(random.uniform(*self.config['pre_paste_delay']))
|
||||
|
||||
# 模拟按下 Ctrl 键
|
||||
await self.page.keyboard.down("Control")
|
||||
await asyncio.sleep(random.uniform(0.05, 0.1))
|
||||
|
||||
# 模拟按下 V 键
|
||||
await self.page.keyboard.press("v")
|
||||
await asyncio.sleep(random.uniform(0.05, 0.1))
|
||||
|
||||
# 释放 Ctrl 键
|
||||
await self.page.keyboard.up("Control")
|
||||
|
||||
async def _perform_paste(self):
|
||||
"""执行粘贴操作"""
|
||||
# 等待内容出现
|
||||
await asyncio.sleep(random.uniform(0.3, 0.5))
|
||||
|
||||
async def _post_paste_actions(self):
|
||||
"""模拟粘贴后的检查和调整动作"""
|
||||
# 模拟粘贴后的停顿
|
||||
await asyncio.sleep(random.uniform(*self.config['post_paste_delay']))
|
||||
|
||||
# 随机检查内容
|
||||
if random.random() < self.config['review_probability']:
|
||||
# 模拟上下滚动查看内容
|
||||
if random.random() < self.config['scroll_probability']:
|
||||
# 向下滚动
|
||||
await self.page.keyboard.press("PageDown")
|
||||
await asyncio.sleep(random.uniform(*self.config['scroll_delay']))
|
||||
# 向上滚动
|
||||
await self.page.keyboard.press("PageUp")
|
||||
await asyncio.sleep(random.uniform(*self.config['scroll_delay']))
|
||||
|
||||
# 模拟检查时间
|
||||
await asyncio.sleep(random.uniform(*self.config['review_time']))
|
||||
|
||||
# 随机调整格式
|
||||
if random.random() < self.config['adjust_probability']:
|
||||
# 模拟删除多余空行
|
||||
for _ in range(random.randint(1, 2)):
|
||||
await self.page.keyboard.press("End")
|
||||
await asyncio.sleep(random.uniform(0.1, 0.2))
|
||||
await self.page.keyboard.press("Backspace")
|
||||
await asyncio.sleep(random.uniform(*self.config['adjust_delay']))
|
||||
|
||||
async def paste_with_format_check(self, text: str, selector: str = None) -> bool:
|
||||
"""带格式检查的粘贴方法"""
|
||||
try:
|
||||
# 模拟复制文本到剪贴板
|
||||
await self.page.evaluate(f'navigator.clipboard.writeText(`{text}`)')
|
||||
await asyncio.sleep(random.uniform(*self.config['pre_paste_delay']))
|
||||
|
||||
if selector:
|
||||
await self._prepare_input(selector)
|
||||
|
||||
# 模拟粘贴操作
|
||||
await self.page.keyboard.down("Control")
|
||||
await asyncio.sleep(random.uniform(0.05, 0.1))
|
||||
await self.page.keyboard.press("v")
|
||||
await asyncio.sleep(random.uniform(0.05, 0.1))
|
||||
await self.page.keyboard.up("Control")
|
||||
|
||||
# 模拟粘贴后的检查
|
||||
await asyncio.sleep(random.uniform(*self.config['post_paste_delay']))
|
||||
|
||||
# 随机检查内容
|
||||
if random.random() < self.config['review_probability']:
|
||||
await asyncio.sleep(random.uniform(*self.config['review_time']))
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"格式检查粘贴失败: {e}")
|
||||
return False
|
||||
Loading…
x
Reference in New Issue
Block a user