Selenium webdriver有没有Verify值的方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Selenium webdriver有没有Verify值的方法相关的知识,希望对你有一定的参考价值。
在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回的元素句柄来定位元素。其中By类的常用定位方式共八种,现分别介绍如下。1. By.name()
假设我们要测试的页面源码如下:
<button id="gbqfba" aria-label="Google Search" name="btnK" class="gbqfba"><span id="gbqfsa">Google Search</span></button>
当我们要用name属性来引用这个button并点击它时,代码如下:
View Code
2. By.id()
页面源码如下:
1 <button id="gbqfba" aria-label="Google Search" name="btnK" class="gbqfba"><span id="gbqfsa">Google Search</span></button>
要引用该button并点击它时,代码如下:
复制代码
1 public class SearchButtonById
2
3 public static void main(String[] args)
4
5 WebDriver driver = new FirefoxDriver();
6
7 driver.get("http://www.forexample.com");
8
9 WebElement searchBox = driver.findElement(By.id("gbqfba"));
10
11 searchBox.click();
12
13
14
15
复制代码
3. By.tagName()
该方法可以通过元素的标签名称来查找元素。该方法跟之前两个方法的区别是,这个方法搜索到的元素通常不止一个,所以一般建议结合使用findElements方法来使用。比如我们现在要查找页面上有多少个button,就可以用button这个tagName来进行查找,代码如下:
复制代码
public class SearchPageByTagName
public static void main(String[] args)
WebDriver driver = new FirefoxDriver();
driver.get("http://www.forexample.com");
List<WebElement> buttons = driver.findElements(By.tagName("button"));
System.out.println(buttons.size()); //打印出button的个数
复制代码
另外,在使用tagName方法进行定位时,还有一个地方需要注意的是,通常有些html元素的tagName是相同的,如下图(1)所示。
图(1)
从图中我们可以看到,单选框、复选框、文本框和密码框的元素标签都是input,此时单靠tagName无法准确地得到我们想要的元素,需要结合type属性才能过滤出我们要的元素。示例代码如下:
复制代码
1 public class SearchElementsByTagName
2
3 public static void main(String[] args)
4
5 WebDriver driver = new FirefoxDriver();
6
7 driver.get("http://www.forexample.com");
8
9 List<WebElement> allInputs = driver.findElements(By.tagName("input"));
10
11 //只打印所有文本框的值
12
13 for(WebElement e: allInputs)
14
15 if (e.getAttribute(“type”).equals(“text”))
16
17 System.out.println(e.getText().toString()); //打印出每个文本框里的值
18
19
20
21
22
23
24
25
复制代码
4. By.className()
className属性是利用元素的css样式表所引用的伪类名称来进行元素查找的方法。对于任何HTML页面的元素来说,一般程序员或页面设计师会给元素直接赋予一个样式属性或者利用css文件里的伪类来定义元素样式,使元素在页面上显示时能够更加美观。一般css样式表可能会长成下面这个样子:
复制代码
1 .buttonStyle
2
3 width: 50px;
4
5 height: 50px;
6
7 border-radius: 50%;
8
9 margin: 0% 2%;
10
11
复制代码
定义好后,就可以在页面元素中引用上述定义好的样式,如下:
1 <button name="sampleBtnName" id="sampleBtnId" class="buttonStyle">I\'m Button</button>
如果此时我们要通过className属性来查找该button并操作它的话,就可以使用className属性了,代码如下:
复制代码
1 public class SearchElementsByClassName
2
3 public static void main(String[] args)
4
5 WebDriver driver = new FirefoxDriver();
6
7 driver.get("http://www.forexample.com");
8
9 WebElement searchBox = driver.findElement(By.className("buttonStyle"));
10
11 searchBox.sendKeys("Hello, world");
12
13
14
15
复制代码
注意:使用className来进行元素定位时,有时会碰到一个元素指定了若干个class属性值的“复合样式”的情况,如下面这个button:<button id="J_sidebar_login" class="btn btn_big btn_submit" type="submit">登录</button>。这个button元素指定了三个不同的css伪类名作为它的样式属性值,此时就必须结合后面要介绍的cssSelector方法来定位了,稍后会有详细例子。
5. By.linkText()
这个方法比较直接,即通过超文本链接上的文字信息来定位元素,这种方式一般专门用于定位页面上的超文本链接。通常一个超文本链接会长成这个样子:
1 <a href="/intl/en/about.html">About Google</a>
我们定位这个元素时,可以使用下面的代码进行操作:
复制代码
1 public class SearchElementsByLinkText
2
3 public static void main(String[] args)
4
5 WebDriver driver = new FirefoxDriver();
6
7 driver.get("http://www.forexample.com");
8
9 WebElement aboutLink = driver.findElement(By.linkText("About Google"));
10
11 aboutLink.click();
12
13
14
15
复制代码
6. By.partialLinkText()
这个方法是上一个方法的扩展。当你不能准确知道超链接上的文本信息或者只想通过一些关键字进行匹配时,可以使用这个方法来通过部分链接文字进行匹配。代码如下:
复制代码
1 public class SearchElementsByPartialLinkText
2
3 public static void main(String[] args)
4
5 WebDriver driver = new FirefoxDriver();
6
7 driver.get("http://www.forexample.com");
8
9 WebElement aboutLink = driver.findElement(By.partialLinkText("About"));
10
11 aboutLink.click();
12
13
14
15
复制代码
注意:使用这种方法进行定位时,可能会引起的问题是,当你的页面中不止一个超链接包含About时,findElement方法只会返回第一个查找到的元素,而不会返回所有符合条件的元素。如果你要想获得所有符合条件的元素,还是只能使用findElements方法。
7. By.xpath()
这个方法是非常强大的元素查找方式,使用这种方法几乎可以定位到页面上的任意元素。在正式开始使用XPath进行定位前,我们先了解下什么是XPath。XPath是XML Path的简称,由于HTML文档本身就是一个标准的XML页面,所以我们可以使用XPath的语法来定位页面元素。
假设我们现在以图(2)所示HTML代码为例,要引用对应的对象,XPath语法如下:
图(2)
绝对路径写法(只有一种),写法如下:
引用页面上的form元素(即源码中的第3行):/html/body/form[1]
注意:1. 元素的xpath绝对路径可通过firebug直接查询。2. 一般不推荐使用绝对路径的写法,因为一旦页面结构发生变化,该路径也随之失效,必须重新写。3. 绝对路径以单/号表示,而下面要讲的相对路径则以//表示,这个区别非常重要。另外需要多说一句的是,当xpath的路径以/开头时,表示让Xpath解析引擎从文档的根节点开始解析。当xpath路径以//开头时,则表示让xpath引擎从文档的任意符合的元素节点开始进行解析。而当/出现在xpath路径中时,则表示寻找父节点的直接子节点,当//出现在xpath路径中时,表示寻找父节点下任意符合条件的子节点,不管嵌套了多少层级(这些下面都有例子,大家可以参照来试验)。弄清这个原则,就可以理解其实xpath的路径可以绝对路径和相对路径混合在一起来进行表示,想怎么玩就怎么玩。
下面是相对路径的引用写法:
查找页面根元素://
查找页面上所有的input元素://input
查找页面上第一个form元素内的直接子input元素(即只包括form元素的下一级input元素,使用绝对路径表示,单/号)://form[1]/input
查找页面上第一个form元素内的所有子input元素(只要在form元素内的input都算,不管还嵌套了多少个其他标签,使用相对路径表示,双//号)://form[1]//input
查找页面上第一个form元素://form[1]
查找页面上id为loginForm的form元素://form[@id=\'loginForm\']
查找页面上具有name属性为username的input元素://input[@name=\'username\']
查找页面上id为loginForm的form元素下的第一个input元素://form[@id=\'loginForm\']/input[1]
查找页面具有name属性为contiune并且type属性为button的input元素://input[@name=\'continue\'][@type=\'button\']
查找页面上id为loginForm的form元素下第4个input元素://form[@id=\'loginForm\']/input[4]
Xpath功能很强大,所以也可以写得更加复杂一些,如下面图(3)的HTML源码。
图(3)
如果我们现在要引用id为“J_password”的input元素,该怎么写呢?我们可以像下面这样写:
WebElement password = driver.findElement(By.xpath("//*[@id=\'J_login_form\']/dl/dt/input[@id=\'J_password\']"));
也可以写成:
WebElement password = driver.findElement(By.xpath("//*[@id=\'J_login_form\']/*/*/input[@id=\'J_password\']"));
这里解释一下,其中//*[@id=’ J_login_form’]这一段是指在根元素下查找任意id为J_login_form的元素,此时相当于引用到了form元素。后面的路径必须按照源码的层级依次往下写。按照图(3)所示代码中,我们要找的input元素包含在一个dt标签内,而dt又包含在dl标签内,所以中间必须写上dl和dt两层,才到input这层。当然我们也可以用*号省略具体的标签名称,但元素的层级关系必须体现出来,比如我们不能写成//*[@id=\'J_login_form\']/input[@id=\'J_password\'],这样肯定会报错的。
前面讲的都是xpath中基于准确元素属性的定位,其实xpath作为定位神器也可以用于模糊匹配。比如下面图(4)所示代码:
图(4)
这段代码中的“退出”这个超链接,没有标准id元素,只有一个rel和href,不是很好定位。不妨我们就用xpath的几种模糊匹配模式来定位它吧,主要有三种方式,举例如下。
a. 用contains关键字,定位代码如下:
1 driver.findElement(By.xpath(“//a[contains(@href, ‘logout’)]”));
这句话的意思是寻找页面中href属性值包含有logout这个单词的所有a元素,由于这个退出按钮的href属性里肯定会包含logout,所以这种方式是可行的,也会经常用到。其中@后面可以跟该元素任意的属性名。
b. 用start-with,定位代码如下:
1 driver.findElement(By.xpath(“//a[starts-with(@rel, ‘nofo’)]));
这句的意思是寻找rel属性以nofo开头的a元素。其中@后面的rel可以替换成元素的任意其他属性。
c. 用Text关键字,定位代码如下:
1 driver.findElement(By.xpath(“//*[text()=’退出’]));
这个方法可谓相当霸气啊。直接查找页面当中所有的退出二字,根本就不用知道它是个a元素了。这种方法也经常用于纯文字的查找。
另外,如果知道超链接元素的文本内容,也可以用
1 driver.findElement(By.xpath(“//a[contains(text(), ’退出’)]));
这种方式一般用于知道超链接上显示的部分或全部文本信息时,可以使用。
最后,关于xpath这种定位方式,webdriver会将整个页面的所有元素进行扫描以定位我们所需要的元素,所以这是一个非常费时的操作,如果你的脚本中大量使用xpath做元素定位的话,将导致你的脚本执行速度大大降低,所以请慎用。
8. By.cssSelector()
cssSelector这种元素定位方式跟xpath比较类似,但执行速度较快,而且各种浏览器对它的支持都相当到位,所以功能也是蛮强大的。
下面是一些常见的cssSelector的定位方式:
定位id为flrs的div元素,可以写成:#flrs 注:相当于xpath语法的//div[@id=’flrs’]
定位id为flrs下的a元素,可以写成 #flrs > a 注:相当于xpath语法的//div[@id=’flrs’]/a
定位id为flrs下的href属性值为/forexample/about.html的元素,可以写成: #flrs > a[href=”/forexample/about.html”]
如果需要指定多个属性值时,可以逐一加在后面,如#flrs > input[name=”username”][type=”text”]。
明白基本语法后,我们来尝试用cssSelector方式来引用图(3)中选中的那个input对象,代码如下:
WebElement password = driver.findElement(By.cssSelector("#J_login_form>dl>dt>input[id=’ J_password’]"));
同样必须注意层级关系,这个不能省略。
cssSelector还有一个用处是定位使用了复合样式表的元素,之前在第4种方式className里面提到过。现在我们就来看看如何通过cssSelector来引用到第4种方式中提到的那个button。button代码如下:
<button id="J_sidebar_login" class="btn btn_big btn_submit" type="submit">登录</button>
cssSelector引用元素代码如下:
driver.findElement(By.cssSelector("button.btn.btn_big.btn_submit"))
。这样就可以顺利引用到使用了复合样式的元素了。
此外,cssSelector还有一些高级用法,如果熟练后可以更加方便地帮助我们定位元素,如我们可以利用^用于匹配一个前缀,$用于匹配一个后缀,*用于匹配任意字符。例如:
匹配一个有id属性,并且id属性是以”id_prefix_”开头的超链接元素:a[id^=\'id_prefix_\']
匹配一个有id属性,并且id属性是以”_id_sufix”结尾的超链接元素:a[id$=\'_id_sufix\']
匹配一个有id属性,并且id属性中包含”id_pattern”字符的超链接元素:a[id*=\'id_pattern\']
最后再总结一下,各种方式在选择的时候应该怎么选择:
1. 当页面元素有id属性时,最好尽量用id来定位。但由于现实项目中很多程序员其实写的代码并不规范,会缺少很多标准属性,这时就只有选择其他定位方法。
2. xpath很强悍,但定位性能不是很好,所以还是尽量少用。如果确实少数元素不好定位,可以选择xpath或cssSelector。
3. 当要定位一组元素相同元素时,可以考虑用tagName或name。
4. 当有链接需要定位时,可以考虑linkText或partialLinkText方式。 参考技术A TestNG不支持verify语句, 但是也有简单的实现方法,简单的java代码示例如下
@Test
public void verifyTest()
/* buffer to hold your errors */
StringBuffer errorBuffer = new StringBuffer();
/* verification 1 */
try
Assert.assertEquals("value1", "value!");
catch(AssertionError e)
errorBuffer.append(e.getMessage() + "\n");
/* verification 2 */
try
Assert.assertEquals("value2", "value!");
catch(AssertionError e)
errorBuffer.append(e.getMessage());
if(errorBuffer.length() > 0)
throw new AssertionError(errorBuffer.toString());
是否存在无法检测到的 Selenium WebDriver 版本?
【中文标题】是否存在无法检测到的 Selenium WebDriver 版本?【英文标题】:Is there a version of Selenium WebDriver that is not detectable? 【发布时间】:2019-10-24 23:40:26 【问题描述】:我在住宅代理网络后面的Ubuntu 服务器上通过 Selenium 运行 Chrome 驱动程序。然而,我的 Selenium 正在被检测到。有没有办法让 Chrome 驱动程序和 Selenium 100% 不可检测?
我已经尝试了很长时间,以至于忘记了我做过的许多事情,包括:
-
尝试不同版本的 Chrome
从 Chrome 驱动程序文件中添加几个标志并删除一些单词。
使用隐身模式在代理(也包括住宅代理)后面运行它。
正在加载配置文件。
鼠标随机移动。
随机化一切。
我正在寻找 100% 无法检测到的真实版本的 Selenium。如果那曾经存在过。或者机器人跟踪器无法检测到的另一种自动化方式。
这是浏览器启动的一部分:
sx = random.randint(1000, 1500)
sn = random.randint(3000, 4500)
display = Display(visible=0, size=(sx,sn))
display.start()
randagent = random.randint(0,len(useragents_desktop)-1)
uag = useragents_desktop[randagent]
#this is to prevent ip leaking
preferences =
"webrtc.ip_handling_policy" : "disable_non_proxied_udp",
"webrtc.multiple_routes_enabled": False,
"webrtc.nonproxied_udp_enabled" : False
chrome_options.add_experimental_option("prefs", preferences)
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-impl-side-painting")
chrome_options.add_argument("--disable-setuid-sandbox")
chrome_options.add_argument("--disable-seccomp-filter-sandbox")
chrome_options.add_argument("--disable-breakpad")
chrome_options.add_argument("--disable-client-side-phishing-detection")
chrome_options.add_argument("--disable-cast")
chrome_options.add_argument("--disable-cast-streaming-hw-encoding")
chrome_options.add_argument("--disable-cloud-import")
chrome_options.add_argument("--disable-popup-blocking")
chrome_options.add_argument("--ignore-certificate-errors")
chrome_options.add_argument("--disable-session-crashed-bubble")
chrome_options.add_argument("--disable-ipv6")
chrome_options.add_argument("--allow-http-screen-capture")
chrome_options.add_argument("--start-maximized")
wsize = "--window-size=" + str(sx-10) + ',' + str(sn-10)
chrome_options.add_argument(str(wsize) )
prefs = "profile.managed_default_content_settings.images": 2
chrome_options.add_experimental_option("prefs", prefs)
chrome_options.add_argument("blink-settings=imagesEnabled=true")
chrome_options.add_argument("start-maximized")
chrome_options.add_argument("user-agent="+uag)
chrome_options.add_extension(pluginfile)#this is for the residential proxy
driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver", chrome_options=chrome_options)
【问题讨论】:
您查看过this question 以了解更多信息吗?每个网站如何以及是否进行机器人检测都会有所不同。他们可能通过 JavaScript 工作,或者他们可能正在检查服务器上的内容,例如,一些自动化工具还设置了适当的用户代理字符串。 我完成了 99% 的工作,还有很多事情没有任何效果.. 您是否尝试覆盖 userAgent?你在用无头浏览器吗? 简单的答案。不,这是不可能的 Can a website detect when you are using selenium with chromedriver?的可能重复 【参考方案1】:为什么不试试undetected-chromedriver?
优化的 Selenium Chromedriver 补丁,不会触发 Distill Network / Imperva / DataDome / Botprotect.io 等反僵尸服务自动下载驱动程序二进制文件并对其进行修补。
测试到当前的 chrome beta 版本 也适用于 Brave Browser 和许多其他基于 Chromium 的浏览器 Python 3.6++
你可以安装它:pip install undetected-chromedriver
您应该注意以下重要事项: 由于模块的内部工作原理,需要以编程方式浏览(即:使用 .get(url) )。切勿使用 gui 导航。使用键盘和鼠标进行导航可能会导致检测!新标签:同样的故事。如果你真的需要多标签,那么打开带有空白页面的标签(提示:url 是数据:,包括逗号,是的,驱动程序接受它)并照常做你的事情。如果您遵循这些“规则”(实际上是它的默认行为),那么您现在会玩得很开心。
In [1]: import undetected_chromedriver as uc
In [2]: driver = uc.Chrome()
In [3]: driver.execute_script('return navigator.webdriver')
Out[3]: True # Detectable
In [4]: driver.get('https://distilnetworks.com') # starts magic
In [4]: driver.execute_script('return navigator.webdriver')
In [5]: None # Undetectable!
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review 这里的多标签问题日志:github.com/ultrafunkamsterdam/undetected-chromedriver/issues/27 我一直在手动修改 chromedriver 使其无法检测到,但随后 citi.com 停止允许我登录。这可以让我再次登录 Citi。而且比自己做更容易。【参考方案2】:selenium 驱动的 WebDriver 被检测到 不这一事实取决于任何特定的 Selenium、Chrome 或ChromeDriver 版本。 网站本身可以检测网络流量,并可以将浏览器客户端,即Web浏览器识别为WebDriver控制。
然而,一些避免在网络抓取时被检测到的通用方法如下:
网站可以确定您的脚本/程序的首要属性是通过您的显示器大小。所以建议不要使用常规的Viewport。 如果您需要向一个网站发送多个请求,您需要不断更改每个请求的user-agent。你可以在Way to change Google Chrome user agent in Selenium?找到详细的讨论 要模拟 类人 行为,您可能需要减慢脚本执行速度,甚至超过 WebDriverWait 和 expected_conditions 诱导time.sleep(secs)
。在这里你可以找到关于How to sleep webdriver in python for milliseconds的详细讨论
@Antoine Vastel 在他的博客网站Detecting Chrome Headless 中提到了几种方法,它们将 Chrome 浏览器与 headless Chrome 浏览器区分开来。
用户代理:用户代理属性通常用于检测操作系统以及用户的浏览器。对于 Chrome 版本 59,它具有以下值:
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/59.0.3071.115 Safari/537.36
可以通过以下方式检查是否存在 Chrome headless:
if (/HeadlessChrome/.test(window.navigator.userAgent))
console.log("Chrome headless detected");
插件:navigator.plugins
返回浏览器中存在的插件数组。通常,在 Chrome 上,我们会找到默认插件,例如 Chrome PDF viewer
或 Google Native Client
。相反,在无头模式下,返回的数组包含 no 插件。
可以通过以下方式检查是否存在 插件:
if(navigator.plugins.length == 0)
console.log("It may be Chrome headless");
语言:在 Chrome 中,两个 Javascript 属性可以获取 user: navigator.language
和 navigator.languages
使用的语言。第一个是浏览器 UI 的语言,而第二个是代表用户首选语言的字符串数组。但是,在无头模式下,navigator.languages
返回一个 empty 字符串。
可以通过以下方式检查是否存在语言:
if(navigator.languages == "")
console.log("Chrome headless detected");
WebGL:WebGL 是一种在 HTML 画布中执行 3D 渲染的 API。使用此 API,可以查询图形驱动程序的供应商以及图形驱动程序的渲染器。使用普通的 Chrome 和 Linux,我们可以获得以下渲染器和供应商的值:Google SwiftShader
和 Google Inc.
。在无头模式下,我们可以获得Mesa OffScreen
,这是一种不使用任何窗口系统的渲染技术和Brian Paul
,这是启动开源Mesa图形库的程序。
可以通过以下方式检查是否存在 WebGL:
var canvas = document.createElement('canvas');
var gl = canvas.getContext('webgl');
var debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
if(vendor == "Brian Paul" && renderer == "Mesa OffScreen")
console.log("Chrome headless detected");
并非所有 Chrome 无头浏览器都具有相同的供应商和渲染器值。其他人保留在非无头版本上也可以找到的值。但是,Mesa Offscreen
和 Brian Paul
表示存在无头版本。
浏览器功能:Modernizr 库可以测试浏览器中是否存在各种 HTML 和 CSS 功能。我们发现 Chrome 和无头 Chrome 之间的唯一区别是后者没有细线功能,该功能检测到对 hidpi/retina hairlines
的支持。
可以通过以下方式检查是否存在细线特征:
if(!Modernizr["hairline"])
console.log("It may be Chrome headless");
缺少图像:我们列表中的最后一个似乎也是最可靠的,它来自 Chrome 使用的图像尺寸,以防图像无法加载。在普通 Chrome 的情况下,图像的宽度和高度取决于浏览器的缩放,但不为零。在无头 Chrome 中,图像的宽度和高度均为零。
可以通过以下方式检查是否存在缺失图像:
var body = document.getElementsByTagName("body")[0];
var image = document.createElement("img");
image.src = "http://iloveponeydotcom32188.jg";
image.setAttribute("id", "fakeimage");
body.appendChild(image);
image.onerror = function()
if(image.width == 0 && image.height == 0)
console.log("Chrome headless detected");
参考
您可以在以下位置找到几个类似的讨论:
How to bypass Google captcha with Selenium and python? How to make Selenium script undetectable using GeckoDriver and Firefox through Python?tl;博士
Selenium webdriver: Modifying navigator.webdriver flag to prevent selenium detection How does recaptcha 3 know I'm using selenium/chromedriver? Selenium and non-headless browser keeps asking for Captcha【讨论】:
嗨,感谢您提供的信息,我已经完成了大部分此类工作以及更多工作。我仍然被检测到。是否有一个脚本的链接,它实现了所有这些东西,我可以用作指南? selenium 标识自己:w3c.github.io/webdriver/…以上是关于Selenium webdriver有没有Verify值的方法的主要内容,如果未能解决你的问题,请参考以下文章
模块“selenium.webdriver”没有属性“PhantomJS”
模块'selenium.webdriver'没有属性'PhantomJS'
Selenium webdriver有没有Verify值的方法
如何使用 C# 在 Selenium WebDriver (Selenium 2) 中最大化浏览器窗口?