Selenium - 鼠标事件
前言
在WebDriver
中,关于鼠标相关操作的方法都封装在ActionChains
类中。
来看看ActionChains
类都提供了哪些鼠标操作的方法:
Method | Description |
---|---|
click(on_element=None) | 鼠标左键单击 |
click_and_hold(on_element=None) | 鼠标左键单击,但不松开 |
context_click(on_element=None) | 鼠标右键单击 |
double_click(on_element=None) | 鼠标左键双击 |
drag_and_drop(source, target) | 鼠标左键单击不松开,移动到指定元素后松开(即拖拽 ) |
drag_and_drop_by_offset(source, xoffset, yoffset) | 鼠标左键单击不松开,移动到指定坐标后松开 |
move_by_offset(xoffset, yoffset) | 鼠标移动到某个坐标 |
move_to_element(to_element) | 鼠标移动到某个元素 |
move_to_element_with_offset(to_element, xoffset, yoffset) | 鼠标移动到距离某个元素的某个距离 |
pause(seconds) | 暂停输入 |
release(on_element=None) | 在某个元素松开鼠标左键 |
send_keys(*keys_to_send) | 在当前元素中输入值 |
send_keys_to_element(element, *keys_to_send) | 给某个元素输入值 |
perform() | 相应存储的动作 |
reset_actions() | 清除所有已存储的动作 |
左键:click
之前已经在用鼠标左键单击了,那就是click
。这里再来学习使用ActionChains
类中调用click
。
通过访问路飞学城的轻课页面,并点击播放。
import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains # 获取webdriver实例 browser = webdriver.Chrome() # 访问URL browser.get('https://www.luffycity.com/home') # 获取轻课标签并点击它 time.sleep(1) span3 = browser.find_element_by_class_name('span3') # 通过分析类名发现,span3只有一个 ActionChains(browser).move_to_element(span3).click().perform() # 点击视频播放按钮 time.sleep(4) button = browser.find_element_by_xpath('//*[@id="router-view"]/div/div[2]/button') ActionChains(browser).move_to_element(button).click().perform() # # 关闭浏览器 time.sleep(20) # 可以适当调整该值 browser.quit() # 截止2019-6-5,代码无误
效果如下:
右键:content_click
再来个鼠标右键的示例,这次打开的是多玩LOL天赋模拟器。
有以下几点需要注意:
- 如果反复打开这个网页,并且上一次有操作天赋模拟器,这一次会自动记录之前添加的点数。
- 第一次点击某个技能(巫术),第一次点击会加5点,然后右键一次减一点,这时你要左键想加回来就是加1点了。要注意第一次加5点的操作。
示例代码如下:
import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains # 获取webdriver实例 browser = webdriver.Chrome() # 访问URL browser.get('http://lol.duowan.com/s/talent.html#duowan') # 反复打开页面,有时候天赋点数会被记录,所以要先重置 time.sleep(2) browser.find_element_by_xpath('//*[@id="reset-tallent"]').click() # 获取巫术标签并点击它增加技能点 time.sleep(1) wu = browser.find_element_by_xpath('//*[@id="calculator"]/div[2]/div[1]') # 获取巫术标签的xpath wu.click() # 点击巫术增加技能点 # 右键减少技能点 time.sleep(2) ActionChains(browser).move_to_element(wu).context_click().perform() time.sleep(1) ActionChains(browser).move_to_element(wu).context_click().perform() # 鼠标左键在加回来 time.sleep(1) wu.click() # 点击重置天赋按钮 time.sleep(2) reset = browser.find_element_by_xpath('//*[@id="reset-tallent"]') ActionChains(browser).move_to_element(reset).click().perform() # # 关闭浏览器 time.sleep(3) browser.quit() # 截止2019-6-5,代码无误
效果如下:
拖动:drag_and_drag
所谓的拖动,也就是鼠标左键点击标签不松开,直到拖动到指定标签后再松开。
来个玩个游戏。
示例代码如下:
import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains # 获取webdriver实例 browser = webdriver.Chrome() # 访问URL browser.get('http://www.jq22.com/demo/pintu20151229/') # 点击开始按钮,开始游戏 time.sleep(1) start = browser.find_element_by_id('start') ActionChains(browser).move_to_element(start).click().perform() # 准备拖动,首先要找到开始和结束的两个标签 time.sleep(2) img1 = browser.find_element_by_xpath('//*[@id="container"]/div[18]') # 选中开始标签 img2 = browser.find_element_by_xpath('//*[@id="container"]/div[18]') # 结束标签 ActionChains(browser).move_to_element(img1).drag_and_drop(img1, img2).perform() # 关闭浏览器 time.sleep(3) browser.quit() # 截止2019-6-5,代码无误
效果如下:
滑动验证
# -*- coding: utf-8 -*- # __author__ = "maple" # import time # from selenium import webdriver # driver = webdriver.Chrome() # driver.implicitly_wait(10) import time import random import getpass from PIL import Image # 处理图片 from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait # 等待页面加载某些元素 from selenium.webdriver.support import expected_conditions as EC full_snap = 'full_snap.png' portion_snap = 'portion_snap.png' def get_img(xpath, img_path): """ 处理图片 """ # 拿到带缺口的图片(整个网页),使用wait等照片加载完毕才能获取 _canvas = wait.until(EC.presence_of_element_located((By.XPATH, xpath))) # 拍个快照,这个是整个网页的快照,没有这个快照,往下就无从谈起 driver.save_screenshot(img_path) # 从带缺口的图片中获取像素点 left = _canvas.location.get('x') top = _canvas.location.get('y') right = left + _canvas.size['width'] bottom = top + _canvas.size['height'] # 从网页快照中截取出我们想要的带缺口的照片 img_file_obj = Image.open(img_path) # 从完整的图片中,截取带缺口的部分照片并保存 img_file = img_file_obj.crop((left, top, right, bottom)) # 裁剪,别忘了是元组类型 # img_file.show() # 展示裁剪后的图片 img_file.save(img_path) # 保存裁剪后的图片 return img_file # def get_distance(portion_img, full_img): # """ 对比上一步中获取的两张图片,获取位移并返回 """ # for x in range(60, full_img.size[0]): # 循环x轴,理解为行 # for y in range(20, full_img.size[1] - 20): # 循环y轴,理解为列 # # print(x, y) # rgb_portion = portion_img.getpixel((x, y)) # rgb_full = full_img.getpixel((x, y)) # if not (abs(rgb_portion[0] - rgb_full[0] < 60) and abs(rgb_portion[1] - rgb_full[1] < 60) and abs( # rgb_portion[2] - rgb_full[2] < 60)): # return x - 8 # 这个不一样的像素点,就是我们想要的,在尝试多次后,该像素点减7后准确率会提高 def get_distance(image1, image2): p1 = image1.load() p2 = image2.load() x = 60 for i in range(x, image1.size[0]): for j in range(20, image1.size[1] - 20): print(i, j) dot1 = p1[i, j] dot2 = p2[i, j] r = abs(dot1[0] - dot2[0]) g = abs(dot1[1] - dot2[1]) b = abs(dot1[2] - dot2[2]) if not (r < 60 and g < 60 and b < 60): return i - 7 # return i return i # 当返回这个i的时候,意味着破解失败了,因为没有找到合适的位移点 def get_tracks(distance): """ 根据distance值,模拟出一段段的滑动轨迹,位移公式: s=V0t+(at^2)/2 """ track = [] current = 0 # 当前速度 0 mid = distance * 3 / 5 # 前3/5是匀加速运动,后2/5是匀减速 # t = random.randint(1, 3) / 10 # 0.2 或者 0.3 # t = 0.18456 t = 0.3 v = 0 # 初始速度 while current < distance: if current < mid: # 前半段,是匀加速 a = random.randint(2, 3) else: a = - random.randint(2, 3) v0 = v v = v0 + a * t move = v0 * t + 0.5 * a * (t ** 2) current += move track.append(round(move)) # 取整 return track def crack_luffy_signin(user, pwd): """ 破解路飞学城登录的极验验证 """ try: # 第1步:访问URL driver.get('https://account.cnblogs.com/signin?returnUrl=http%3a%2f%2fi.cnblogs.com%2f') # 第2步,获取用户名和密码标签并输入相应的值 time.sleep(1) driver.find_element_by_id('LoginName').send_keys(user) driver.find_element_by_id('Password').send_keys(pwd) driver.find_element_by_class_name('ladda-label').click() # 第4步,拿到缺口和完整图片,用于后续做对比 # 4.1 获取缺口图片 time.sleep(1) portion_img = get_img('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/div/canvas[1]', portion_snap) # 传递缺口图片标签的xpath和图片名称 # 4.2 获取完整的图片,但由于完整图片默认是隐藏的,我们无法截取,所以先让它显示出来 # 4.2.1 通过js脚本将隐藏标签显示出来 time.sleep(1) # 4.2.2 执行js脚本 js = "document.getElementsByClassName('geetest_canvas_fullbg geetest_fade geetest_absolute')[0].style.display='block'" driver.execute_script(js) # 4.3 获取完整图片截图 time.sleep(0.5) full_img = get_img('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]/canvas', full_snap) # 传递完整图片标签的xpath和图片名称 # 第5步,对比两张图的像素RGB,得到不一样的像素点,取位移 distance = get_distance(portion_img, full_img) # print(distance) # 97就是我们想要的位移,并且这个值是不固定的 # 第6步,获取移动轨迹 tracks_list = get_tracks(distance) # 第7步, 按照轨迹列表开始匀加速再匀减速运动,水平移动 # 7.1 获取滑动按钮 geetest_slider_button = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_slider_button'))) # 7.2 按住不放 ActionChains(driver).click_and_hold(geetest_slider_button).perform() print(1111, tracks_list) for track in tracks_list: print(22222222222,track) ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform() # 水平移动,所以x轴在变,y轴不变 # else: # 模拟人滑动到缺口位置之后再滑动一点再滑动回来 ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform() ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform() # 在滑到位置后,不是立即松开,而是在一段时间之后再松开 ActionChains(driver).pause(random.randint(6, 15) / 10).release(geetest_slider_button).perform() # 第8步,获取确定按钮并点击 # time.sleep(2) # driver.find_element_by_xpath('//*[@id="router-view"]/div/div/div[2]/div[2]/button').click() finally: # 关闭浏览器 time.sleep(3) driver.quit() if __name__ == '__main__': user = input('输入你的用户名: ').strip() # 替换为你的用户名 pwd = getpass.getpass('输入的密码: ').strip() # 替换为你的密码 # 获取webdriver实例 driver = webdriver.Chrome() wait = WebDriverWait(driver, 10) crack_luffy_signin(user, pwd) # try: # driver.get('https://account.cnblogs.com/signin?returnUrl=http%3a%2f%2fi.cnblogs.com%2f') # # driver.find_element_by_id('LoginName').send_keys('11111') # driver.find_element_by_id('Password').send_keys('22222') # driver.find_element_by_class_name('ladda-label').click() # # except Exception as e: # print(e) # finally: # time.sleep(20) # driver.quit()
效果:
下拉菜单选择
下拉菜单这里可以有三种方式选择:
- select_by_index(id),通过id选择。
- select_by_value(value值),通过value值选择。
- select_by_text(“中国”),通过显示的文本内容选择。
现在通过路飞学城的注册页面来演示下拉菜单的操作:
import time from selenium import webdriver from selenium.webdriver.support.ui import Select # 获取webdriver实例 browser = webdriver.Chrome() # 访问URL browser.get('https://www.luffycity.com/signup') # browser.maximize_window() # 窗口最大化 time.sleep(1) # 定位到select标签 select = browser.find_element_by_class_name('phone_select') Select(select).select_by_value('355') # 根据value值选择 # 关闭浏览器 time.sleep(3) browser.quit() # 截止2019-6-6,代码无误
效果如下:
模拟hover事件
hover也就是鼠标悬浮,那么使用selenium怎么实现呢?
通过一个悬浮事例来学习。
事例以淘宝官网为例,要求:
- 循环悬浮主题市场列表。
- 然后悬浮【女装/男装/内衣】,并点击其内的【夏上新】。
import time from selenium import webdriver from selenium.webdriver import ActionChains as AC driver = webdriver.Chrome() driver.get('https://www.taobao.com/') # 获取 主题市场 列表 menu_list = driver.find_elements_by_class_name('J_Cat') print(menu_list.__len__()) for i in menu_list: # 循环模拟鼠标悬浮 AC(driver).move_to_element(i).perform() time.sleep(0.5) # 悬浮到 女装/男装/内衣 time.sleep(2) AC(driver).move_to_element(menu_list[0]).perform() # 点击其内的 夏上新 链接 time.sleep(2) obj = driver.find_element_by_xpath('/html/body/div[4]/div[1]/div[1]/div[1]/div/div/div[1]/div[1]/div[1]/p/a[1]') print(obj.text) obj.click() time.sleep(6) driver.quit()