前言

前几周做了个使用Selenium的项目,踩了好多好多好多的Selenium的坑,越来越感觉他作为一个第三方库,对于Chrome的操作实在是有局限。另外,推荐大家一个Selenium之外的操作浏览器的选择:puppeteer(https://github.com/GoogleChrome/puppeteer),是来自谷歌的库。它解决了很多在Selenium里很难解决的问题,比如手机页面截全屏。

好了,收回来,Selenium很多难解决的问题,我们要首先想到从JS脚本出发,毕竟Selenium还是支持驱动浏览器运行JS脚本的。

这篇文章的内容主要是Selenium日常开发中会遇到的坑,以Java代码为主,当然Python的小伙伴不用担心,这里所有的解决方案都是可以在Python中通用的。

Selenium

主要参考

Selenium使用总结(Java版本):

https://juejin.im/post/6844903737744424973

Selenium准备

chromedriver各版本镜像:

https://npm.taobao.org/mirrors/chromedriver/

chromedriver版本与chrome客户端对应支持关系:

https://npm.taobao.org/mirrors/chromedriver/2.46/notes.txt

最新版本截图:

----------ChromeDriver v2.46 (2019-02-01)----------
Supports Chrome v71-73
Resolved issue 2728: Is Element Displayed command does not work correctly with v0 shadow DOM inserts [[Pri-1]]
Resolved issue 755: /session/:sessionId/doubleclick only generates one set of mousedown/mouseup/click events [[Pri-2]]
Resolved issue 2744: Execute Script returns wrong error code when JavaScript returns a cyclic data structure [[Pri-2]]
Resolved issue 1529: OnResponse behavior can lead to port exhaustion [[Pri-2]]
Resolved issue 2736: Close Window command should handle user prompts based on session capabilities [[Pri-2]]
Resolved issue 1963: Sending keys to disabled element should throw Element Not interactable error [[Pri-2]]
Resolved issue 2679: Timeout value handling is not spec compliant [[Pri-2]]
Resolved issue 2002: Add Cookie is not spec compliant [[Pri-2]]
Resolved issue 2749: Update Switch To Frame error checks to match latest W3C spec [[Pri-3]]
Resolved issue 2716: Clearing Text Boxes [[Pri-3]]
Resolved issue 2714: ConnectException: Failed to connect to localhost/0:0:0:0:0:0:0:1:15756. Could not start driver. [[Pri-3]]
Resolved issue 2722: Execute Script does not correctly convert document.all into JSON format [[Pri-3]]
Resolved issue 2681: ChromeDriver doesn't differentiate "no such element" and "stale element reference" [[Pri-3]] ----------ChromeDriver v2.45 (2018-12-10)----------
Supports Chrome v70-72
Resolved issue 1997: New Session is not spec compliant [[Pri-1]]
Resolved issue 2685: Should Assert that the chrome version is compatible [[Pri-2]]
Resolved issue 2677: Find Element command returns wrong error code when an invalid locator is used [[Pri-2]]
Resolved issue 2676: Some ChromeDriver status codes are wrong [[Pri-2]]
Resolved issue 2665: compile error in JS inside of WebViewImpl::DispatchTouchEventsForMouseEvents [[Pri-2]]
Resolved issue 2658: Window size commands should handle user prompts [[Pri-2]]
Resolved issue 2684: ChromeDriver doesn't start Chrome correctly with options.addArguments("user-data-dir=") [[Pri-3]]
Resolved issue 2688: Status command is not spec compliant [[Pri-3]]
Resolved issue 2654: Add support for strictFileInteractability [[Pri-]]

Selenium 滚动至元素

滚动至元素参考:

https://blog.csdn.net/sinat_28734889/article/details/77933401

实现代码片段:

// 获取元素
WebElement element = webDriver.findElement(By.cssSelector(elementsCss)); // 获取元素左上坐标值
Point elementPoint = element.getLocation();
int documentScrollTop = elementPoint.getY(); // 将页面根据元素滚动至合适位置
jsExecutor.executeScript("window.scrollTo(0," + documentScrollTop + ")");

Selenium等待:显示,隐式

参考:

https://huilansame.github.io/huilansame.github.io/archivers/sleep-implicitlywait-wait

强制等待

sleep(3)  # 强制等待3秒再执行下一步

隐性等待

隐形等待是设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后执行下一步。注意这里有一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下你看到浏览器标签栏那个小圈不再转,才会执行下一步。

# -*- coding: utf-8 -*-
from selenium import webdriver driver = webdriver.Firefox()
driver.implicitly_wait(30) # 隐性等待,最长等30秒
driver.get('https://huilansame.github.io') print driver.current_url
driver.quit()

需要特别说明的是:隐性等待对整个driver的周期都起作用,所以只要设置一次即可,我曾看到有人把隐性等待当成了sleep在用,走哪儿都来一下…

显性等待

显性等待,WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By driver = webdriver.Firefox()
driver.implicitly_wait(10) # 隐性等待和显性等待可以同时用,但要注意:等待的最长时间取两者之中的大者
driver.get('https://huilansame.github.io')
locator = (By.LINK_TEXT, 'CSDN') try:
WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator))
print driver.find_element_by_link_text('CSDN').get_attribute('href')
finally:
driver.close()

