selenium行为链

问题的引出

Selenium 做模拟滑块的时候能感觉到明显的卡顿

查找原因

这个博文中有个测试,我自己写了下确实是这样,但是他的解决方式我不能接受,直接修改源代码的话机器多了根本不行的.

然后在这个issues上看到了作者的相关回答,可以在行为链的时候赋值一个参数做到这样,然后在去看ActionChains的定义的话确实有这可以这样初始化.

1
2
3
4
5
6
7
8
9
10
11
12
13
class ActionChains:

def __init__(self, driver, duration=250):
"""
Creates a new ActionChains.

:Args:
- driver: The WebDriver instance which performs user actions.
- duration: override the default 250 msecs of DEFAULT_MOVE_DURATION in PointerInput
"""
self._driver = driver
self._actions = []
self.w3c_actions = ActionBuilder(driver, duration=duration)

那思路就明确可以不用修改源文件直接在初始化的时候传参数就可以了

代码示例

action_chains 动作可以不附加在元素上执行 而且不会报错,这里我就打开百度跑下看看效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait


class Search:
def __init__(self):
option = webdriver.ChromeOptions()
option.add_argument('--disable-dev-shm-usage')
option.add_argument('--disable-gpu')
option.add_argument('--incognito') # 隐身模式
option.add_argument('--no-sandbox') # root用户不加这条会无法运行
option.add_argument('headless') # root用户不加这条会无法运行
option.binary_location = r'/Applications/Chrome.app/Contents/MacOS/Google Chrome' # mac 下的谷歌路径
# option.add_argument(f'--proxy-server=https://{proxy}')
option.add_argument(
'User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36')
option.add_experimental_option('excludeSwitches', ['enable-automation'])

service = Service(DRIVER_PATH)
self.driver = webdriver.Chrome(service=service, options=option)
self.wait = WebDriverWait(self.driver, 10)
self.action_chains = ActionChains(self.driver, duration=1)
self.url = "https://www.baidu.com"

def __del__(self):
self.driver.close()

def main(self)
self.driver.get(self.url)
self.driver.set_window_size(1907, 1035)

start_time = time.time()
for i in range(1, 21):
self.action_chains.move_by_offset(xoffset=0, yoffset=0).perform()
now_time = time.time()
hs = round((now_time - start_time), 3)
start_time = now_time
print(f'{i} ,{hs}')


if __name__ == '__main__':
s = Search()
s.main()
del s

结果的话确实比之前的间隔短

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1 ,0.046
2 ,0.037
3 ,0.077
4 ,0.007
5 ,0.019
6 ,0.015
7 ,0.017
8 ,0.017
9 ,0.017
10 ,0.016
11 ,0.018
12 ,0.015
13 ,0.017
14 ,0.018
15 ,0.015
16 ,0.016
17 ,0.019
18 ,0.017
19 ,0.015
20 ,0.017

这个库的作者也贴了一段代码,大致思路就是把move_by_offset 通过更多的step 来让滑块更精细

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from selenium.webdriver.common.action_chains import ActionChains


class EnhancedActionChains(ActionChains):
def smooth_move_by_offset(self, dx, dy, n_step=50):
def get_displacements():
step_x = dx / n_step
step_y = dy / n_step
for i in range(n_step):
yield (
round((i + 1) * step_x) - round(i * step_x),
round((i + 1) * step_y) - round(i * step_y),
)

# pylint: disable=protected-access
self.w3c_actions.pointer_action._duration = 0
for ddx, ddy in get_displacements():
self.w3c_actions.pointer_action.move_by(ddx, ddy)

return self

selenium行为链
https://kingjem.github.io/2022/05/29/selenium行为链初始化-解决卡顿的问题/
作者
Ruhai
发布于
2022年5月29日
许可协议