【python】Selenium中鼠标&键盘&js操作

本文详细介绍了Selenium中如何进行鼠标操作,包括ActionChains的基本原理、常用方法及其应用示例。接着讲解了键盘操作,利用Keys库实现不同按键的模拟,并给出了错误展示。最后探讨了JS脚本的运用,解释了Python如何通过WebDriver执行JS代码,以及在实际操作中如何修改只读属性的优化技巧。

一.鼠标操作

主要使用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 = '\ue031'  # function  keys
    F2 = '\ue032'
    F3 = '\ue033'
    F4 = '\ue034'
    F5 = '\ue035'
    F6 = '\ue036'
    F7 = '\ue037'
    F8 = '\ue038'
    F9 = '\ue039'
    F10 = '\ue03a'
    F11 = '\ue03b'
    F12 = '\ue03c'

    META = '\ue03d'
    COMMAND = '\ue03d'

可以看出借助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代码来修改这个属性。

<input type="text" class="input" value="2018-07-21" id="train_date" readonly="">

这里可以发送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中可能查找会有多个参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值