Selenium定位元素后偏差

这是一个奇怪的问题,之所以会出现这个坐标偏差是因为windows系统下电脑设置的显示缩放比例造成的,location获取的坐标是按显示100%时得到的坐标,而截图所使用的坐标却是需要根据显示缩放比例缩放后对应的图片所确定的,因此就出现了偏差。

解决这个问题有三种方法:

1.修改电脑显示设置为100%。这是最简单的方法

2.缩放截取到的页面图片,即将截图的size缩放为宽和高都除以缩放比例后的大小;

3.修改Image.crop的参数,将参数元组的四个值都乘以缩放比例。

Selenium加载Flash

看服务报告pc端截图重构内ChromeUtil.java如何使用

问题答案里提供了很多解决思路:

https://stackoverflow.com/questions/52185371/allow-flash-content-in-chrome-69-running-via-chromedriver

网上方案:

prefs.put("profile.default_content_setting_values.plugins", 1);
prefs.put("profile.content_settings.plugin_whitelist.adobe-flash-player", 1);
prefs.put("profile.content_settings.exceptions.plugins.*,*.per_resource.adobe-flash-player", 1);

经测试Chrome65+无法使用,无效。

方法一

基本思路:通过Selenium自动访问chrome单个网页的设置页,操作元素,始终允许加载flash。

让Selenium自动选择下面的按钮

这个操作的Demo代码:

