操作 DOM 元素
webdriver 主要提供了 2 个 API 来给我们操作 DOM 元素
- RemoteWebDriver::findElement(WebDriverBy) 获取单个元素
- RemoteWebDriver::findElements(WebDriverBy) 获取元素列表
WebDriverBy 是查询方式对象,提供了下面几个常用的方式
- WebDriverBy::id($id) 根据 ID 查找元素
- WebDriverBy::className($className) 根据 class 查找元素
- WebDriverBy::cssSelector($selctor) 根据通用的 css 选择器查询
- WebDriverBy::name($name) 根据元素的 name 属性查询
- WebDriverBy::linkText($text) 根据可见元素的文本锚点查询
- WebDriverBy::tagName($tagName) 根据元素标签名称查询
- WebDriverBy::xpath($xpath) 根据 xpath 表达式查询,这个很强大。 不了解什么是 xpath 的请参考我前面的文章 XPath 语法
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$input = $driver ->findElement(
WebDriverBy::id( ‘key‘ )
);
$input ->sendKeys( ‘iPhone 8‘ );
$button = $input ->findElement(
WebDriverBy::xpath( "../button[1]" )
);
$button ->click();
$links = $driver ->findElements(WebDriverBy::cssSelector( ".goods-list > .p-img > a" ));
$aTags = [];
foreach ( $links as $value ) {
array_push ( $aTags , array (
‘href‘ => $value ->getAttribute( ‘href‘ ),
‘title‘ => $value ->getAttribute( "title" )
));
}
print_r( $aTags );
|
cookies 操作
1
2
3
4
5
6
7
8
9
10
|
$cookies = $driver ->manage()->getCookies();
$driver ->manage()->deleteAllCookies();
$driver ->manage()->addCookie( array (
‘name‘ => ‘cookie_name‘ ,
‘value‘ => ‘cookie_value‘ ,
));
$cookies = $driver ->manage()->getCookies();
|
键盘操作
- RemoteKeyboard::sendKeys() 输入内容到当前 focus 的元素
- RemoteKeyboard::pressKey($key) 按下某个键
- RemoteKeyboard::releaseKey($key) 释放某个键
1
2
3
|
$driver ->getKeyboard()->sendKeys( "登录" );
$driver ->getKeyboard()->pressKey(WebDriverKeys::SHIFT);
$driver ->getKeyboard()->releaseKey(WebDriverKeys::SHIFT);
|
鼠标操作
- WebDriverMouse::click(WebDriverCoordinates) 单击鼠标
- WebDriverMouse::doubleClick(WebDriverCoordinates) 双击鼠标
- WebDriverMouse::mouseDown(WebDriverCoordinates) 触发 mousedown 事件
- WebDriverMouse::mouseUp(WebDriverCoordinates) 触发 mouseup 事件
- WebDriverMouse::click(WebDriverCoordinates, $x, $y) 移动鼠标到指定的位置,触发 mousemove 事件
注入 JS 代码
- RemoteWebDriver::executeScript($script, $args) 执行同步js代码
- RemoteWebDriver::executeAsyncScript($script, $args) 执行异步 js 代码
1
|
$driver ->executeScript( "document.body.scrollTop = 1000; alert(arguments[0])" , [ "fuck" ]);
|
截图
1
|
$driver ->takeScreenshot( "test.png" );
|
1.通过composer安装Selenium:
1 |
composer require facebook/webdriver |
2.下载Selenium Server并启动:
3 |
java -jar selenium-server-standalone-2.42.2.jar |
3. 运行测试代码
另启命令提示符,运行php test.php 命令
示例脚本test.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
<?php
namespace Facebook\WebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
require_once ( ‘vendor/autoload.php‘ );
header( "Content-Type: text/html; charset=UTF-8" );
$waitSeconds = 15;
$host = ‘http://localhost:4444/wd/hub‘ ; // this is the default
$capabilities = DesiredCapabilities::chrome();
$driver = RemoteWebDriver::create( $host , $capabilities , 5000);
$driver ->get( ‘https://www.baidu.com/‘ );
echo iconv( "UTF-8" , "GB2312" , ‘标题1‘ ). ":" . $driver ->getTitle() . "\n" ;
$driver ->findElement(WebDriverBy::id( ‘kw‘ ))->sendKeys( ‘wwe‘ )->submit();
$driver ->wait( $waitSeconds )->until(
WebDriverExpectedCondition::visibilityOfElementLocated(
WebDriverBy::partialLinkText( ‘100shuai‘ )
)
);
$driver ->findElement(WebDriverBy::partialLinkText( ‘100shuai‘ ))->sendKeys( ‘xxx‘ )->click();
switchToEndWindow( $driver );
$driver ->wait( $waitSeconds )->until(
WebDriverExpectedCondition::visibilityOfElementLocated(
WebDriverBy::partialLinkText( ‘SmackDown收视率创历史新低‘ )
)
);
echo iconv( "UTF-8" , "GB2312" , ‘标题2‘ ). ":" . $driver ->getTitle() . "\n" ;
$driver ->findElement(WebDriverBy::partialLinkText( ‘SmackDown收视率创历史新低‘ ))->click();
switchToEndWindow( $driver );
$driver ->wait( $waitSeconds )->until(
WebDriverExpectedCondition::titleContains( ‘SmackDown收视率创历史新低‘ )
);
echo iconv( "UTF-8" , "GB2312" , ‘标题3‘ ). ":" . $driver ->getTitle() . "\n" ;
$driver ->quit();
function switchToEndWindow( $driver ){
$arr = $driver ->getWindowHandles();
foreach ( $arr as $k => $v ){
if ( $k == ( count ( $arr )-1)){
$driver ->switchTo()->window( $v );
}
}
}
|
元素定位
1. WebDriverBy::id()
通过ID属性定位元素
5 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
7 |
$element = $driver ->findElement(WebDriverBy::id( ‘kw‘ )); |
2. WebDriverBy::name()
通过name属性定位元素。如果查找多个,则使用findElements进行定位
05 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
07 |
$element = $driver ->findElement(WebDriverBy::name( ‘wd‘ )); |
08 |
foreach ( $elements as $elem ){ |
09 |
echo $elem ->getAttribute( ‘type‘ ); |
10 |
echo $elem -> getText (); |
3. WebDriverBy::tagName()
通过标签进行定位元素。如果查找多个,则使用findElements进行定位,具体参考WebDriverBy::name()的代码
07 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
09 |
$element = $driver ->findElement(WebDriverBy::tagName( ‘input‘ )); |
4. WebDriverBy::className()
通过css类进行定位元素。如果查找多个,则使用findElements进行定位,具体参考WebDriverBy::name()的代码
5 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
7 |
$element = $driver ->findElement(WebDriverBy::className( ‘s_ipt‘ )); |
5. WebDriverBy::linkText()
通过超文本链接上的文字信息来定位元素。如果查找多个,则使用findElements进行定位,具体参考WebDriverBy::name()的代码
5 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
7 |
$element = $driver ->findElement(WebDriverBy::linkText( ‘新闻‘ )); |
6. WebDriverBy::partialLinkText()
这个方法是上一个方法的扩展。当你不能准确知道超链接上的文本信息或者只想通过一些关键字进行匹配时,可以使用这个方法来通过部分链接文字进行匹配。如果查找多个,则使用findElements进行定位,具体参考WebDriverBy::name()的代码
5 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome(), 5000); |
7 |
$element = $driver ->findElement(WebDriverBy::partialLinkText( ‘新‘ )); |
7. WebDriverBy::xpath()
这个方法是非常强大的元素查找方式,使用这种方法几乎可以定位到页面上的任意元素。在正式开始使用XPath进行定位前,我们先了解下什么是XPath。XPath是XML Path的简称,由于HTML文档本身就是一个标准的XML页面,所以我们可以使用XPath的语法来定位页面元素。更多详细的定位资料,参考页脚链接地址。
XPath语法如下:
2 |
$element = $driver ->findElement(WebDriverBy::xpath( "//*[@id=‘J_login_form‘]/dl/dt/input[@id=‘J_password‘]" )); |
8. WebDriverBy::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方式来层级关系定位,代码如下:
5 |
$element = $driver ->findElement(WebDriverBy::cssSelector( "#J_login_form>dl>dt>input[id=‘J_password‘]" )); |
cssSelector还有一个用处是定位使用了复合样式表的元素,之前在第4种方式className里面提到过。现在我们就来看看如何通过cssSelector来引用到第4种方式中提到的那个button。button代码如下:
5 |
$element = $driver ->findElement(WebDriverBy::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’]
9. 判断定位的元素是否存在
selenium找元素时,如果超出timeout时间后,还未找到元素,则会报异常,我们则可以利用这样的方式进行判断元素是否存在。不过这种方式对于及时性要求不高的情况下使用,如果要求及时性的话,建议还是获取到page source后,用htmlparser或正则判断即可。
03 |
if (isElementExsit( $driver , WebDriverBy::linkText( ‘新闻‘ ))){ |
14 |
function isElementExsit( $driver , $locator ){ |
16 |
$nextbtn = $driver ->findElement( $locator ); |
18 |
} catch (\Exception $e ) { |
19 |
echo ‘element is not found!‘ ; |
元素操作
1.输入框
1 |
$element = $driver ->findElement(WebDriverBy::id( ‘wd‘ )); |
2 |
$element ->sendKeys( "wwe" ); |
4 |
$element ->getAttribute( ‘value‘ ); |
2.单选框
1 |
$radio = $driver ->findElement(WebDriverBy::id( ‘BookMode‘ )); |
3.多选框
1 |
$checkbox = $driver ->findElement(WebDriverBy::id( ‘myCheckbox‘ )); |
3 |
$checkbox ->isSelected(); |
4 |
$checkbox ->isEnabled(); |
4.下拉框
下拉框是我们最常见的一种页面元素,对于一般的元素,我们只需要一次就定位,但下拉框里的内容需要进行两次定位,先定位到下拉框,再定位到下拉框内里的选项。
1 |
$select = $driver ->findElement(WebDriverBy::id( ‘myselect‘ )); |
2 |
$select ->findElement(WebDriverBy::xpath( "//option[@value=‘100‘]" ))->click(); //找到值为100的选项进行选中 |
5.按钮
1 |
$btn = $driver ->findElement(WebDriverBy::id( ‘btn‘ )); |
6.文件上传
1 |
$upload = $driver ->findElement(WebDriverBy::id( ‘img-upload‘ )); |
2 |
$filePath = "C:\test\\uploadfile\\media_ads\\test.jpg" ; |
3 |
$upload ->sendKeys( $filePath ); |
7.指定元素点击
因为有时候因为种种原因(如元素上有蒙版层或者因为一些浮动的div导致坐标变化或者不可点击),而不能使用$ele.click()时,采用通用的方式,就是用JS执行点击事件。而且点击事件是可被监听的,可在元素上写onclick事件进行监听。
02 |
$ele = $driver ->findElement(WebDriverBy::id( ‘haha‘ )); |
03 |
$driver ->executeScript( "arguments[0].click();" ,[ $ele ]); |
07 |
var ele = document.getElementById( ‘haha‘ ); |
10 |
$driver ->executeScript( $js ); |
8.滚动到指定元素
用JS的方式滚动到指定的元素。
1 |
$ele = $driver ->findElement(WebDriverBy::id( ‘haha2‘ )); |
2 |
$driver ->executeScript( "arguments[0].scrollIntoView();" ,[ $ele ]); |
9.移动到指定元素
移动的时候,鼠标不会真正移动,但实际上已移动,这个可以在haha2元素上写一个onmouseover事件进行监听即可测试。
1 |
$ele = $driver ->findElement(WebDriverBy::id( ‘haha2‘ )); |
2 |
$driver ->getMouse()->mouseMove( $ele ->getCoordinates()); |
元素等待
明确的等待
明确的等待是指在代码进行下一步操作之前等待某一个条件的发生。最不好的情况是使用sleep()去设置一段确认的时间去等待。但为什么说最不好呢?因为一个元素的加载时间有长有短,你在设置sleep的时间之前要自己把握长短,太短容易超时,太长浪费时间。selenium webdriver提供了一些方法帮助我们等待正好需要等待的时间,比如以下例子中我们设置的最长等待时间为15秒。
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
11 |
$capabilities = DesiredCapabilities::chrome(); |
12 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
16 |
$driver ->wait( $waitSeconds )->until( |
17 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
21 |
$driver ->findElement(WebDriverBy::id( ‘kw‘ ))->sendKeys( ‘wwe‘ ); |
隐性等待
隐性等待是指当要查找元素,而这个元素没有马上出现时,告诉WebDriver查询Dom一定时间。默认值是0,但是设置之后,这个时间将在WebDriver对象实例整个生命周期都起作用。上面的代码就变成了这样:
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
10 |
$capabilities = DesiredCapabilities::chrome(); |
11 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
12 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
15 |
$driver ->findElement(WebDriverBy::id( ‘kw‘ ))->sendKeys( ‘wwe‘ ); |
JS调用
frame与弹窗的控制
对于web应用,经常会出现框架(frame) 或窗口(window)的应用,这也就给我们的定位带来了一个难题。有时候我们定位一个元素,定位器没有问题,但一直定位不了,这时候就要检查这个元素是否在一个frame中,seelnium webdriver 提供了这样的方法,可以很轻松的来解决这个问题。
- $driver->switchTo()->frame(“id”)
- $driver->switchTo()->window(“id”)
- $driver->switchTo()->alert()
frame示例脚本
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
14 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
17 |
echo $driver ->getCurrentURL(). ‘\r\n‘ ; |
22 |
$js = "window.scrollBy(0,100000000);" ; |
23 |
$driver ->executeScript( $js ); |
26 |
#再找到其下面的 iframe(id=commentIframe) |
27 |
$driver ->switchTo()->frame( "commentIframe" ); |
28 |
$str = $driver ->getPageSource(); |
32 |
fwrite( $myfile , $str ); |
alert示例脚本
3 |
$driver ->switchTo()->alert()->accept(); |
4 |
$driver ->switchTo()->alert()->dismiss(); |
5 |
$driver ->switchTo()->alert()-> getText (); |
我们以百度的页面为例来演示一下功能。
1.点击百度的设置
2.选择”每天显示多少条”的下拉框 (这个顺便把“元素操作”文章中的“select”元素章节也演示了)
3.点击保存设置按钮:会弹出一个alert弹窗
4.执行点击alert的确定按钮
5.试一下搜索的结果是否变化,操作完毕
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
13 |
$capabilities = DesiredCapabilities::chrome(); |
14 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
18 |
$driver ->findElement(WebDriverBy::linkText( ‘设置‘ ))->click(); |
20 |
$driver ->findElement(WebDriverBy::linkText( ‘搜索设置‘ ))->click(); |
22 |
$warpper = $driver ->findElement(WebDriverBy::id( ‘wrapper‘ )); |
26 |
$driver ->wait( $waitSeconds )->until( |
27 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
32 |
$selectDom = $warpper ->findElement(WebDriverBy::id( ‘nr‘ )); |
33 |
$select = new WebDriverSelect( $selectDom ); |
34 |
$select ->selectByValue(10); |
37 |
$driver ->wait( $waitSeconds )->until( |
38 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
39 |
WebDriverBy::linkText( ‘保存设置‘ ) |
43 |
$driver ->findElement(WebDriverBy::linkText( ‘保存设置‘ ))->click(); |
47 |
$driver ->switchTo()->alert()->accept(); |
49 |
$driver ->findElement(WebDriverBy::id( "kw" ))->sendKeys( ‘wwe‘ ); |
50 |
$driver ->findElement(WebDriverBy::id( "su" ))->click(); |
window弹窗 示例脚本
AJAX分页数据获取
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
10 |
$capabilities = DesiredCapabilities::chrome(); |
11 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
12 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
16 |
js = "window.scrollTo(0,document.body.scrollHeight)" |
18 |
$driver ->executeScript( $js ); |
24 |
js = "window.scrollTo(0,document.body.scrollHeight)" ; |
25 |
$driver ->executeScript( $js ); |
31 |
js = "window.scrollTo(0,document.body.scrollHeight)" ; |
32 |
$driver ->executeScript( $js ); |
PhantomJS
用浏览器驱动的方式,很方便我们在测试阶段调试代码正确性,但是由于浏览器要启动,解析DOM、JS、下载图片等,使得程序跑起来的效率并不高,这个时候我们就需要用到Phantomjs,以后台的形式运行程序,大大的提升运行的性能。
1.安装Phantomjs
到http://phantomjs.org/download.html 上面去下载对应的版本,我这里下载的是windows版本的。将解压包中的phantomjs.exe放到PHP程序根目录,或将该exe加入到本机的环境变量中都行。
2.使用Phantomjs
拿的是“验证码识别”那篇文章的代码,只改了一处,$capabilities = DesiredCapabilities::phantomjs();这一行。
运行后,可以看到“验证码识别”程序不再启动chrome浏览器,而是后台执行,速度也快了很多。程序顺利跑出了我们想要的结果~ 大家可以休息一下咯~
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
12 |
$capabilities = DesiredCapabilities::phantomjs(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
16 |
$driver ->manage()->window()->maximize(); |
17 |
$driver ->takeScreenshot(vcodeDst); |
18 |
$element = $driver ->findElement(WebDriverBy::id( ‘vcode_img‘ )); |
19 |
generateVcodeIMG( $element ->getLocation(), $element ->getSize(),vcodeDst); |
31 |
function generateVcodeIMG( $location , $size , $src_img ){ |
32 |
$width = $size ->getWidth(); |
33 |
$height = $size ->getHeight(); |
34 |
$x = $location ->getX(); |
35 |
$y = $location ->getY(); |
37 |
$src = imagecreatefrompng( $src_img ); |
38 |
$dst = imagecreatetruecolor( $width , $height ); |
39 |
imagecopyresampled( $dst , $src ,0,0, $x , $y , $width , $height , $width , $height ); |
40 |
imagejpeg( $dst , $src_img ); |
屏蔽图片
1. 查看chrome支持的浏览器属性
chrome driver的官方文档( https://sites.google.com/a/chromium.org/chromedriver/capabilities ),可以看到,chrome driver可以支持的自定义属性
php-webdriver:PHP控制浏览器动作, php web驱动, PHP实现自动化, A php client for webdriver.
2. 查看本地配置的参数值
可以使用自己的chrome浏览器进行配置,配置好了后,查看“Preferences文件”里的值就可以了。一般路径都为“用户文件夹\AppData\Local\Google\Chrome\User Data\Default”。
php-webdriver:PHP控制浏览器动作, php web驱动, PHP实现自动化, A php client for webdriver.
php-webdriver:PHP控制浏览器动作, php web驱动, PHP实现自动化, A php client for webdriver.
php-webdriver:PHP控制浏览器动作, php web驱动, PHP实现自动化, A php client for webdriver.
3. 代码DEMO
找到了屏蔽图片对应的参数后,我们就可以进行测试了
02 |
$capabilities = DesiredCapabilities::chrome(); |
03 |
$options = new ChromeOptions(); |
04 |
$value = [ ‘profile.managed_default_content_settings.images‘ =>2]; |
05 |
$options ->setExperimentalOption( ‘prefs‘ , $value ); |
06 |
$capabilities ->setCapability(ChromeOptions::CAPABILITY, $options ); |
08 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
09 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
4. 换个思路,变得更简洁
上面提到的都是设置具体的参数,而要找到对应设置的参数比较繁杂,当如果不想那么麻烦时候,完全可以在已有的chrome浏览器先设置好,然后把“用户文件夹\AppData\Local\Google\Chrome\User Data”加载到自己的应用中。
02 |
$capabilities = DesiredCapabilities::chrome(); |
03 |
$options = new ChromeOptions(); |
04 |
$options ->addArguments([ "--user-data-dir=d:/xampp/test/User Data" ]); |
05 |
$capabilities ->setCapability(ChromeOptions::CAPABILITY, $options ); |
07 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
08 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
总结:这里虽然只是介绍的屏蔽图片,但是同理的chrome其他设置也可以用这样的方式进行,如禁用JS等等之类的。
使用扩展插件
有时候我们需要使用浏览器的扩展插件来帮助我们达到某种特定的效果,比如“Block Image”插件可使得selenium使用过程中不显示图片,从而加快访问的速度和性能。再比如使用“adsafe”插件可使得访问网站的时候禁用相应的广告以及弹窗广告等。
这里我们使用”Block Image”插件的来展示下selenium怎么加载插件。这里使用的是chrome driver方式进行测试,其他浏览器的测试代码请自行百度。
1.下载Block Image插件
到http://www.cnplugins.com/ 上面搜索Block Image,下载下来,存放到自己的程序根目录。
2.代码测试
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
use Facebook\WebDriver\Chrome\ChromeOptions; |
06 |
require_once ( ‘vendor/autoload.php‘ ); |
08 |
header( "Content-Type: text/html; charset=UTF-8" ); |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$options = new ChromeOptions(); |
14 |
$options ->addExtensions([ ‘Block-image.crx‘ ]); |
15 |
$capabilities ->setCapability(ChromeOptions::CAPABILITY, $options ); |
16 |
$driver = RemoteWebDriver::create( $host , $capabilities , 15000); |
17 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
代理设置
1.修改User Agent
Chrome 示例
这里提供user-agent大全供参考http://www.cnblogs.com/hykun/p/Ua.html
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
use Facebook\WebDriver\Chrome\ChromeOptions; |
06 |
require_once ( ‘vendor/autoload.php‘ ); |
08 |
header( "Content-Type: text/html; charset=UTF-8" ); |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$useragent = ‘Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1‘ ; |
14 |
$options = new ChromeOptions(); |
15 |
$options ->addArguments([ "user-agent={$useragent}" ]); |
16 |
$capabilities ->setCapability(ChromeOptions::CAPABILITY, $options ); |
18 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
19 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
21 |
var_dump( $capabilities ->getCapability(ChromeOptions::CAPABILITY)); |
Phantomjs 示例
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
use Facebook\WebDriver\Chrome\ChromeOptions; |
06 |
require_once ( ‘vendor/autoload.php‘ ); |
08 |
header( "Content-Type: text/html; charset=UTF-8" ); |
12 |
$capabilities = DesiredCapabilities::phantomjs(); |
13 |
$useragent = ‘Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1‘ ; |
14 |
$capabilities ->setCapability( "phantomjs.page.settings.userAgent" , $useragent ); |
16 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
17 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
19 |
echo $driver ->findElement(WebDriverBy::id( ‘ua_code‘ ))->getAttribute( ‘value‘ ); |
2.修改代理IP
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
04 |
use Facebook\WebDriver\Remote\WebDriverCapabilityType; |
05 |
require_once ( ‘vendor/autoload.php‘ ); |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
09 |
$ip = ‘115.225.2.3:8998‘ ; |
10 |
$capabilities = array (WebDriverCapabilityType::BROWSER_NAME => ‘chrome‘ , |
11 |
WebDriverCapabilityType::PROXY => array ( ‘proxyType‘ => ‘manual‘ , |
12 |
‘httpProxy‘ => $ip , ‘sslProxy‘ => $ip )); |
14 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
15 |
$driver ->manage()->timeouts()->implicitlyWait(15); |
17 |
$driver ->findElement(WebDriverBy::id( ‘kw‘ ))->sendKeys( ‘ip‘ ); |
18 |
$driver ->findElement(WebDriverBy::id( ‘su‘ ))->click(); |
使用总结
使用selenium时会遇到很多的坑,这里分享一些经验给大家。
1.wait ~ until的使用
要勤使用wait~until,由于我们打开的网页有时候会比较慢时,查找调用某个元素时就比较容易报NoSuchElementException异常。或者有时候一些JS是动态生成的,也需要用到wait~until,不然也会报错。
2.switchToEndWindow勤使用
switchToEndWindow是我们自定义的一个方法,由于我们使用selenium访问某个网页,然后又点击了其中一个链接,谁知道这个链接是否含有target=”_blank”呢。做爬虫类程序尤为如此。所以我们增加一个方法,每次点击了某个链接跳转后,执行一下switchToEndWindow方法。
03 |
function switchToEndWindow( $driver ){ |
05 |
$arr = $driver ->getWindowHandles(); |
06 |
foreach ( $arr as $k => $v ){ |
07 |
if ( $k == ( count ( $arr )-1)){ |
08 |
$driver ->switchTo()->window( $v ); |
3.异常处理
使用selenium过程中,会碰到各种意想不到的报错。比如做爬虫过程中,都要用try包含起来处理异常,这样可以防止一旦异常报错后,终止了程序的执行。那么在测试的每个节点的健康状态,可在数据库中记录查询。
4.定位异常解决
元素在网页第一次加载后,就会确定他的坐标,当我们进行了某种操作,改变了宽度或高度,则很容易引起相关元素的坐标改变,从而报错。
报错信息:Element is not clickable at point (284, 11).
解决保存就是在调用click或submit方式之前先调用sendKeys方法,让其重绘坐标
1 |
$elemA ->sendKeys( ‘xxx‘ )->click(); |
2 |
$elemB ->sendKeys( ‘xxx‘ )->submit(); |
有时候,以上使用sendKeys方式还是没办法解决问题时,则很可能是因为网页中含有浮动DIV,导致各个元素定位变化了。
这个时候只需要找到那个浮动的DIV,隐藏掉就可以了。
2 |
var nav = document.getElementsByClassName( "nav_m" ); |
3 |
nav[0].style.display = ‘none‘ ; |
5 |
$driver ->executeScript( $js ); |
如果以上两种方式结合都还有问题的情况下,就建议用JS来解决。
02 |
$elems = $driver ->findElements(WebDriverBy::className( ‘n‘ )); |
03 |
foreach ( $elems as $elem ){ |
04 |
if (CommonUtil::contain( $elem -> getText (), ‘下一页‘ )){ |
05 |
$elem ->sendKeys( ‘xxx‘ ); |
11 |
var next = document.getElementsByClassName( ‘n‘ ); |
12 |
for (i = 0; i < next.length; i++) { |
13 |
if (next[i].innerHTML == ‘下一页>‘ ){ |
15 |
next[i].style.backgroundColor = "red" ; |
20 |
$driver ->executeScript( $js ); |
5.执行时间的设置
使用自动化测试或爬虫程序,往往程序执行的时间会比较长。为了防止timeout,我们需要设置如下
2 |
ignore_user_abort(true); |
下载资料:
1.http://selenium-release.storage.googleapis.com/index.html (selenium 下载地址)
2.https://chromedriver.storage.googleapis.com/index.html (chrome driver 下载地址)
3.http://phantomjs.org/download.html (PhantomJS Driver 下载地址)
4.http://www.cnbeta.com/articles/soft/563605.htm (chrome 下载地址,建议使用这个版本或者以下版本,其他最新版本,浏览器识别了是否为测试软件,对于个别用途的软件需要注意,如果仅仅是为了做测试,那就无所谓了。)
5.http://blog.csdn.net/huilan_same/article/details/51896672 (chromedriver.exe版本对应的chrome版本)
参考文档:
1.https://github.com/facebook/php-webdriver (里面有example.php以及 tests文件下的案例文档共参考)
2.https://github.com/facebook/php-webdriver/wiki 快速开始教程
3.http://facebook.github.io/php-webdriver/namespaces/default.html API文档
4.http://www.yiibai.com/selenium/ 易百教程
6.https://github.com/chibimagic/WebDriver-PHP/
7.https://code.google.com/archive/p/php-webdriver-bindings/
8.https://github.com/Element-34/php-webdriver
9.https://github.com/Nearsoft/php-selenium-client
10.http://pan.baidu.com/s/1eR31pM6 selenium_webdriver(python)第一版.pdf