項目地址:https://github.com/facebook/php-webdriver
一、技術選型
php + facebook/webdriver + selenium
Selenium是一套完整的Web應用程序測試系統,它提供了一系列的操作瀏覽器的 API
webdriver 是 facebook 開發的一套 selenium API 的客戶端組件,使用 composer 作為依賴管理工具。
二、環境搭建
- php 的開發環境
- webdriver 使用 composer 做依賴管理,所以需要安裝 composer
- selenium-server 需要 java 運行環境
環境配置自己搞定,很簡單,這里就不做贅述了。
三、開始使用
安裝 php-webdriver
1 |
# 前提是需要安裝好 composer.phar |
2 |
curl -sS https: //getcomposer .org /installer | php |
3 |
4 |
# 安裝library |
5 |
php composer.phar require facebook /webdriver |
運行 Selenium 服務, 首先你需要到 selenium 官網去下載 selenium-server-standalone-#.jar, 下載地址請狠狠的 戳這里.
或者直接下載最新版 (2018-12-14):selenium-server-standalone-3.9.1
1 |
java -jar -Dwebdriver.chrome.driver= "driver/chromedriver" selenium-server-standalone-x.xx.x.jar -port 4444 |
需要指定一個 chromedriver(一個閹割版的 chrome 瀏覽器) ,這里是下載地址 也可以直接下載最新版 (2018-12-14):
另外:Java 8+ 必須已經安裝.
然后創建一個會話,並指定你的服務器運行的地址和端口。
1 |
$host = 'http://localhost:4444/wd/hub' ; |
啟動火狐瀏覽器,前提是你安裝了火狐的 Geckodriver
1 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::firefox()); |
或者啟動 chrome 瀏覽器
1 |
$driver = RemoteWebDriver::create( $host , DesiredCapabilities::chrome()); |
你也可以自定義配置你的瀏覽器
1 |
$host = 'http://localhost:4444/wd/hub' ; |
2 |
$capabilities = DesiredCapabilities::chrome(); |
3 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
更多配置,請參考 這里.
設置瀏覽器窗口
1 |
$size = new WebDriverDimension(1280, 900); |
2 |
$driver ->manage()->window()->setSize( $size ); |
$driver->manage()->window() 返回的是一個 WebDriverWindow, 它提供了以下 API
方法名稱 | 方法說明 |
getPosition(), setPosition() | 獲取,設置瀏覽器的位置 |
getSize(), setSize() | 獲取,設置瀏覽器大小 |
maximize() | 最大化窗口 |
發送請求
1 |
$driver ->get( 'http://www.ikeepstudying.com' ); |
操作 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
|
// id 查詢
$input
=
$driver
->findElement(
WebDriverBy::id(
'key'
)
);
//往輸入框填入元素
$input
->sendKeys(
'iPhone 8'
);
// xpath 查詢
$button
=
$input
->findElement(
WebDriverBy::xpath(
"../button[1]"
)
);
$button
->click();
//單擊按鈕
//獲取列表的 a 標簽
$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
|
// fetch cookies
$cookies
=
$driver
->manage()->getCookies();
// delete cookies
$driver
->manage()->deleteAllCookies();
// add cookies
$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);
//按下 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"
);
|
快速開始
Selenium是用於自動化測試工具,它是在Apache許可證2.0許可的開放源代碼工具。Selenium是一套工具,它有助於自動化Web應用程序測試。
- 框架底層使用JavaScript模擬真實用戶對瀏覽器進行操作。測試腳本執行時,瀏覽器自動按照腳本代碼做出點擊,輸入,打開,驗證等操作,就像真實用戶所做的一樣,從終端用戶的角度測試應用程序。
- 使瀏覽器兼容性測試自動化成為可能,盡管在不同的瀏覽器上依然有細微的差別。
- 使用簡單,可使用Java,Python等多種語言編寫用例腳本。
1.通過composer安裝Selenium:
1 |
composer require facebook/webdriver |
2.下載Selenium Server並啟動:
1 |
//到http://www.seleniumhq.org/download/ 下找到Selenium Standalone Server並下載,或到https://chromedriver.storage.googleapis.com/index.html 上面下載。 |
2 |
//到命令提示符里啟動以下命令(前提需要安裝jdk,確保java命令能夠運行) |
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"
);
// start Firefox with 5 second timeout
$waitSeconds
= 15;
//需等待加載的時間,一般加載時間在0-15秒,如果超過15秒,報錯。
$host
=
'http://localhost:4444/wd/hub'
; // this is the
default
//這里使用的是chrome瀏覽器進行測試,需到http://www.seleniumhq.org/download/上下載對應的瀏覽器測試插件
//我這里下載的是win32 Google Chrome Driver 2.25版:https://chromedriver.storage.googleapis.com/index.html?path=2.25/
$capabilities
= DesiredCapabilities::chrome();
$driver
= RemoteWebDriver::create(
$host
,
$capabilities
, 5000);
// navigate to 'http://docs.seleniumhq.org/'
$driver
->get(
'https://www.baidu.com/'
);
echo
iconv(
"UTF-8"
,
"GB2312"
,
'標題1'
).
":"
.
$driver
->getTitle() .
"\n"
;
//cmd.exe中文亂碼,所以需轉碼
$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();
//一般點擊鏈接的時候,擔心因為失去焦點而拋異常,則可以先調用一下sendKeys,再click
switchToEndWindow(
$driver
);
//切換至最后一個window
// 等待加載....
$driver
->wait(
$waitSeconds
)->until(
WebDriverExpectedCondition::visibilityOfElementLocated(
WebDriverBy::partialLinkText(
'SmackDown收視率創歷史新低'
)
)
);
echo
iconv(
"UTF-8"
,
"GB2312"
,
'標題2'
).
":"
.
$driver
->getTitle() .
"\n"
;
//cmd.exe中文亂碼,所以需轉碼
$driver
->findElement(WebDriverBy::partialLinkText(
'SmackDown收視率創歷史新低'
))->click();
switchToEndWindow(
$driver
);
//切換至最后一個window
// 等待加載....
$driver
->wait(
$waitSeconds
)->until(
WebDriverExpectedCondition::titleContains(
'SmackDown收視率創歷史新低'
)
);
echo
iconv(
"UTF-8"
,
"GB2312"
,
'標題3'
).
":"
.
$driver
->getTitle() .
"\n"
;
//cmd.exe中文亂碼,所以需轉碼
//關閉瀏覽器
$driver
->quit();
//切換至最后一個window
//因為有些網站的鏈接點擊過去帶有target="_blank"屬性,就新開了一個TAB,而selenium還是定位到老的TAB上,如果要實時定位到新的TAB,則需要調用此方法,切換到最后一個window
function
switchToEndWindow(
$driver
){
$arr
=
$driver
->getWindowHandles();
foreach
(
$arr
as
$k
=>
$v
){
if
(
$k
== (
count
(
$arr
)-1)){
$driver
->switchTo()->window(
$v
);
}
}
}
|
元素定位
1. WebDriverBy::id()
通過ID屬性定位元素
1
//HTML代碼
2
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::id(
'kw'
));
8
?>
2. WebDriverBy::name()
通過name屬性定位元素。如果查找多個,則使用findElements進行定位
01
//HTML代碼
02
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
03
04
<?php
05
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
06
$driver
->get(
'https://www.baidu.com/'
);
07
$element
=
$driver
->findElement(WebDriverBy::name(
'wd'
));
08
foreach
(
$elements
as
$elem
){
//有時候多個元素時,想找出某個特定元素,可根據attribute或text進行判斷過濾
09
echo
$elem
->getAttribute(
'type'
);
10
echo
$elem
->
getText
();
11
}
12
?>
3. WebDriverBy::tagName()
通過標簽進行定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
01
//HTML代碼
02
//<input type="hidden" name="rsv_bp" value="0" />
03
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
04
//.....
05
06
<?php
07
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
08
$driver
->get(
'https://www.baidu.com/'
);
09
$element
=
$driver
->findElement(WebDriverBy::tagName(
'input'
));
10
?>
4. WebDriverBy::className()
通過css類進行定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::className(
's_ipt'
));
8
?>
5. WebDriverBy::linkText()
通過超文本鏈接上的文字信息來定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a>
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::linkText(
'新聞'
));
8
?>
6. WebDriverBy::partialLinkText()
這個方法是上一個方法的擴展。當你不能准確知道超鏈接上的文本信息或者只想通過一些關鍵字進行匹配時,可以使用這個方法來通過部分鏈接文字進行匹配。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a>
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::partialLinkText(
'新'
));
8
?>
7. WebDriverBy::xpath()
這個方法是非常強大的元素查找方式,使用這種方法幾乎可以定位到頁面上的任意元素。在正式開始使用XPath進行定位前,我們先了解下什么是XPath。XPath是XML Path的簡稱,由於HTML文檔本身就是一個標准的XML頁面,所以我們可以使用XPath的語法來定位頁面元素。更多詳細的定位資料,參考頁腳鏈接地址。
XPath語法如下:
1 |
<?php |
2 |
$element = $driver ->findElement(WebDriverBy::xpath( "//*[@id='J_login_form']/dl/dt/input[@id='J_password']" )); |
3 |
?> |
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方式來層級關系定位,代碼如下:
1 |
//HTML代碼 |
2 |
//<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a> |
3 |
4 |
<?php |
5 |
$element = $driver ->findElement(WebDriverBy::cssSelector( "#J_login_form>dl>dt>input[id='J_password']" )); |
6 |
?> |
cssSelector還有一個用處是定位使用了復合樣式表的元素,之前在第4種方式className里面提到過。現在我們就來看看如何通過cssSelector來引用到第4種方式中提到的那個button。button代碼如下:
1 |
//HTML代碼 |
2 |
//<button id="J_sidebar_login" class="btn btn_big btn_submit" type="submit">登錄</button> |
3 |
4 |
<?php |
5 |
$element = $driver ->findElement(WebDriverBy::cssSelector( "button.btn.btn_big.btn_submit" )); |
6 |
?> |
此外,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或正則判斷即可。
01
<?php
02
03
if
(isElementExsit(
$driver
, WebDriverBy::linkText(
'新聞'
))){
04
echo
'找到元素啦'
;
05
}
else
{
06
echo
'沒有找到元素'
;
07
}
08
09
/**
10
* 判斷元素是否存在
11
* @param WebDriver $driver
12
* @param WebDriverBy $locator
13
*/
14
function
isElementExsit(
$driver
,
$locator
){
15
try
{
16
$nextbtn
=
$driver
->findElement(
$locator
);
17
return
true;
18
}
catch
(\Exception
$e
) {
19
echo
'element is not found!'
;
20
return
false;
21
}
22
}
23
?>
元素操作
1.輸入框
1 |
$element = $driver ->findElement(WebDriverBy::id( 'wd' )); |
2 |
$element ->sendKeys( "wwe" ); //在輸入框中輸入內容 |
3 |
$element ->clear(); //將輸入框清空 |
4 |
$element ->getAttribute( 'value' ); //獲取輸入框的文本內容 |
2.單選框
1 |
$radio = $driver ->findElement(WebDriverBy::id( 'BookMode' )); |
2 |
$radio ->click(); //選擇某個單選項 |
3 |
$radio ->isSelected(); //判斷某個單選項是否已經被選擇 |
3.多選框
1 |
$checkbox = $driver ->findElement(WebDriverBy::id( 'myCheckbox' )); |
2 |
$checkbox ->click(); //選擇某選項 |
3 |
$checkbox ->isSelected(); //判斷該選項是否已經被選擇 |
4 |
$checkbox ->isEnabled(); //判斷是否enable |
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' )); |
2 |
$btn ->click(); //點擊按鈕 |
3 |
$btn ->isEnabled(); //判斷是否enable |
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事件進行監聽。
01
//用webdriver獲取對象,再進行JS操作
02
$ele
=
$driver
->findElement(WebDriverBy::id(
'haha'
));
03
$driver
->executeScript(
"arguments[0].click();"
,[
$ele
]);
04
05
//用JS獲取對象進行操作
06
$js
= <<<js
07
var
ele = document.getElementById(
'haha'
);
08
ele.click();
09
js;
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秒。
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
// start Firefox with 5 second timeout |
09 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
10 |
$waitSeconds = 15; //需等待加載的時間,一般加載時間在0-15秒,如果超過15秒,報錯。 |
11 |
$capabilities = DesiredCapabilities::chrome(); |
12 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
13 |
$driver ->get( 'https://www.baidu.com/' ); |
14 |
15 |
//由於下拉框是通過點擊“搜索設置”按鈕觸發JS動態生成的DOM,所以這里使用Wait for new element to appear方式,不然直接調用查找元素會報錯,說找不到元素 |
16 |
$driver ->wait( $waitSeconds )->until( |
17 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
18 |
WebDriverBy::id( 'kw' ) |
19 |
) |
20 |
); |
21 |
$driver ->findElement(WebDriverBy::id( 'kw' ))->sendKeys( 'wwe' ); |
22 |
echo 'done!' ; |
23 |
//關閉瀏覽器 |
24 |
//$driver->quit(); |
25 |
26 |
?> |
隱性等待
隱性等待是指當要查找元素,而這個元素沒有馬上出現時,告訴WebDriver查詢Dom一定時間。默認值是0,但是設置之后,這個時間將在WebDriver對象實例整個生命周期都起作用。上面的代碼就變成了這樣:
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
// start Firefox with 5 second timeout |
09 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
10 |
$capabilities = DesiredCapabilities::chrome(); |
11 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
12 |
$driver ->manage()->timeouts()->implicitlyWait(15); //隱性設置15秒 |
13 |
$driver ->get( 'https://www.baidu.com/' ); |
14 |
15 |
$driver ->findElement(WebDriverBy::id( 'kw' ))->sendKeys( 'wwe' ); |
16 |
echo 'done!' ; |
17 |
18 |
//關閉瀏覽器 |
19 |
//$driver->quit(); |
20 |
21 |
?> |
JS調用
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
14 |
$driver ->get( 'https://www.baidu.com/' ); |
15 |
16 |
$element = $driver ->findElement(WebDriverBy::className( 's_ipt' )); |
17 |
18 |
$js = <<<js |
19 |
document.getElementById( "kw" ).style.border = '2px solid red' ; |
20 |
var button = document.getElementById( "su" ); |
21 |
button.setAttribute( 'type' , 'button' ); |
22 |
button.setAttribute( 'onclick' , 'document.getElementById("kw").style.border = "2px solid blue";alert("hello,dear wangkun!");' ); |
23 |
js; |
24 |
$driver ->executeScript( $js ); |
25 |
echo 'done!' ; |
26 |
27 |
//關閉瀏覽器 |
28 |
//$driver->quit(); |
29 |
30 |
?> |
驗證碼識別
有些網站打開后,有驗證碼需要填寫,而我們又不能直接獲取該驗證碼的遠程地址,然后下載,這樣的話就相當於又請求了一次,那么驗證碼又被更新了,就達不到我們識別驗證碼的效果。
而我們的方案是通過網頁截圖,然后找到驗證碼的具體位置,然后再截圖方式把驗證碼圖片獲取到。廢話不多說,直接開始!
示例腳本:
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
const vcodeDst = 'f://vcode.png' ; //驗證碼存放地址 |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
14 |
$driver ->get( 'http://www.yimuhe.com/' ); |
15 |
16 |
$driver ->manage()->window()->maximize(); //將瀏覽器最大化 |
17 |
$driver ->takeScreenshot(vcodeDst); //截取當前網頁,該網頁有我們需要的驗證碼 |
18 |
$element = $driver ->findElement(WebDriverBy::id( 'vcode_img' )); |
19 |
generateVcodeIMG( $element ->getLocation(), $element ->getSize(),vcodeDst); |
20 |
21 |
echo 'done!' ; |
22 |
23 |
//關閉瀏覽器 |
24 |
$driver ->quit(); |
25 |
26 |
/** |
27 |
* 生成驗證碼圖片 |
28 |
* @param $location 驗證碼x,y軸坐標 |
29 |
* @param $size 驗證碼的長寬 |
30 |
*/ |
31 |
function generateVcodeIMG( $location , $size , $src_img ){ |
32 |
$width = $size ->getWidth(); |
33 |
$height = $size ->getHeight(); |
34 |
$x = $location ->getX(); |
35 |
$y = $location ->getY(); |
36 |
|
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 ); |
41 |
chmod ( $src_img ,0777); |
42 |
imagedestroy( $src ); |
43 |
imagedestroy( $dst ); |
44 |
} |
45 |
?> |
備注:當我們已經把正確的驗證碼圖片下載到了本地后,不管是用自己寫的OCR程序進行識別還是用第三方程序進行識別都可以,這個就比較簡單了,就不在這里進行陳述。
這里推薦一個比較准確的第三方驗證碼識別的程序,集成一下就可以了。
https://www.juhe.cn/docs/api/id/60/aid/344
frame與彈窗的控制
對於web應用,經常會出現框架(frame) 或窗口(window)的應用,這也就給我們的定位帶來了一個難題。有時候我們定位一個元素,定位器沒有問題,但一直定位不了,這時候就要檢查這個元素是否在一個frame中,seelnium webdriver 提供了這樣的方法,可以很輕松的來解決這個問題。
- $driver->switchTo()->frame(“id”)
- $driver->switchTo()->window(“id”)
- $driver->switchTo()->alert()
frame示例腳本
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
12 |
$capabilities = DesiredCapabilities::chrome(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
14 |
$driver ->manage()->timeouts()->implicitlyWait(15); //隱性設置15秒 |
15 |
$driver ->get( 'https://v.qq.com/x/cover/e7hi6lep1yc51ca.html?vid=h0018p9ihom' ); |
16 |
17 |
echo $driver ->getCurrentURL(). '\r\n' ; |
18 |
19 |
20 |
//將頁面滾動條拖到底部 |
21 |
//因為這個頁面默認打開的時候,"評論區"的iframe沒有渲染到DOM里,騰訊做的處理是拖動到底部的時候用JS動態渲染,所以我們需要控制瀏覽器滾動至底部 |
22 |
$js = "window.scrollBy(0,100000000);" ; |
23 |
$driver ->executeScript( $js ); |
24 |
sleep(3); |
25 |
26 |
#再找到其下面的 iframe(id=commentIframe) |
27 |
$driver ->switchTo()->frame( "commentIframe" ); |
28 |
$str = $driver ->getPageSource(); |
29 |
30 |
//將獲取到的影評數據保存再本地,再測試是否正確。 |
31 |
$myfile = fopen ( "d://newfile.html" , "w" ) or die ( "Unable to open file!" ); |
32 |
fwrite( $myfile , $str ); |
33 |
fclose( $myfile ); |
34 |
35 |
echo 'done!' ; |
36 |
37 |
//關閉瀏覽器 |
38 |
$driver ->quit(); |
39 |
40 |
?> |
alert示例腳本
1 |
<?php |
2 |
//~~~以上代碼省略... |
3 |
$driver ->switchTo()->alert()->accept(); //獲取到confim alert,並且點擊同意 |
4 |
$driver ->switchTo()->alert()->dismiss(); //取消 |
5 |
$driver ->switchTo()->alert()-> getText (); //獲取alert彈出的提示內容 |
6 |
?> |
我們以百度的頁面為例來演示一下功能。
1.點擊百度的設置
2.選擇”每天顯示多少條”的下拉框 (這個順便把“元素操作”文章中的“select”元素章節也演示了)
3.點擊保存設置按鈕:會彈出一個alert彈窗
4.執行點擊alert的確定按鈕
5.試一下搜索的結果是否變化,操作完畢
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
12 |
$waitSeconds = 15; //需等待加載的時間,一般加載時間在0-15秒,如果超過15秒,報錯。 |
13 |
$capabilities = DesiredCapabilities::chrome(); |
14 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
15 |
$driver ->get( 'https://www.baidu.com/' ); |
16 |
17 |
18 |
$driver ->findElement(WebDriverBy::linkText( '設置' ))->click(); |
19 |
20 |
$driver ->findElement(WebDriverBy::linkText( '搜索設置' ))->click(); |
21 |
22 |
$warpper = $driver ->findElement(WebDriverBy::id( 'wrapper' )); |
23 |
24 |
25 |
//由於下拉框是通過點擊“搜索設置”按鈕觸發JS動態生成的DOM,所以這里使用Wait for new element to appear方式,不然直接調用查找元素會報錯,說找不到元素 |
26 |
$driver ->wait( $waitSeconds )->until( |
27 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
28 |
WebDriverBy::id( 'nr' ) |
29 |
) |
30 |
); |
31 |
32 |
$selectDom = $warpper ->findElement(WebDriverBy::id( 'nr' )); |
33 |
$select = new WebDriverSelect( $selectDom ); |
34 |
$select ->selectByValue(10); |
35 |
36 |
//由於下拉框是通過點擊“搜索設置”按鈕觸發JS動態生成的DOM,所以這里使用Wait for new element to appear方式,不然直接調用查找元素會報錯,說找不到元素 |
37 |
$driver ->wait( $waitSeconds )->until( |
38 |
WebDriverExpectedCondition::visibilityOfElementLocated( |
39 |
WebDriverBy::linkText( '保存設置' ) |
40 |
) |
41 |
); |
42 |
43 |
$driver ->findElement(WebDriverBy::linkText( '保存設置' ))->click(); |
44 |
45 |
sleep(2); |
46 |
47 |
$driver ->switchTo()->alert()->accept(); |
48 |
49 |
$driver ->findElement(WebDriverBy::id( "kw" ))->sendKeys( 'wwe' ); |
50 |
$driver ->findElement(WebDriverBy::id( "su" ))->click(); |
51 |
52 |
echo 'done!' ; |
53 |
54 |
//關閉瀏覽器 |
55 |
//$driver->quit(); |
56 |
57 |
?> |
window彈窗 示例腳本
1 |
//$driver->switchTo()->window("id"),用法與 frame 相同。 |
AJAX分頁數據獲取
有時候有些列表頁使用的是滾動條到最底部才加載下一頁的數據,這個時候就需要用到selenium來操作這樣的數據。我們拿letv的分頁來做測試。
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
// start Firefox with 5 second timeout |
09 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
10 |
$capabilities = DesiredCapabilities::chrome(); |
11 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
12 |
$driver ->manage()->timeouts()->implicitlyWait(15); //隱性設置15秒 |
13 |
$driver ->get( 'http://list.le.com/listn/c1_t-1_a50071_y-1_s1_lg-1_ph-1_md_o4_d1_p.html' ); |
14 |
15 |
//翻一頁 |
16 |
js = "window.scrollTo(0,document.body.scrollHeight)" //滾動至底部 |
17 |
//$js = "window.scrollBy(0,100000000);"; //也可以把值設大一點,達到底部的效果 |
18 |
$driver ->executeScript( $js ); |
19 |
20 |
echo 'sleep...' ; |
21 |
sleep(6); |
22 |
23 |
//再翻一頁 |
24 |
js = "window.scrollTo(0,document.body.scrollHeight)" ; |
25 |
$driver ->executeScript( $js ); |
26 |
27 |
echo 'sleep...' ; |
28 |
sleep(6); |
29 |
30 |
//再翻一頁 |
31 |
js = "window.scrollTo(0,document.body.scrollHeight)" ; |
32 |
$driver ->executeScript( $js ); |
33 |
34 |
echo 'done!' ; |
35 |
36 |
//關閉瀏覽器 |
37 |
//$driver->quit(); |
38 |
39 |
?> |
PhantomJS
用瀏覽器驅動的方式,很方便我們在測試階段調試代碼正確性,但是由於瀏覽器要啟動,解析DOM、JS、下載圖片等,使得程序跑起來的效率並不高,這個時候我們就需要用到Phantomjs,以后台的形式運行程序,大大的提升運行的性能。
1.安裝Phantomjs
到http://phantomjs.org/download.html 上面去下載對應的版本,我這里下載的是windows版本的。將解壓包中的phantomjs.exe放到PHP程序根目錄,或將該exe加入到本機的環境變量中都行。
2.使用Phantomjs
拿的是“驗證碼識別”那篇文章的代碼,只改了一處,$capabilities = DesiredCapabilities::phantomjs();這一行。
運行后,可以看到“驗證碼識別”程序不再啟動chrome瀏覽器,而是后台執行,速度也快了很多。程序順利跑出了我們想要的結果~ 大家可以休息一下咯~
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\DesiredCapabilities; |
04 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
const vcodeDst = 'f://vcode.png' ; //驗證碼存放地址 |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
12 |
$capabilities = DesiredCapabilities::phantomjs(); |
13 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
14 |
$driver ->get( 'http://www.yimuhe.com/' ); |
15 |
16 |
$driver ->manage()->window()->maximize(); //將瀏覽器最大化 |
17 |
$driver ->takeScreenshot(vcodeDst); //截取當前網頁,該網頁有我們需要的驗證碼 |
18 |
$element = $driver ->findElement(WebDriverBy::id( 'vcode_img' )); |
19 |
generateVcodeIMG( $element ->getLocation(), $element ->getSize(),vcodeDst); |
20 |
21 |
echo 'done!' ; |
22 |
23 |
//關閉瀏覽器 |
24 |
$driver ->quit(); |
25 |
26 |
/** |
27 |
* 生成驗證碼圖片 |
28 |
* @param $location 驗證碼x,y軸坐標 |
29 |
* @param $size 驗證碼的長寬 |
30 |
*/ |
31 |
function generateVcodeIMG( $location , $size , $src_img ){ |
32 |
$width = $size ->getWidth(); |
33 |
$height = $size ->getHeight(); |
34 |
$x = $location ->getX(); |
35 |
$y = $location ->getY(); |
36 |
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 ); |
41 |
chmod ( $src_img ,0777); |
42 |
imagedestroy( $src ); |
43 |
imagedestroy( $dst ); |
44 |
} |
45 |
?> |
屏蔽圖片
1. 查看chrome支持的瀏覽器屬性
chrome driver的官方文檔( https://sites.google.com/a/chromium.org/chromedriver/capabilities ),可以看到,chrome driver可以支持的自定義屬性

2. 查看本地配置的參數值
可以使用自己的chrome瀏覽器進行配置,配置好了后,查看“Preferences文件”里的值就可以了。一般路徑都為“用戶文件夾\AppData\Local\Google\Chrome\User Data\Default”。



3. 代碼DEMO
找到了屏蔽圖片對應的參數后,我們就可以進行測試了
01
$host
=
'http://localhost:4444/wd/hub'
; // this is the
default
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
);
07
08
$driver
= RemoteWebDriver::create(
$host
,
$capabilities
, 5000);
09
$driver
->manage()->timeouts()->implicitlyWait(15);
//隱性設置15秒
10
11
$driver
->get(
'http://www.baidu.com/'
);
12
13
echo
'done'
;
4. 換個思路,變得更簡潔
上面提到的都是設置具體的參數,而要找到對應設置的參數比較繁雜,當如果不想那么麻煩時候,完全可以在已有的chrome瀏覽器先設置好,然后把“用戶文件夾\AppData\Local\Google\Chrome\User Data”加載到自己的應用中。
01
$host
=
'http://localhost:4444/wd/hub'
; // this is the
default
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
);
06
07
$driver
= RemoteWebDriver::create(
$host
,
$capabilities
, 5000);
08
$driver
->manage()->timeouts()->implicitlyWait(15);
//隱性設置15秒
09
10
$driver
->get(
'http://www.baidu.com/'
);
11
12
echo
'done'
;
總結:這里雖然只是介紹的屏蔽圖片,但是同理的chrome其他設置也可以用這樣的方式進行,如禁用JS等等之類的。
使用擴展插件
有時候我們需要使用瀏覽器的擴展插件來幫助我們達到某種特定的效果,比如“Block Image”插件可使得selenium使用過程中不顯示圖片,從而加快訪問的速度和性能。再比如使用“adsafe”插件可使得訪問網站的時候禁用相應的廣告以及彈窗廣告等。
這里我們使用”Block Image”插件的來展示下selenium怎么加載插件。這里使用的是chrome driver方式進行測試,其他瀏覽器的測試代碼請自行百度。
1.下載Block Image插件
到http://www.cnplugins.com/ 上面搜索Block Image,下載下來,存放到自己的程序根目錄。
2.代碼測試
01 |
<?php |
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' ); |
07 |
08 |
header( "Content-Type: text/html; charset=UTF-8" ); |
09 |
10 |
// start Firefox with 5 second timeout |
11 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
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); //隱性設置15秒 |
代理設置
1.修改User Agent
Chrome 示例
這里提供user-agent大全供參考http://www.cnblogs.com/hykun/p/Ua.html
01
<?php
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'
);
07
08
header(
"Content-Type: text/html; charset=UTF-8"
);
09
10
// start Firefox with 5 second timeout
11
$host
=
'http://localhost:4444/wd/hub'
; // this is the
default
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
);
17
18
$driver
= RemoteWebDriver::create(
$host
,
$capabilities
, 5000);
19
$driver
->manage()->timeouts()->implicitlyWait(15);
//隱性設置15秒
20
$driver
->get(
'http://www.atool.org/useragent.php'
);
21
var_dump(
$capabilities
->getCapability(ChromeOptions::CAPABILITY));
22
echo
'done!'
;
23
24
//關閉瀏覽器
25
//$driver->quit();
26
?>
Phantomjs 示例
01
<?php
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'
);
07
08
header(
"Content-Type: text/html; charset=UTF-8"
);
09
10
// start Firefox with 5 second timeout
11
$host
=
'http://localhost:4444/wd/hub'
; // this is the
default
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
);
15
16
$driver
= RemoteWebDriver::create(
$host
,
$capabilities
, 5000);
17
$driver
->manage()->timeouts()->implicitlyWait(15);
//隱性設置15秒
18
$driver
->get(
'http://www.atool.org/useragent.php'
);
19
echo
$driver
->findElement(WebDriverBy::id(
'ua_code'
))->getAttribute(
'value'
);
20
echo
'done!'
;
21
22
//關閉瀏覽器
23
$driver
->quit();
24
?>
2.修改代理IP
01 |
<?php |
02 |
namespace Facebook\WebDriver; |
03 |
use Facebook\WebDriver\Remote\RemoteWebDriver; |
04 |
use Facebook\WebDriver\Remote\WebDriverCapabilityType; |
05 |
require_once ( 'vendor/autoload.php' ); |
06 |
07 |
header( "Content-Type: text/html; charset=UTF-8" ); |
08 |
$host = 'http://localhost:4444/wd/hub' ; // this is the default |
09 |
$ip = '115.225.2.3:8998' ; //設置代理IP |
10 |
$capabilities = array (WebDriverCapabilityType::BROWSER_NAME => 'chrome' , |
11 |
WebDriverCapabilityType::PROXY => array ( 'proxyType' => 'manual' , |
12 |
'httpProxy' => $ip , 'sslProxy' => $ip )); |
13 |
14 |
$driver = RemoteWebDriver::create( $host , $capabilities , 5000); |
15 |
$driver ->manage()->timeouts()->implicitlyWait(15); //隱性設置15秒 |
16 |
$driver ->get( 'https://www.baidu.com/' ); |
17 |
$driver ->findElement(WebDriverBy::id( 'kw' ))->sendKeys( 'ip' ); |
18 |
$driver ->findElement(WebDriverBy::id( 'su' ))->click(); |
19 |
echo 'done!' ; |
20 |
//關閉瀏覽器 |
21 |
//$driver->quit(); |
22 |
23 |
?> |
使用總結
使用selenium時會遇到很多的坑,這里分享一些經驗給大家。
1.wait ~ until的使用
要勤使用wait~until,由於我們打開的網頁有時候會比較慢時,查找調用某個元素時就比較容易報NoSuchElementException異常。或者有時候一些JS是動態生成的,也需要用到wait~until,不然也會報錯。
2.switchToEndWindow勤使用
switchToEndWindow是我們自定義的一個方法,由於我們使用selenium訪問某個網頁,然后又點擊了其中一個鏈接,誰知道這個鏈接是否含有target=”_blank”呢。做爬蟲類程序尤為如此。所以我們增加一個方法,每次點擊了某個鏈接跳轉后,執行一下switchToEndWindow方法。
01
<?php
02
//切換至最后一個window
03
function
switchToEndWindow(
$driver
){
04
05
$arr
=
$driver
->getWindowHandles();
06
foreach
(
$arr
as
$k
=>
$v
){
07
if
(
$k
== (
count
(
$arr
)-1)){
08
$driver
->switchTo()->window(
$v
);
09
}
10
}
11
}
12
?>
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,隱藏掉就可以了。
1
$js
= <<<js
2
var
nav = document.getElementsByClassName(
"nav_m"
);
3
nav[0].style.display =
'none'
;
4
js;
5
$driver
->executeScript(
$js
);
如果以上兩種方式結合都還有問題的情況下,就建議用JS來解決。
01
//設置屏幕滾動到當前元素
02
$elems
=
$driver
->findElements(WebDriverBy::className(
'n'
));
03
foreach
(
$elems
as
$elem
){
04
if
(CommonUtil::contain(
$elem
->
getText
(),
'下一頁'
)){
05
$elem
->sendKeys(
'xxx'
);
//設置焦點
06
}
07
}
08
09
10
$js
= <<<js
11
var
next = document.getElementsByClassName(
'n'
);
12
for
(i = 0; i < next.length; i++) {
13
if
(next[i].innerHTML ==
'下一頁>'
){
14
//next[i].click();
15
next[i].style.backgroundColor =
"red"
;
16
}
17
}
18
js;
19
20
$driver
->executeScript(
$js
);
//JS執行點擊下一頁
5.執行時間的設置
使用自動化測試或爬蟲程序,往往程序執行的時間會比較長。為了防止timeout,我們需要設置如下
1
set_time_limit(0);
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
元素定位
1. WebDriverBy::id()
通過ID屬性定位元素
1
//HTML代碼
2
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::id(
'kw'
));
8
?>
2. WebDriverBy::name()
通過name屬性定位元素。如果查找多個,則使用findElements進行定位
01
//HTML代碼
02
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
03
04
<?php
05
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
06
$driver
->get(
'https://www.baidu.com/'
);
07
$element
=
$driver
->findElement(WebDriverBy::name(
'wd'
));
08
foreach
(
$elements
as
$elem
){
//有時候多個元素時,想找出某個特定元素,可根據attribute或text進行判斷過濾
09
echo
$elem
->getAttribute(
'type'
);
10
echo
$elem
->
getText
();
11
}
12
?>
3. WebDriverBy::tagName()
通過標簽進行定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
01
//HTML代碼
02
//<input type="hidden" name="rsv_bp" value="0" />
03
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
04
//.....
05
06
<?php
07
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
08
$driver
->get(
'https://www.baidu.com/'
);
09
$element
=
$driver
->findElement(WebDriverBy::tagName(
'input'
));
10
?>
4. WebDriverBy::className()
通過css類進行定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<input id="kw" name="wd" class="s_ipt" maxlength="255" autocomplete="off" />
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::className(
's_ipt'
));
8
?>
5. WebDriverBy::linkText()
通過超文本鏈接上的文字信息來定位元素。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a>
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::linkText(
'新聞'
));
8
?>
6. WebDriverBy::partialLinkText()
這個方法是上一個方法的擴展。當你不能准確知道超鏈接上的文本信息或者只想通過一些關鍵字進行匹配時,可以使用這個方法來通過部分鏈接文字進行匹配。如果查找多個,則使用findElements進行定位,具體參考WebDriverBy::name()的代碼
1
//HTML代碼
2
//<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新聞</a>
3
4
<?php
5
$driver
= RemoteWebDriver::create(
$host
, DesiredCapabilities::chrome(), 5000);
6
$driver
->get(
'https://www.baidu.com/'
);
7
$element
=
$driver
->findElement(WebDriverBy::partialLinkText(
'新'
));
8
?>
7. WebDriverBy::xpath()
這個方法是非常強大的元素查找方式,使用這種方法幾乎可以定位到頁面上的任意元素。在正式開始使用XPath進行定位前,我們先了解下什么是XPath。XPath是XML Path的簡稱,由於HTML文檔本身就是一個標准的XML頁面,所以我們可以使用XPath的語法來定位頁面元素。更多詳細的定位資料,參考頁腳鏈接地址。
XPath語法如下:
1 |
<?php |
2 |
$element = $driver ->findElement(WebDriverBy::xpath( "//*[@id='J_login_form']/dl/dt/input[@id='J_password']" )); |
3 |
?> |