一.鼠标操作
主要使用selenium中的ActionChains类
AcitonChains基本原理
ActionChains的执行原理是,当调用ActionChain方法的时候不会立即执行,而是使用一个队列,当调用perform()方法的时候,队列中的时间会依次执行
来自源码,可以看到这里有个列表_action 用来临时存储需要执行的队列
from selenium.webdriver.common.action_chains import ActionChains
def __init__(self, driver):
"""
Creates a new ActionChains.
:Args:
- driver: The WebDriver instance which performs user actions.
"""
self._driver = driver
self._actions = []
if self._driver.w3c:
self.w3c_actions = ActionBuilder(driver)
然后返回的都是self,也就是链式调用。
ActionChains 常用方法列表
click()——单击鼠标左键
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None) ——双击鼠标左键
drag_and_drop(source, target) ——拖拽到某个元素然后松开
move_by_offset(xoffset, yoffset) ——鼠标从当前位置移动到某个坐标
move_to_element(to_element) ——鼠标移动到某个元素
perform() ——执行链中的所有动作
release(on_element=None) ——在某个元素位置松开鼠标左键
这里问题:为什么双击不可以用
ac.click().click()
因为:click()方法返回的数据都是None,不利于之后的操作与断言
使用展示
这里可以把鼠标的每一步操作都分开写
action = ActionChains(driver)
# 1.鼠标悬停
action.move_to_element()
# 2.点击动作
action.click()
# 3.右击
action.context_click()
# 4.perform结束
action.perform()
也可以放在一起写
ActionChains(driver).move_to_element(testa).click(testb).perform()
示例
from selenium.webdriver import Chrome,ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.remote.webelement import WebElement
driver = Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
def wait_find_element(locator):
wait = WebDriverWait(driver, timeout=30, poll_frequency=0.5)
input_ele = wait.until(EC.presence_of_element_located(locator))
return input_ele
def wait_clickable_element(locator):
wait = WebDriverWait(driver, timeout=30, poll_frequency=0.5)
input_ele = wait.until(EC.element_to_be_clickable(locator))
return input_ele
ac = ActionChains(driver)
ele = wait_clickable_element((By.XPATH, "//a[text()='设置' and contains(@href, 'http')]"))
gj = wait_find_element((By.XPATH, "//a[text()='高级搜索']"))
二.键盘操作
这里需要借助selenium的Keys库
from selenium.webdriver.common.keys import Keys
查看源码
class Keys(object):
F1 = '' # function keys
F2 = ''
F3 = ''
F4 = ''
F5 = ''
F6 = ''
F7 = ''
F8 = ''
F9 = ''
F10 = ''
F11 = ''
F12 = ''
META = ''
COMMAND = ''
可以看出借助Key库可以把按键转换成机械可以识别的语言。
举个例子
当我们想调用F1键的时候
element = driver.find_element_by_id("id")
element.send_keys("HELLO",Keys.F1,Keys.CANCEL)
复杂点的例子
import time
from selenium.webdriver import Chrome,ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.remote.webelement import WebElement
driver = Chrome()
driver.implicitly_wait(3)
driver.get("http://www.baidu.com")
def wait_find_element(locator):
wait = WebDriverWait(driver, timeout=30, poll_frequency=0.5)
input_ele = wait.until(EC.presence_of_element_located(locator))
return input_ele
def wait_clickable_element(locator):
wait = WebDriverWait(driver, timeout=30, poll_frequency=0.5)
input_ele = wait.until(EC.element_to_be_clickable(locator))
return input_ele
action = ActionChains(driver)
element = wait_clickable_element((By.XPATH ,"//a[text()='设置' and contains(@href, 'http')]"))
action.move_to_element(element).perform()
action.click(wait_find_element((By.XPATH, "//a[text()='高级搜索']"))).perform()
time.sleep(10)
错误展示
action = ActionChains(driver)
element = wait_clickable_element((By.XPATH ,"//a[text()='设置' and contains(@href, 'http')]"))
gj = wait_find_element((By.XPATH, "//a[text()='高级搜索']"))
ac.move_to_element(element).click(gj).perform()
这样子的话就无法找到高级搜索这个地方,因为涉及到函数调用顺序perform
三.JS 脚本
原理: Python-》WebDriver-》JS脚本-》浏览器
例如:find_element_by_id(id)->getElementByID(id)
还有一种方法就是:通过Python发送JS命令给
原理代码
def execute_script(self, script, *args):
"""
Synchronously Executes JavaScript in the current window/frame.
:Args:
- script: The JavaScript to execute.
- \*args: Any applicable arguments for your JavaScript.
:Usage:
driver.execute_script('return document.title;')
"""
converted_args = list(args)
command = None
if self.w3c:
command = Command.W3C_EXECUTE_SCRIPT
else:
command = Command.EXECUTE_SCRIPT
return self.execute(command, {
'script': script,
'args': converted_args})['value']
去掉readonly举例
在查找选择12306其中的出发日期的时候,可以通过以下代码获取
driver = Chrome()
driver.implicitly_wait(3)
driver.get('https://www.12306.cn/index/')
data_element = wait_find_element((By.ID,"train_date"))
print(data_element)
注意这里的readonly,这里标记着在该页面中这个是只读的,如果想要修改这个元素,但是python中没有对应的代码方法;我们可以选择通过python发送js代码来修改这个属性。
这里可以发送JS代码
data_element = wait_find_element((By.ID,"train_date"))
print(data_element)
js_code = "e = document.getElementById('train_date');"
ele = driver.execute_script(js_code)
print(ele)
time.sleep(2)
#修改属性
js_code1 = "e.readOnly = false;"
driver.execute_script(js_code1)
time.sleep(2)
#修改时间
js_code2 = "e.value = '2019-05-26'"
driver.execute_script(js_code2)
time.sleep(20)
这里查看页面可以看到最终日期被修改成功
注意:如果这个缺少time.sleep,JS执行代码时间不过,会导致发送多条指令,有些没有执行成功
优化
直接使用js自带的removeAttribute方法去除readonly属性
js_code = "document.getElementById('train_date').removeAttribute('readonly')"
driver.execute_script(js_code)
time.sleep(3)
js_code = "document.getElementById('train_date').value = '2019-05-26'"
driver.execute_script(js_code)
time.sleep(3)
也可以使用webdriver的元素定位
# 使用arguments充当占位符
data_element = wait_find_element((By.ID,"train_date"))
print(data_element)
js_code1 = "arguments[0].readOnly=false"
driver.execute_script(js_code1, data_element)
time.sleep(3)
js_code2 = "arguments[0].value = '2019-05-26'"
driver.execute_script(js_code2,data_element)
time.sleep(3)
这里使用arguments充当占位符,替换了arguments传递过去的第0个参数,因为使用例如xpath中可能查找会有多个参数