测试老宅男扶摇

导航

Selenium4Web自动化7-文件上传和日期控件

一、文件上传操作-input标签文件选择

当input元素为文件类型时, 文件上传对话框可以使用Selenium处理. 文件上传的代码实现如下

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.implicitly_wait(10)
driver.get("https://the-internet.herokuapp.com/upload");
driver.find_element(By.ID,"file-upload").send_keys("selenium-snapshot.jpg")
driver.find_element(By.ID,"file-submit").submit()
if(driver.page_source.find("File Uploaded!")):
    print("file upload success")
else:
    print("file upload not successful")
driver.quit()

二、文件上传操作-非input标签文件选择

当上传文件按钮不是input标签时,比如下图的前端框架layui(一个JS框架)上传按钮就是button标签,selenium无法处理文件上传。

那么对于那些不是input框实现的上传怎么办,这种上传千奇百怪,有用a标签的,有用div的,有用button的,有用object的,我们没有办法通过直接在网页上处理掉这些上传,唯一的办法就是打开windows的系统弹框,去处理弹框。
解决办法很简单,用OS层面的操作去处理。这里经过多种库的调用,找到一个适用性最好,学习起来最简单的库PyAutoGui来解决上传问题。
当然网上还有很多方法,有兴趣的可以去看看,这里贴一下链接,对比下来就会知道PyAutoGui才是更简单易用以及实用的解决方案。
Selenium+Python上传文件方法:
https://www.jianshu.com/p/fba37cc5d5e2

1. PyAutoGui入门

官方文档链接:
https://pyautogui.readthedocs.io/en/latest/

PyAutoGUI 让您的 Python 脚本控制鼠标和键盘以自动与其他应用程序交互。API 的设计很简单。PyAutoGUI 适用于 Windows、macOS 和 Linux,并在 Python 2 和 3 上运行。

要使用 pip 安装:pip install pyautogui

PyAutoGUI 有如下几块功能:
移动鼠标并单击其他应用程序的窗口。
向应用程序发送击键(例如,填写表格)。
截取屏幕截图,并给出一个图像(例如,一个按钮或复选框),然后在屏幕上找到它。
找到应用程序的窗口,然后移动、调整大小、最大化、最小化或关闭它(目前仅限 Windows)。
显示警报和消息框。

1.1 入门代码案例

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pyautogui
from time import sleep

# Get the size of the primary monitor.
# 获取主监视器的大小
# screenWidth, screenHeight = pyautogui.size()
# print(screenWidth, screenHeight)
#
# # Get the XY position of the mouse.
# # 获得鼠标的XY坐标(演示的是扩展屏,所以X坐标>1920了)
# currentMouseX, currentMouseY = pyautogui.position()
# print(currentMouseX, currentMouseY)
#
# # Move the mouse to XY coordinates.
# # 移动鼠标到指定的坐标
# pyautogui.moveTo(3800, 613)
#
# # Click the mouse.
# # 点击鼠标
# pyautogui.click()
#
# # Move the mouse to XY coordinates and click it.
# # 移动鼠标到坐标然后点击
# pyautogui.click(3800, 513)
#
# # Find where button.png appears on the screen and click it.
# # 找到桌面上名为button.png的图片并点击
# # 代码测试会报错:TypeError: cannot unpack non-iterable NoneType object
# # pyautogui.Click('button.png')
#
# # Move the mouse 400 pixels to the right of its current position.
# # 从当前位置右移鼠标400PX
# pyautogui.move(400, 0)
#
# # Double click the mouse.
# # 双击鼠标
# pyautogui.doubleClick()
#
# # Use tweening/easing function to move mouse over 2 seconds.
# # 使用渐变/缓动功能移动鼠标,间隔2秒。
# # 坐标是目标坐标,从当前位置移动过去,2秒停顿一下(方便看移动过程)
# pyautogui.moveTo(500, 500, duration=2, tween=pyautogui.easeInOutQuad)

# type with quarter-second pause in between each key
# 输入文本,每次按键间隔0.25秒
# 案例:新建txt文档演示
# pyautogui.write('Hello world!', interval=0.25)

# Press the Esc key. All key names are in pyautogui.KEY_NAMES
# 案例:选中代码然后取消
# pyautogui.press('esc')
# pyautogui.KEY_NAMES

# Press the Shift key down and hold it.
# 按下Shift键不放
# with pyautogui.hold('shift'):
#         # Press the left arrow key 4 times.
#         # 按左键4次
#         pyautogui.press(['left', 'left', 'left', 'left'])  # Press the left arrow key 4 times.
# Shift键会自动释放
# Shift key is released automatically.

# Press the Ctrl-C hotkey combination.
# 按Ctrl-C组合键
# pyautogui.hotkey('ctrl', 'c')

# Make an alert box appear and pause the program until OK is clicked.
# 生成一个弹窗并暂停程序,直到点击Ok按钮
# pyautogui.alert('This is the message to display.')

1.2 例子,在画图中以方形螺旋拖动鼠标

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pyautogui
from time import sleep

sleep(5)

