演示 Selenium 最经典的 拖拽操作,从 A 元素拖到 B 元素,或从一个位置拖到另一个坐标。拖拽是 ActionChains 中最常见的组合操作。
两种拖拽方式:
drag_and_drop(source, target) → 元素到元素,自动计算目标中心,最常用drag_and_drop_by_offset(el, dx, dy) → 元素到偏移坐标,滑块/进度条场景用click_and_hold(el).move_to_element(t).release().perform() → 手动分解,灵活度最高但代码最长⚠️ 兼容性问题:原生 HTML5 拖拽(draggable="true")和 jQuery UI 拖拽的事件模型不同。Selenium 的 drag_and_drop 对 jQuery UI 效果更好,对某些 React 拖拽库可能需要手动组合。
drag_and_drop(A, B):起点 = 元素 A 中心,终点 = 元素 B 中心(一行式)drag_and_drop_by_offset(A, dx, dy):起点 = A 中心,终点 = A 中心 + 偏移(滑块验证最爱)click_and_hold + move_by_offset + release:起点 = A 中心,终点 = 当前鼠标 + 偏移(分步式)drag_and_drop_with_offset(A, B, dx, dy):起点 = A 中心,终点 = B 中心 + 偏移(Selenium 4.4+)贝塞尔曲线分步:起点 = A 中心,轨迹 = 多次微偏移 + 抖动(模拟真人行为)
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains # 1. 启动浏览器 + 打开演示页面 driver = webdriver.Chrome() driver.get("https://autotest-505.pages.dev/mouse_op_tech_sections/mouse_drag_tech.html") # 2. 定位元素 src = driver.find_element(By.ID, "drag1") tgt = driver.find_element(By.ID, "dropBox") slider = driver.find_element(By.ID, "slider") # ── ① drag_and_drop:元素 A → 元素 B(一行式,80% 场景) ── ActionChains(driver).drag_and_drop(src, tgt).perform() # ── ② drag_and_drop_by_offset:元素 → 相对偏移(滑块验证最爱) ── # 把滑块元素从当前位置向右拖 300px、向下 0px ActionChains(driver).drag_and_drop_by_offset(slider, xoffset=300, yoffset=0).perform() # ── ③ 分步式:click_and_hold → move_by_offset → release ── # 更灵活,可中途变速、多次移动、配合键盘 ActionChains(driver) \ .click_and_hold(src) \ .move_by_offset(150, 30) \ .move_by_offset(80, -20) \ .release() \ .perform() # ── ④ drag_and_drop_with_offset:Selenium 4.4+ ── # 拖到目标元素中心再向右偏移 50px(精确落位) ActionChains(driver) \ .drag_and_drop_with_offset(src, tgt, xoffset=50, yoffset=0) \ .perform() # ── ⑤ 贝塞尔曲线分步:模拟真人行为 ── import random, math def bezier_drag(driver, src, dx, dy, steps=30): actions = ActionChains(driver) actions.click_and_hold(src) for i in range(steps): t = i / steps # 二次贝塞尔,带随机抖动 step_dx = dx/steps + random.uniform(-2, 2) step_dy = dy/steps + random.uniform(-1, 1) actions.move_by_offset(step_dx, step_dy) actions.release().perform() bezier_drag(driver, slider, dx=300, dy=0) # ── 方法对比速查 ── # 方法 起点锚点 终点锚点 # drag_and_drop(A, B) A 中心 B 中心 ★★★★★ # drag_and_drop_by_offset(A,dx,dy) A 中心 A 中心+偏移 ★★★★☆ 滑块验证 # click_and_hold + move_by_offset A 中心 当前鼠标+偏移 ★★★★☆ 分步灵活 # drag_and_drop_with_offset A 中心 B 中心+偏移 ★★☆☆☆ 4.4+ # 贝塞尔曲线分步 A 中心 多点偏移轨迹 ★★★☆☆ 反爬 # 3. 关闭浏览器 driver.quit()