改进动作链定位准确性

This commit is contained in:
g1879 2023-01-09 18:50:45 +08:00
parent cf3959ddab
commit 1994261b00
3 changed files with 106 additions and 20 deletions

View File

@ -30,7 +30,9 @@ class ActionChains:
:param offset_y: 偏移量y :param offset_y: 偏移量y
:return: self :return: self
""" """
is_loc = False
if isinstance(ele_or_loc, (tuple, list)): if isinstance(ele_or_loc, (tuple, list)):
is_loc = True
lx = ele_or_loc[0] + offset_x lx = ele_or_loc[0] + offset_x
ly = ele_or_loc[1] + offset_y ly = ele_or_loc[1] + offset_y
elif isinstance(ele_or_loc, str) or 'ChromiumElement' in str(type(ele_or_loc)): elif isinstance(ele_or_loc, str) or 'ChromiumElement' in str(type(ele_or_loc)):
@ -42,9 +44,19 @@ class ActionChains:
raise TypeError('ele_or_loc参数只能接受坐标(x, y)或ChromiumElement对象。') raise TypeError('ele_or_loc参数只能接受坐标(x, y)或ChromiumElement对象。')
if not _location_in_viewport(self.page, lx, ly): if not _location_in_viewport(self.page, lx, ly):
self.page.scroll.to_location(lx, ly) # 把元素滚动到页面中间
clientWidth = self.page.run_js('return document.body.clientWidth;')
clientHeight = self.page.run_js('return document.body.clientHeight;')
self.page.scroll.to_location(lx - clientWidth // 2, ly - clientHeight // 2)
# # 这样设计为了应付那些不随滚动条滚动的元素
if is_loc:
cx, cy = location_to_client(self.page, lx, ly)
else:
x, y = ele_or_loc.client_location if offset_x or offset_y else ele_or_loc.client_midpoint
cx = x + offset_x
cy = y + offset_y
cx, cy = location_to_client(self.page, lx, ly)
self._dr.Input.dispatchMouseEvent(type='mouseMoved', x=cx, y=cy, modifiers=self.modifier) self._dr.Input.dispatchMouseEvent(type='mouseMoved', x=cx, y=cy, modifiers=self.modifier)
self.curr_x = cx self.curr_x = cx
self.curr_y = cy self.curr_y = cy
@ -266,4 +278,4 @@ def location_to_client(page, lx, ly):
"""绝对坐标转换为视口坐标""" """绝对坐标转换为视口坐标"""
scroll_x = page.run_js('return document.documentElement.scrollLeft;') scroll_x = page.run_js('return document.documentElement.scrollLeft;')
scroll_y = page.run_js('return document.documentElement.scrollTop;') scroll_y = page.run_js('return document.documentElement.scrollTop;')
return lx + scroll_x, ly + scroll_y return lx - scroll_x, ly - scroll_y

View File

@ -1,17 +1,46 @@
参考 selenium 的`ActionChains`,本库也提供了自己的`ActionChains`。语法更简洁易用,每个动作执行即生效,无须`perform()` 参考 selenium 的`ActionChains`,本库也提供了自己的`ActionChains`
动作链可以完成一系列交互行为,如鼠标移动、鼠标点击、键盘输入等。
语法比 selenium 更简洁易用,每个动作执行即生效,无须`perform()`
多个动作可以用链式模式操作:
```python
ac.move_to(ele).click().type('some text')
```
也可以多个操作分开执行:
```python
ac.move_to(ele)
ac.click()
ac.type('some text')
```
这两种方式效果是一样的,每个动作总会依次执行。
# ✔ 创建对象 # ✔ 创建对象
## 📍 导入
```python
from DrissionPage import ActionChains
```
## 📍 `ActionChains` ## 📍 `ActionChains`
创建动作链对象非常简单,只要把`WebPage`对象或`ChromiumPage`对象传入即可。动作链只在这个页面上生效。 创建动作链对象非常简单,只要把`WebPage`对象或`ChromiumPage`对象传入即可。动作链只在这个页面上生效。
**参数:** **参数:**
- `page``WebPage`对象或`ChromiumPage`对象 | 名称 | 数据类型 | 说明 |
| ------ | ---------------------------- | ------------ |
| `page` | `WebPage`对象或`ChromiumPage`对象 | 动作链要操作的浏览器页面 |
**示例:**
```python ```python
# 创建前先导入
from DrissionPage import WebPage, ActionChains from DrissionPage import WebPage, ActionChains
page = WebPage() page = WebPage()
@ -26,13 +55,19 @@ ac = ActionChains(page)
**参数:** **参数:**
- `ele_or_loc`:元素对象、文本定位符或绝对坐标,坐标为`tuple`(int, int) 形式 | 名称 | 数据类型 | 说明 |
| ------------ | ----------------------------------------- | --------------------------------------- |
| `ele_or_loc` | `ChrmoiumElement``str``Tuple[int, int]` | 元素对象、文本定位符或绝对坐标,坐标为`tuple`(int, int) 形式 |
| `offset_x` | `int` | 偏移量 x |
| `offset_y` | `int` | 偏移量 y |
- `offset_x`:偏移量 x **返回:**
- `offset_y`:偏移量 y | 数据类型 | 说明 |
| -------------- | ------- |
| `ActionChains` | 动作链对象本身 |
**返回:**`ActionChains`对象自己 **示例:**
```python ```python
ele = page('tag:a') ele = page('tag:a')
@ -45,14 +80,23 @@ ac.move_to(ele_or_loc=ele) # 使鼠标移动过到 ele 元素上
**参数:** **参数:**
- `offset_x`:偏移量 x | 名称 | 数据类型 | 说明 |
| ---------- | ----- | ----- |
| `offset_x` | `int` | 偏移量 x |
| `offset_y` | `int` | 偏移量 y |
- `offset_y`:偏移量 y **返回:**
**返回:**`ActionChains`对象自己 | 数据类型 | 说明 |
| -------------- | ------- |
| `ActionChains` | 动作链对象本身 |
**示例:**
鼠标向右移动 300 像素
```python ```python
ac.move(300, 0) # 鼠标向右移动 300 像素 ac.move(300, 0)
``` ```
## 📍 `up()` ## 📍 `up()`
@ -259,16 +303,46 @@ ac.key_down(Keys.CTRL) # 按下 ctrl 键
ac.wait(3) # 停顿 3 秒 ac.wait(3) # 停顿 3 秒
``` ```
# ✔ 链式操作 # ✔ 示例
以上操作皆能实现链式操作。且最后无需`perform()` ## 📍 模拟输入 ctrl+a
```python ```python
from DrissionPage import ChromiumPage, ActionChains from DrissionPage import ChromiumPage, ActionChains
from DrissionPage.keys import Keys
# 创建页面
page = ChromiumPage() page = ChromiumPage()
ac = ActionCHains(page) # 创建动作链对象
ac = ActionChains(page)
# 链式操作 # 鼠标移动到<input>元素上
ac.move_to('tag:h1').right(30).click().key_down('a').key_up('a') ac.move_to('tag:input')
# 点击鼠标,使光标落到元素中
ac.click()
# 按下 ctrl 键
ac.key_down(Keys.CTRL)
# 输入 a
ac.type('a')
# 提起 ctrl 键
ac.key_up(Keys.CTRL)
```
## 📍 拖拽元素
```python
from DrissionPage import ChromiumPage, ActionChains
from DrissionPage.keys import Keys
# 创建页面
page = ChromiumPage()
# 创建动作链对象
ac = ActionChains(page)
# 左键按住元素
ac.hold('#div1')
# 向右移动鼠标300像素
ac.right(300)
# 释放左键
ac.release()
``` ```

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup( setup(
name="DrissionPage", name="DrissionPage",
version="3.0.31", version="3.0.32",
author="g1879", author="g1879",
author_email="g1879@qq.com", author_email="g1879@qq.com",
description="A module that integrates selenium and requests session, encapsulates common page operations.", description="A module that integrates selenium and requests session, encapsulates common page operations.",