distance = 200
while distance > 0:
        pyautogui.drag(distance, 0, duration=0.5)   # 右移
        distance -= 5
        pyautogui.drag(0, distance, duration=0.5)   # 下移
        pyautogui.drag(-distance, 0, duration=0.5)  # 左移
        distance -= 5
        pyautogui.drag(0, -distance, duration=0.5)  # 上移

1.3 应用PyAutoGui实现文件上传

通过直接操控鼠标键盘,是很容易实现文件上传的,只要能快速获得坐标即可,下面的代码可以实时获取鼠标的坐标

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import time
import pyautogui as pag
try:
    while True:
        print("Press Ctrl-C to end")
        screenWidth, screenHeight = pag.size()  #获取屏幕的尺寸
        print(screenWidth,screenHeight)
        x,y = pag.position()   #获取当前鼠标的位置
        # Python rjust() 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串。
        # 如果指定的长度小于字符串的长度则返回原字符串。
        posStr = "Position:" + str(x).rjust(4)+','+str(y).rjust(4)
        print(posStr)
        time.sleep(0.2)
        os.system('cls')   #清除屏幕
except KeyboardInterrupt:
    print('end....')

如下图,运行代码后,不要停,控制台会实时输出鼠标所在位置的坐标,类似于页面元素定位了,只是这里换成了坐标。

有了坐标,就可控制鼠标和键盘在屏幕中的指定位置进行文件上传操作了。

三、日期控件

1 可输入日期控件

一般的日期控件是可以直接输入日期的,如果使用webdriver 去设置日期,

  1. 定位到该日期控件
  2. 使用sendKeys 方法
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from time import sleep
from selenium.webdriver.support import expected_conditions as ec

driver = webdriver.Chrome()
wait = WebDriverWait(driver,10)

driver.get("https://layuion.com/demo/laydate.html")


# 移动窗口
driver.set_window_position(1900,-200)
driver.set_window_size(1550,1000)

# 定位到日期控件,并输入
locator = (By.XPATH,'//input[@id="test1"]')
wait.until(ec.visibility_of_element_located(locator)).send_keys("2022-09-30")

2 readonly日期控件

有的日期控件是readonly的
比如:

<input class="form-control getTime ng-touched valid ng-valid-parse ng-valid ng-valid-required ng-pristine" type="text" required="" name="establish_time" ng-model="addStationInfo.establish_time" ng-readonly="true" readonly="readonly"/>

这个时候,没法调用WebElement的sendKeys()
方法1:可以使用JS remove readonly attribute,然后sendKeys

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

"""
<input class="form-control getTime ng-touched valid ng-valid-parse ng-valid ng-valid-required ng-pristine" 
type="text" required="" name="establish_time" ng-model="addStationInfo.establish_time" ng-readonly="true" 
readonly="readonly"/>
"""
js = 'document.getElementByName("establish_time").removeAttribute("readonly")'
driver.execute_script(js)

# 在sendKeys之前应该清空原来的默认值
driver.find_element(By.NAME,"establish_time").clear()
driver.find_element(By.NAME,"establish_time").send_keys("2033-08-03")

如果输入完日期,并无法触发查询动作,可以点击日期输入框,调出日历控件,点击“确认”按钮,即可触发

方法2:使用js方法,输入日期,直接改掉输入框元素的值即可

#去掉元素的readonly属性
js = 'document.getElementByName("establish_time").removeAttribute("readonly");'
driver.execute_script(js)
 
#使用js方法输入日期
js_value = 'document.getElementByName("establish_time").value = "2020-05-28"'
driver.execute_script(js_value)

目前很少有使用readonly的日期控件了,没有相应的案例。

3 日期控件在frame里

操作思路:
1、切换到iframe;
2、完成相关操作;
3、返回主文档

iframes=browser.find_elements_by_css_selector('iframe')
browser.switch_to.frame(iframes[0])
ny=browser.find_element_by_xpath('//*[@id="ny"]')
ny.click()
time.sleep(1)
ny.send_keys('202106')
time.sleep(1)
#从frame中切回主文档
browser.switch_to.default_content() 

4 非readonly,也无法直接输入的日期控件

这种,基本只能靠鼠标点击和鼠标滚动日期控件来完成了。会存在一些看不到的元素,就要用到最新学到的Selenium4的滚轮

如上图,最下面的23时和59分、59秒,都是不可见的,需要滚动到下面

# 修改分钟,改成59
locater = (By.XPATH,"//p[contains(text(),'分')]/../ol/li[60]")
# 基于元素,按给点数值滚动
min = driver.find_element(By.XPATH, "//p[contains(text(),'分')]/../ol")
# 定义滚动起始元素
scroll_origin = ScrollOrigin.from_element(min)
min59 = driver.find_element(*locater)
# 按住不动,滚动指定数值成功
ActionChains(driver) \
    .scroll_to_element(min)\
    .click_and_hold(min)\
    .scroll_from_origin(scroll_origin,0,1800) \
    .release(min)\
    .move_to_element(min59)\
    .click()\
    .perform()

如果ActionChains不能解决问题,还可以考虑使用PyAutoGui,用坐标进行定位并点击。

posted on 2022-10-24 15:21  测试老宅男扶摇  阅读(351)  评论(0编辑  收藏  举报