Selenium作死总结
说明: 这个笔记很多是个人总结, 当然也有些内容是先搜索后复制, 修改, 总结而来的.
个人感受
折腾了selenium这么久, ‘所见即所得’, 是我最大的体会了!
- 呈现在网页的内容, 你都能通过selenium找到.
- 你当前看到的, 就是你当前仅能操作的
- 网页源代码page_source实时更新
- 不可对不在网页上的元素进行操作
- 框架frame是个坑
- page_source仅是当前框架的源代码
- 在某些网站, 由于程序速度快于浏览器速度, 可能你成功切入了一个框架, 但该框架却没有显示出来, 于是你后面的操作都出错了!
- 浏览器需要不确定的时间去执行你的命令
- 可以考虑根据页面内容及当前url判断页面有没有发生改变
- 涉及id的定位方式都存在不稳定性, 可以考虑切换为link_text
- send_keys()方法可能会出现内容发送不完整的情况
常见问题
01. 浏览网页登录, 登录框
02. Screenshot: available via screen
- 无法找到元素
- 使用phantomjs时, 未设置窗口大小, 导致元素不可见: 设置下窗口大小
03. Element is not clickable at point(x, y). Other element would receive the click
- 无法点击元素, 否则将点击到别的元素
- 元素被遮挡: 想法弄走遮盖元素, 或暂停一会让其自动消失
- 元素未出现在窗口内: 下拉滚动条, 使元素出现
- 元素未获得焦点: 使其获得焦点
04. No such Frame 或 Unable to locate element
- 没有此框架 或 无法找到元素
- 框架/元素未加载: 显式/隐式等待, 添加暂停
- 元素在框架内: 切换到框架
- 元素的定位不正确(动态id或class): 更改定位方法
- 由于未知原因, 无法定位: 更换定位方法, xpath或css selector
补充: 从浏览器直接copy出来的xpath路径, 以前能用, 现在却不能用, 换为css却行了!
初步怀疑是路径的问题, ‘/html/body/div/section/section[4]/div[2]/ul/li[4]’, 由于对xpath的了解不够多, 所以尚未从根源上解决! - 动态路径: 根据网页内容, 动态更改路径
05. element is not attached to the page
- 元素不在当前页面
- 页面的刷新使元素对象发生改变: 重新定位元素
- 元素归属于旧页面(另外一个url)的: 无解
06. send_keys报错
- 浏览器不兼容
- 降低浏览器版本
- 接受体元素不对
- 找到对应的接收体元素
06. Compound class names not permitted
- 无法定位复合类(class=”tile div”)
- 取其中独特的类名, 或使用其它定位方法
07. page_source可见不可得
- 框架原因(page_source仅是显示当前框架的实时内容)
- 驱动与浏览器版本不符合, 浏览器偷偷升级了
- 更新为合适的驱动
常用函数
01. 获取cookies
1 | cookie = driver.get_cookies() |
02. 获取网页源代码
- driver.page_source
注意, 网页源代码是实时更新的
03. 获取当前网址
- driver.current_url
注意, 网页网址是实时更新的
04. frame框架切换
切换到id为child_frame的框架: driver.switchTo().frame(“child_frame”)
切换回默认框架: driver.switchTo().defaultContent()
框架的切换是一层一层, 由外到里的
切进内框架后, 必须在切回外框架后, 才能对外框架的元素进行操作
传入id、name、index以及selenium的WebElement对象来切换框架
传入index时, 0指的是第一个子框架, 不是根框架!
由于不可知原因, 对子框架进行操作时, 有时得多次切换回到默认框架, 再切进子框架, 然后才能对子框架进行操作
05. 获取标签属性
- tag.get_attribute(attributename)
a.get_attribute(‘href’)
延时, 显/隐式等待
01. time.sleep()
- 延时, 固定等待时长
02. Implicit Waits(隐式等待)(修改自: 简书 半个王国)
隐式等待是在尝试发现某个元素的时候,如果没能立刻发现,就==等待固定长度的时间==(默认为0秒),等待完成后, 成功发现元素或抛出异常。一旦设置了隐式等待时间,它的作用范围就是Webdriver对象实例的整个生命周期。
- 若无法成功找到元素, 就会等待固定时长后再去寻找
- 默认0秒, 即: 找不到元素后, 没有等待时长, 于是不再寻找该元素, 直接抛出异常
- 整个生命周期, 设置一次, 再程序结束前都有效
隐式等待有时不好用, 程序执行很快, 但是浏览器, 网络很慢, 可能造成每个操作都要等待固定时长
driver.implicitly_wait(seconds)
03. Explicit Waits(显式等待)(修改自: 简书 半个王国)
对于特定元素, 指定某个条件,然后设置最长等待时间。在这个时间内不断尝试寻找元素,找不到便会抛出异常。只有该条件触发,才执行后续代码。
- 特定元素, 针对不是所有元素
- 某个条件, 对于不同元素有不同的等待条件
1
WebDriverWait(driver=driver, timeout=300, poll_frequency=0.5, ignored_exceptions=None).until(EC.xx((By.xx, 'xx')))
driver:浏览器驱动
timeout:最长超时等待时间(s)
poll_frequency:检测的时间间隔,默认为500ms
ignore_exception:超时后抛出的异常信息,默认情况下抛 NoSuchElementException 异常1
2
3
4
5
6
7
8
9
- until() 或者 until_not()
```python
until(method, message='')
调用该方法体提供的回调函数作为一个参数,直到返回值为True
until_not(method, message='')
调用该方法体提供的回调函数作为一个参数,直到返回值为FalseWebDriverWait(driver, timeout).until(EC.xx((By.xx, “xx”)))
| EC | 预期条件 |
| —- | ——– |
| title_is | 判断当前页面的title是否等于预期 |
| title_contains | 判断当前页面的title是否包含预期字符串 |
| presence_of_element_located | 判断某个元素是否被加到了dom树里,并不代表该元素一定可见 |
| visibility_of_element_located | 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0 |
| visibility_of | 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了 |
| presence_of_all_elements_located | 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是’column-md-3’,那么只要有1个元素存在,这个方法就返回True |
| text_to_be_present_in_element | 判断某个元素中的text是否包含了预期的字符串 |
| text_to_be_present_in_element_value | 判断某个元素中的value属性是否包含了预期的字符串 |
| frame_to_be_available_and_switch_to_it | 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False |
| invisibility_of_element_located | 判断某个元素中是否不存在于dom树或不可见 |
| element_to_be_clickable - it is Displayed and Enabled | 判断某个元素中是否可见并且是enable的,这样的话才叫clickable |
| staleness_of | 等某个元素从dom树中移除,注意,这个方法也是返回True或False |
| element_to_be_selected | 判断某个元素是否被选中了,一般用在下拉列表 |
| element_located_to_be_selected | 判断某个元素是否被选中了,一般用在下拉列表 |
| element_selection_state_to_be | 判断某个元素的选中状态是否符合预期 |
| element_located_selection_state_to_be | 跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator |
| alert_is_present | 判断页面上是否存在alert |
- By: 定位方式
实际使用中, 发现显/隐式等待, 对Python环境自带的IDE, 支持不好; 用pycharm执行不会报错, 用自带的就遇到了很多问题.
常用js操作
01. js 下拉滚动条
移动到元素element对象的“顶端”与当前窗口的“顶部”对齐
driver.execute_script("arguments[0].scrollIntoView();", element);
driver.execute_script("arguments[0].scrollIntoView(true);", element);
移动到元素element对象的“底端”与当前窗口的“底部”对齐
driver.execute_script("arguments[0].scrollIntoView(false);", element);
移动到页面最底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)");
移动到指定的坐标(相对当前的坐标移动)
driver.execute_script("window.scrollBy(0, 700)");
结合上面的scrollBy语句,相当于移动到700+800=1600像素位置driver.execute_script("window.scrollBy(0, 800)");
移动到窗口绝对位置坐标,如下移动到纵坐标1600像素位置
driver.execute_script("window.scrollTo(0, 1600)");
结合上面的scrollTo语句,仍然移动到纵坐标1200像素位置
driver.execute_script(“window.scrollTo(0, 1200)”);`移动到指定元素(根据css选择器定位)
`driver.execute_script(‘’’$(‘html,body’).animate({scrollTop:$(css选择器位置).offset().top}, 800);’’’)
02. js 构造表单实现提交
1 | function post(URL, PARAMS) { |
03. js 其它操作
- 关闭当前窗口
window.close();