前言:接了人生中第一个python单子,用selenium自动化,是一个比较时新的网站,用了大量的js渲染,费了很大的力气,但我也终于发现了——任何人能够进行的浏览器操作都可以用selenium实现。
在非select类下拉框这里遇到了两种需求,一种是可输入字符,一种是不可输入字符
这种下拉框允许输入字符,沟通后确定输入字符如出现多个选项则点选第一个
思路:用
send_keys
输入字符后会激活下拉框进行智能提示,然后用ActionChains
模拟鼠标点击
brand = driver.find_element_by_css_selector('#rc_select_0')
brand.send_keys(lst[1])
time.sleep(0.5)
ActionChains(driver).move_to_element(brand).move_by_offset(0,30).click().perform()
#ActionChains(driver).move_to_element(brand).move_by_offset(0,30).context_click().perform()
#这里用鼠标先定位到输入框,再往下移一段距离,这里因为不知道移动的距离,所以先用点击左键context_click来观察
需求:按照指定的内容选择相应的选项
思路:点击一下激活下拉框,因为无法用Select
模块,所以要先获取全部的选项,然后遍历匹配目标内容,匹配上了则点击相应的元素
从图片中可以看到这个下拉框是一个变动的,周围没有其他的选项,activedecendant
属性会跟随鼠标的选择变化,观察看到aria-owns
来自另一个地方,定位后如下图:
可以看到定位后出现的也是一个变化的元素,而在它不远处就是所有的选项,是一对div
标签,于是用find_elements
获取所有的选项进行匹配,然后再点击该元素即可
driver.find_element_by_xpath("//input[starts-with(@id,'ifDangerous_productList_0')]/../..").click()
#点击下拉框激活,如果不激活的话选项元素会被隐藏无法定位
lst_dangerous = driver.find_elements_by_xpath("//div[starts-with(@id,'ifDangerous_productList_0')]/../div[2]/div[1]/div[1]/div[1]/div")
#获取选项,形成一个列表
for dangerous in lst_dangerous:
if lst[12]==dangerous.get_attribute('title'): #遍历匹配
driver.execute_script('arguments[0].click()',dangerous)
找了半天也没有找到能获取全部选项的地方,好在这个下拉框允许输入,通过输入再模拟鼠标点击解决了,不知道有没有更好的办法
在这个网页中很多元素都是动态id,因此无法直接用id定位
如上图,后一半是动态生成的,但前一半是固定的,可以通过xpath
表达式进行定位
driver.find_element_by_xpath("//标签名[starts-with(@属性名, 'xxx')]")
#以xxx开头的属性的标签
driver.find_element_by_xpath("//标签名[ends-with(@属性名, 'xxx')]")
#以xxx结尾的属性的标签
driver.find_element_by_xpath("//标签名[contains(@属性名, 'xxx')]")
#包含xxx的属性的标签
本身无唯一属性,也可以通过xpath
、css_selector
的绝对位置来定位,可是网站上有很多隐藏的元素,在特定的时候会出现,所以会导致绝对位置变化,如果要实现每次定位都能成功,应该尽可能使用相对位置。
思路:先定位到周围有唯一属性的元素,再通过该元素定位到目标元素
driver.find_element_by_xpath("//div[@id='xxx']/A")
#由id为xxx的父元素定位到子元素A
driver.find_element_by_xpath("//div[@id='xxx']/..")
#由id为xxx的子元素定位到其父元素
driver.find_element_by_xpath("//div[@id='xxx']/../A")
#由id为xxx的子元素定位到其同级元素A(先定位到父元素)
lst_dangerous = driver.find_elements_by_xpath("//div[starts-with(@id,'ifDangerous_productList_0')]/../div[2]/div[1]/div[1]/div[1]/div")
如前面所说的下拉框,就是通过id=ifDangerous_productList_0_…这个元素,定位到父元素,在逐步定位到目标元素
有时实行点击时,会被遮挡或不在范围内,可以采用执行JS
ele=driver.find_element_by_xpath("//input[starts-with(@id,'chemicaltype_productList_0')]/../..").
driver.execute_script('arguments[0].click()',ele)
input上传文件只要用send_keys
输入路径即可,非input会触发windows控件,但是selenium无法操控windows,于是要使用pywinauto
库
#点击上传按钮,触发窗口
upload1 = driver.find_element_by_xpath("//div[text()='MSDS文件:']//../div[2]/span[1]/div[1]/span[1]/button[1]")
driver.execute_script('arguments[0].click()',upload1)
#通过窗口打开
app = pywinauto.Desktop()
#通过弹窗名称进入控件
win = app['文件上传']
#输入路径
win['Edit'].type_keys(path + '\\' + file)
#点击打开按钮
win['Button'].click()
需要提醒的两点是:
通过弹窗名称进入控件时要注意不同浏览器的名称不一样,如火狐浏览器是“上传文件”,谷歌浏览器是“打开”
不能使用360安全卫士,否则会报错