package util;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.Select; import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class ChromeUtil { /**
* 格式化url进入该url设置页
* @param url
* @return
*/
private static String _base_url(String url){
if (url.isEmpty()){
return url;
} try {
URL urls = new URL(url);
return String.format("%s://%s",urls.getProtocol(),urls.getHost());
}catch (Exception e){
return url;
}
} /**
* 元素选择
* @param driver
* @param element
* @return
*/
private static WebElement _shadow_root(WebDriver driver, WebElement element){
return (WebElement)((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot", element);
} /**
* 允许网页的flash运行,chrome67版本可行,75版本提示升级flash
* @param driver
* @param url
*/
public static void allow_flash(WebDriver driver, String url) {
url = _base_url(url);
driver.get(String.format("chrome://settings/content/siteDetails?site=%s",url));
WebElement webele_settings = _shadow_root(driver,(((ChromeDriver)driver).findElementByTagName("settings-ui")));
WebElement webele_container = webele_settings.findElement(By.id("container"));
WebElement webele_main = _shadow_root(driver,webele_container.findElement(By.id("main")));
WebElement showing_subpage = _shadow_root(driver,webele_main.findElement(By.className("showing-subpage")));
WebElement advancedPage = showing_subpage.findElement(By.id("advancedPage"));
WebElement settings_privacy_page = _shadow_root(driver,advancedPage.findElement(By.tagName("settings-privacy-page")));
WebElement pages = settings_privacy_page.findElement(By.id("pages"));
WebElement settings_subpage = pages.findElement(By.tagName("settings-subpage"));
WebElement site_details = _shadow_root(driver,settings_subpage.findElement(By.tagName("site-details")));
WebElement plugins = _shadow_root(driver,site_details.findElement(By.id("plugins")));
WebElement permission = plugins.findElement(By.id("permission"));
Select sel = new Select(permission);
sel.selectByValue("allow");
} /**
* @param args
*/
public static void main(String[] args) { System.setProperty("webdriver.chrome.driver", Constants.PATH_Dict.DRIVER_PATH.getValue());
WebDriver webDriver = null;
try {
// 初始化webDriver
ChromeOptions options = new ChromeOptions();
// options.addArguments("--headless"); // 无头模式
// options.addArguments("--no-sandbox"); // Linux关闭沙盒模式
// options.addArguments("--disable-gpu"); // 禁用显卡
webDriver = new ChromeDriver(options);
webDriver.manage().window().setSize(new Dimension(1300, 800));
String url = "https://shanghai.fang.anjuke.com/"; // 获取重定向后网址再打开Flash权限
webDriver.get(url);
allow_flash(webDriver,webDriver.getCurrentUrl());
webDriver.get(url);
Thread.sleep(1 * 60 * 1000); } catch(Exception e) {
e.printStackTrace();
} finally {
if(webDriver != null) {
webDriver.quit();
}
}
}
}

方法二

在chrome设置里将所有网站加入flash白名单,但实测selenium会打开新的chrome,不读取通用设置,类似无痕窗口,有空再试试。

总结

  • 全局flash加载的设置按钮在selenium不起作用
  • 使用pref加载也没有用

禁止javascript

禁止运行javascript还是可以通过pref的:

HashMap<String, Object> chromePrefs = new HashMap<>(2);
chromePrefs.put("profile.managed_default_content_settings.javascript", 2);
options.setExperimentalOption("prefs", chromePrefs);

Selenium调整网页缩放大小

运行js

document.body.style.zoom='0.5'

关注我

我目前是一名后端开发工程师。主要关注后端开发,数据安全,网络爬虫,物联网,边缘计算等方向。

微信:yangzd1102

Github:@qqxx6661

个人博客:

原创博客主要内容

  • Java知识点复习全手册
  • Leetcode算法题解析
  • 剑指offer算法题解析
  • SpringCloud菜鸟入门实战系列
  • SpringBoot菜鸟入门实战系列
  • Python爬虫相关技术文章
  • 后端开发相关技术文章

个人公众号:后端技术漫谈

如果文章对你有帮助,不妨收藏起来并转发给您的朋友们~

Selenium使用总结:加载Flash、禁用JS、滚动页面至元素、缩放页面的更多相关文章

  1. selenium chrome 自动加载flash

    #coding:utf-8from selenium import webdriverfrom selenium.webdriver.support.select import Selectfrom ...

  2. 使用 JS 嵌入的方式来加载 Flash 插件,在各浏览器中播放视频

    嵌入插件 使用 object 和 embed 标签 这种方法用到的是 Object 和 Embed 标签,可以看到 object 的很多参数和 embed 里面的很多属性是重复的.浏览器兼容性,有的浏 ...

  3. HTML加载FLASH(*.swf文件)详解

    引言 在web项目中经常会遇到在线浏览word文档,通常解决方法将word转换成pdf,然后在线浏览,但是在实际实现过程中,由于阅读器的原因,用户可以直接下载该pdf,这显然不是我们想要的,通过网络搜 ...

  4. 最新版Google Chrome 自动加载flash插件的方法

    我们在用Selenium做自动化测试时,有时候需要浏览器自动加载flash插件,69以前的谷歌浏览器,可以通过加载属性的方法自动运行flash插件,如下: prefs={ "profile. ...

  5. cef加载flash的办法

    cef有2种加载flash插件的方式, 1,npapi,这种方式是调用系统自带的flash插件,由于有安全性方面的问题,已经被新版cef禁用. 2,ppapi,也就是 pepper flash,这是谷 ...

  6. JQuery 加载 CSS、JS 文件

    JS 方式加载 CSS.JS 文件: //加载 css 文件 function includeCss(filename) { var head = document.getElementsByTagN ...

  7. CI模板加载css和js

    1.需求 ci无法加载css和js文件. 2.解决 删除..htaccess文件. 在config目录下配置base_url,并传给页面 $base_url = $this->config-&g ...

  8. 如何在HTML中加载Flash(2种实现方法)_HTML/Xhtml_网页制作

    点评:如何在HTML中加载Flash,为网页添加更多的色彩,普通的网页以无法满足用户的需求,接下来为大家介绍下2种在HTML中加载Flash的方法,感兴趣的各位可以适当参考下,希望对你有所帮助 第一种 ...

  9. yii2 如何在页面底部加载css和js

    作者:白狼 出处:www.manks.top/article/yii2_load_js_css_in_end 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接 ...

  10. ruby -- 进阶学习(十一)配置解决production环境下无法加载css或js

    最近配置production环境,找了好几份文档,从傻逼到苦逼~~终于配置成功~~@_@!!! 首先,先加载以下几个插件: # Use Uglifier as compressor for JavaS ...

随机推荐

  1. Scala 特质自身类型

    1 package chapter06 2 3 object Test16_TraitSelfType { 4 def main(args: Array[String]): Unit = { 5 va ...

  2. #Multi-SG#BZOJ 2940 [POI2000] 条纹

    题目 有\(n\)个格子,可以选择三种长度的线段覆盖,不能重叠, 无法覆盖者为负,问先手是否必胜,\(n\leq 10^3\) 分析 考虑选择一个位置覆盖则该局面分成两个局面, 直接求出SG函数不为0 ...

  3. AI云增强升级!还原生动人像,拍出质感照片

    近期不少细心用户发现,在用HUAWEI Mate 60 Pro手机拍照后,使用相册中的AI云增强功能,照片变得更加细腻有质感.这是因为AI云增强升级并更新支持了人像模式拍摄的照片,高清自然的人像细节还 ...

  4. openGauss中的sequence跟Oracle的sequence有什么区别?

    openGauss 中的 sequence 跟 Oracle 的 sequence 有什么区别? openGauss 中也提供了 sequence 序列功能,使用 Oracle 的用户应该都非常喜欢使 ...

  5. 《深入理解Java虚拟机》读书笔记:内存分配策略

    Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象的内存.关于回收内存这一点,我们已经使用了大量篇幅去介绍虚拟机中的垃圾收集器体系以及运作原理 ...

  6. BZOJ 4403序列统计

    假设存在一个满足条件的长度为i的不下降序列(显然是一定存在的)那么只需要从中选出i个数即可 (不必在意选出具体数的大小,可以把满足条件的序列写下来,选几个数感受一下). 但是$n \choose m ...

  7. Apollo+ES源码改造,构建民生银行的ELK日志平台配置管理中心【转载】

    Apollo+ES源码改造,构建民生银行的ELK日志平台配置管理中心 原创 高效开发运维 架构头条 2019-02-28 作者 | 中国民生银行大数据基础平台运维组团队 编辑 | 张婵 随着 IT 业 ...

  8. CentOS 6.5编译安装httpd-2.4.7

    CentOS 6.5编译安装httpd-2.4.7 CentOS 编译安装 Apache 2.4 准备: [root@NFSServer ~]# yum groupinstall "Deve ...

  9. 简单写一个eventbus

    前言 闲暇之余,简单写一个eventbus. 正文 什么是eventbus? eventbus 是一个开源的发布订阅模式的框架,用于简化程序间不同组件的通信. 它允许不同组件间松耦合通信,组件之间不通 ...

  10. 重新点亮shell————特殊符号[五]

    前言 简单整理一下特殊符号. 正文 特殊符号大全: 引号 ' 完成引用 "" 不完全引用 ` 执行命令 括号 () (()) $() 圆括号 单独使用圆括号会产生一个子shell ...