# selenium和phantomJS
——編輯:大牧莫邪
### 目錄清單
- [x].selenium和phantomjs概述
- [x].selenium常用API
- [x].案例操作:模擬登陸csdn
### 課程內(nèi)容
#### 1. selenium和phantomJS是什么東西
selenium是一套web網(wǎng)站自動(dòng)化測(cè)試工具,主要通過(guò)命令行的操作完成常規(guī)可視化界面下的用戶各種操作行為,因?yàn)槠浜?jiǎn)單易學(xué)成本低,并且執(zhí)行測(cè)試效率較高而在web自動(dòng)化測(cè)試方面比較突出,該庫(kù)可以直接運(yùn)行操作各種主流瀏覽器,輔助瀏覽器自動(dòng)完成表單互動(dòng)、鼠標(biāo)點(diǎn)擊、鼠標(biāo)拖拽、窗口切換等等各種用戶行為,是一套非常好用且強(qiáng)大的測(cè)試庫(kù),但是selenium沒(méi)有內(nèi)置的瀏覽器模塊,不能獨(dú)立運(yùn)行,必須要和第三方瀏覽器配合使用才可以完成自動(dòng)化測(cè)試操作。
在實(shí)際操作的過(guò)程中,經(jīng)常使用selenium和各大主流瀏覽器共同操作,如谷歌、火狐、IE等等,但是在selenium自動(dòng)化測(cè)試發(fā)展過(guò)程中,有一個(gè)特殊的瀏覽器經(jīng)常用于和它配合使用,就是比較出名的無(wú)界面瀏覽器phantomJS。
#### 2. 爬蟲、selenium、phantomJS
這時(shí)候問(wèn)題就來(lái)了,爬蟲中,為什么要涉及到selenium測(cè)試工具和無(wú)界面瀏覽器這樣的東東呢?
說(shuō)來(lái)話長(zhǎng)了
> 故事背景:那是很久的以前,人們生活在一個(gè)非常平和的年代
>
>> 老李住在人民小區(qū)的一所豪宅中,人人互愛(ài)互助,路不拾遺夜不閉戶已經(jīng)成了傳統(tǒng)
> -------------
> 這天,從遙遠(yuǎn)的他鄉(xiāng)來(lái)了一個(gè)人
~老王(爬蟲),禁不住五臟廟的鬧騰,終于決定要找點(diǎn)吃的了,他一路獨(dú)行直接進(jìn)來(lái)了老李家,把老李留給媳婦的無(wú)骨燉雞湯給吃了個(gè)精光,然后施施然瀟灑的離去了..
> [ ** 爬蟲老王,根據(jù)自己需要的數(shù)據(jù)對(duì)于網(wǎng)站服務(wù)器老李進(jìn)行了數(shù)據(jù)采集,服務(wù)器沒(méi)有任何防范,數(shù)據(jù)直接被獲取到了! **]
> -------------
> 老李終于回家了,發(fā)現(xiàn)有人動(dòng)了他的雞湯....于是,晚上老李家傳來(lái)了老李的慘叫聲.
> 老李吸取教訓(xùn),應(yīng)該是有小區(qū)之外的人進(jìn)了小區(qū),于是跟守門大媽說(shuō)了一句,以后進(jìn)門的人一定要問(wèn)問(wèn)有木有門卡(備注:門卡是小區(qū)住戶才有的一種身份卡片),有卡才讓進(jìn)小區(qū),否則不允許進(jìn)入
> [ ** 服務(wù)器老李由于數(shù)據(jù)無(wú)端泄露導(dǎo)致出現(xiàn)了安全問(wèn)題,于是進(jìn)行了簡(jiǎn)單的升級(jí)防范,針對(duì)所有進(jìn)行訪問(wèn)的用戶驗(yàn)證其User - agent,如果User - agent不合適則禁止訪問(wèn) **]
> -------------
> 老王這天又餓的不行了,但是進(jìn)小區(qū)時(shí)發(fā)現(xiàn)大媽竟然要查牌,好吧,~老王找到小區(qū)的某個(gè)人,請(qǐng)它吃了頓飯,順便看了看門卡長(zhǎng)的什么樣子,然后自己偷偷去做了一張一模一樣的卡片,然后
~ 老王又進(jìn)去了老李家,半夜
~小區(qū)又傳來(lái)了老李的慘叫
~~~
> [ ** 爬蟲老王通過(guò)抓包工具進(jìn)行了服務(wù)器請(qǐng)求的抓包,分析了請(qǐng)求中的各項(xiàng)參數(shù),在請(qǐng)求頭中添加了瀏覽器的User - agent的值,再次訪問(wèn)服務(wù)器,順利拿到了需要采集的數(shù)據(jù) **]
> -------------
> 老李憤慨于老王的行為,再次跟門口大媽說(shuō)了說(shuō),家里的東西又被人動(dòng)了,大媽回憶了一下這幾天的情況,發(fā)現(xiàn)老王頻繁的進(jìn)入小區(qū),于是大媽針對(duì)每天頻繁進(jìn)入小區(qū)的人單獨(dú)進(jìn)行了登記,注意防范,一旦出現(xiàn)就堅(jiān)決不允許這樣的人再進(jìn)入小區(qū)
> [ ** 服務(wù)器老李針對(duì)再次數(shù)據(jù)泄露,認(rèn)識(shí)到了可能有非法用戶多次采集數(shù)據(jù)造成的,于是針對(duì)限定時(shí)間頻繁訪問(wèn)數(shù)據(jù)的操作進(jìn)行了屏蔽,如果出現(xiàn)1分鐘內(nèi)訪問(wèn)次數(shù)超過(guò)30次的直接屏蔽ip地址 **]
>
> <> -------------
> 老王這天來(lái)到小區(qū)門口,發(fā)現(xiàn)和他一樣的老孫餓的皮包骨頭,很詫異的問(wèn)老孫什么情況,老孫據(jù)實(shí)說(shuō)了實(shí)際情況,老孫已經(jīng)進(jìn)了大媽的黑名單,再也不能進(jìn)小區(qū)覓食了!老王發(fā)現(xiàn)了這個(gè)問(wèn)題之后,于是
~每天只進(jìn)入一次小區(qū),還跟大媽很熱情的打招呼呢.....老李是徹底的憤怒了,家里的吃的雖然沒(méi)有像之前丟的那么頻繁,但是終歸還是丟了特別重要的部分,半夜時(shí)分,
老李的慘叫是那么的慘絕人寰[ ** 爬蟲老王限制了爬蟲訪問(wèn)服務(wù)器的時(shí)間,根據(jù)正常用戶的發(fā)送請(qǐng)求的時(shí)間,限制了不同爬取請(qǐng)求之間的休眠時(shí)間,盡管采集數(shù)據(jù)較慢,但是同樣得到了數(shù)據(jù) **]
>
> <> -------------
> 老李這次學(xué)乖了,出門的時(shí)候給家里上鎖了, 在也不愁數(shù)據(jù)數(shù)據(jù)再次丟失的問(wèn)題了[ ** 服務(wù)器老李在請(qǐng)求參數(shù)中,添加了一個(gè)加密字段,如果參數(shù)中包含了正確的加密字段,就允許訪問(wèn)數(shù)據(jù),如果參數(shù)中沒(méi)有標(biāo)注則拒絕訪問(wèn) **]
> ------------
> 老王已經(jīng)餓了太多天了
>
> 老王找到了傳說(shuō)中的某個(gè)大師,跟他學(xué)了曠古絕技,于是在某個(gè)艷陽(yáng)高照的晴天,再次進(jìn)了老李家....這天半夜,老李默默的坐了一個(gè)晚上[ ** 爬蟲針對(duì)加密數(shù)據(jù)進(jìn)行了分析追蹤,得到了加密
的具體流程,于是進(jìn)行了加密字段的重現(xiàn),將加密數(shù)據(jù)通過(guò)請(qǐng)求傳遞給了服務(wù)器,順利獲取到了數(shù)據(jù) **]
>
> <> -------------
> 老李根據(jù)自己的需要,換了指紋密碼鎖[ ** 服務(wù)器針對(duì)數(shù)據(jù)安全問(wèn)題,進(jìn)行了再次升級(jí),對(duì)數(shù)據(jù)進(jìn)行了混淆編碼的同時(shí),通過(guò)混淆編碼進(jìn)行了多重加密操作,同時(shí)進(jìn)行了多個(gè)字段的數(shù)字指紋簽名操作,如果請(qǐng)求中不包含這些數(shù)據(jù)的情況下,拒絕提供數(shù)據(jù) **]
>
> <> -------------
> 老王看著緊鎖的大門,想了很久....
>
> 這天老李家來(lái)了客人,好酒好菜兩人暢談甚久,夜幕時(shí)分,老王施施然從老李家走了出來(lái),
身旁就是老李相送[ ** 客戶端老王看到服務(wù)器老李已經(jīng)做了非常復(fù)雜的反爬蟲操作,于是權(quán)衡之后不再做反扒操作,直接讓自己變成了正式用戶發(fā)送請(qǐng)求,同樣獲取到了數(shù)據(jù) **]
>
> 而這里涉及到的正式用戶的請(qǐng)求,就是直接通過(guò)瀏覽器發(fā)送請(qǐng)求訪問(wèn)服務(wù)器,用到的瀏覽器就是phantomJS無(wú)界面瀏覽器,通過(guò)selenium測(cè)試工具發(fā)送請(qǐng)求操作訪問(wèn)過(guò)程獲取數(shù)據(jù)
** 準(zhǔn)備工作:selenium和PhantomJS **
** phantomjs:一個(gè)獨(dú)立的無(wú)界面瀏覽器,并不是python模塊,所以需要單獨(dú)下載安裝;phantomjs官方網(wǎng)站:http: // phantomjs.org / **
** selenium:獨(dú)立的第三方模塊,通過(guò)
`pip
install
selenium
`進(jìn)行安裝 **
#### 3. selenium核心API
*selenium.webdriver
*selenium核心驅(qū)動(dòng)模塊,主要包含了web服務(wù)相關(guān)的核心操作,可以調(diào)用指定的服務(wù)器
*如:driver = selenium.webdriver.PhantomJS()
*如:driver = selenium.webdriver.Chrome()
*接續(xù):瀏覽器填寫url地址訪問(wèn)文章:
*driver.get("http://www.baidu.com")
*接續(xù):獲取標(biāo)簽對(duì)象
*find_element_by_id()
*根據(jù)標(biāo)簽編號(hào)查詢標(biāo)簽對(duì)象
*? \ < div
id = "box" > ...\ < / div >
*driver.find_by_element_by_id("box")
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_element(by=By.ID, value='box')
*find_elements_by_name()
*根據(jù)標(biāo)簽的name屬性只查詢標(biāo)簽對(duì)象
*? \ < div
name = "real_name" >\ < / div >
*driver.find_elements_by_name("real_name")
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elemnets(by=By.NAME, value='real_name')
*find_elemnets_by_xpath()
*根據(jù)xpath語(yǔ)法查詢指定的標(biāo)簽
*driver.find_elements_by_xpath('//input[id="kw"]')
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.XPATH, value='//input[@id="kw"]')
*find_elements_by_link_text()
*根據(jù)超鏈接標(biāo)簽鏈接文本查詢標(biāo)簽
*driver.find_elements_by_link_text('damu')
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.LINK_TEXT, value='damu')
*find_elemetns_by_partial_link_text()
*根據(jù)超鏈接標(biāo)簽鏈接文本
擴(kuò)展
查詢標(biāo)簽
*driver.find_elements_by_partial_link_text('damu')
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.PARTIAL_LINK_TEXT, value='damu')
*find_elements_by_tag_name()
*根據(jù)標(biāo)簽名稱查詢標(biāo)簽
*driver.find_elements_by_tag_text('damu')
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.TAG_NAME, value='damu')
*find_elements_by_class_name()
*根據(jù)標(biāo)簽的class名稱查詢標(biāo)簽
*driver.find_elements_by_class_name("")
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.CLASS_NAME)
*find_elements_by_css_selector()
*根據(jù)標(biāo)簽的樣式名稱查詢得到標(biāo)簽
*driver.find_elements_by_css_selector("#box > div")
*同下:
* from selenium.webdriver.common.by
import By
*driver.find_elements(by=By.CSS_SELECT, value='#box')
*selenium.webdirver.common.keys.Keys
*selenium用于操作用戶鍵盤的核心模塊
*表單處理:輸入框填寫數(shù)據(jù)
*選擇輸入框:kw = driver.find_element_by_id("kw")
*輸入數(shù)據(jù):kw.send_keys(u"關(guān)鍵字")
*表單處理:下拉列表框選擇數(shù)據(jù)
* from selenium.webdriver.support.ui
import Select
*選擇下拉框:sl = Select(driver.find_element_by_id("city"))
*輸入選擇的值:
*sl.select_by_index(1)? # 根據(jù)值的索引賦值
*sl.select_by_value("zhengzhou")? # 根據(jù)具體下拉框的value賦值
*sl.select_by_visible_text("鄭州")? # 根據(jù)下拉框顯示的值賦值
*sl.deselect_all()? # 全部取消
*鍵盤按鍵:功能鍵 + 字母按鍵
* from selenium.webdriver.common.keys
import Keys
*driver.find_element_by_id("kw").send_keys(Keys.CONTROL, "a")? # ctrl+a全選
*ALT:alt按鍵
*NUMBER1:數(shù)字鍵1
*LFET:←左方向鍵
*F1:功能鍵F1
*更多more
~
*selenium.webdriver.ActionChains
*該模塊包含了和鼠標(biāo)操作相關(guān)的行為
*模擬鼠標(biāo)單擊
*driver.find_element_by_id("su").click()
*鼠標(biāo)鏈操作
* from selenium.webdriver
import ActionChains? # 引入鼠標(biāo)模塊
*su = driver.find_element_by_id("su")? # 獲取標(biāo)簽對(duì)象
*ActionChains(driver).move_to_element(su).perform()? # 鼠標(biāo)移動(dòng)到對(duì)象上
*ActionChains(driver).move_to_element(su).click(su).perform()? # 鼠標(biāo)單擊
*ActionChains(driver).move_to_element(su).double_click(su).perform()? # 鼠標(biāo)雙擊
*ActionChains(driver).move_to_element(su).context_click(su).perform()? # 鼠標(biāo)右鍵單擊
*ActionChains(driver).move_to_element(su).click_to_hold(su).perform()? # 鼠標(biāo)單擊并按住
*pos1 = driver.find_element_by_element("pos1")
*pos2 = driver.find_element_by_element("pos2")
*ActionChains(driver).drag_and_drop(pos1, pos2).perform()? # 鼠標(biāo)將pos1脫拽到pos2的位置
*頁(yè)面窗口操作
*driver.switch_to.window("window name")? # 窗口誒切換
*driver.forward()? # 導(dǎo)航前進(jìn)
*driver.back()? # 導(dǎo)航后退
*cookie操作
*driver.get_cookies()
獲取當(dāng)前正在訪問(wèn)url地址的所有cookies數(shù)據(jù)
*driver.delete_cookie(key)
根據(jù)key值刪除對(duì)應(yīng)的cookie數(shù)據(jù)
*driver.delete_all_cookies()
清空cookie
*網(wǎng)頁(yè)延時(shí):針對(duì)網(wǎng)頁(yè)中通過(guò)Ajax異步加載Json數(shù)據(jù)的情況,不同的網(wǎng)速下返回Json數(shù)據(jù)并渲染頁(yè)面會(huì)有延遲,網(wǎng)頁(yè)中并不一定能正常獲取數(shù)據(jù),需要延時(shí)操作
*顯式等待
```
# coding:utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdirver.support import except_conditions as EC
driver = webdriver.PhantomJS()
driver.get("http://www.baidu.com")
try:
? ? # 獲取標(biāo)簽:間隔10S獲取標(biāo)簽~一直等待到標(biāo)簽獲取成功
? ? element = WebDriverWait(driver, 10).until(
? ? ? ? EC.presence_of_element_located((By.ID, "box"))
? ? )
finally:
? ? driver.quit()
```
這里的等待條件,就是
`except_conditions`
調(diào)用時(shí)執(zhí)行的函數(shù),內(nèi)置如下條件可以直接調(diào)用
```
title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable – it is Displayed and Enabled.
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present
```
*隱時(shí)等待:設(shè)置一個(gè)等待時(shí)間即可
```
# coding:utf-8
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
driver.find_element_by_id("su")
```
以上,是selenium核心的幾個(gè)API操作方式
####? 案例:CSDN登錄
真實(shí)用戶登錄CSDN場(chǎng)景:
*用戶打開(kāi)瀏覽器,訪問(wèn)并打開(kāi)csdn登錄網(wǎng)頁(yè)
*填寫賬號(hào)、密碼,點(diǎn)擊登錄
*進(jìn)入CSDN主頁(yè)
selenium配合phantomjs完成登錄操作,并保存數(shù)據(jù)到文件中
```
# coding:utf-8
from selenium import webdriver
driver = webdriver.PhantomJS("./phantomjs-2.1.1/bin/phantomjs")
# 訪問(wèn)登錄頁(yè)面
driver.get("https://passport.csdn.net/account/login?ref=toolbar")
# 保存登錄頁(yè)面截圖
driver.save_screenshot("csdn1.png")
# 獲取登錄 用戶輸入框、密碼輸入框
u_name = driver.find_element_by_id("username").send_keys("damumoye")
p_word = driver.find_element_by_id("password").send_keys("********")
# 模擬點(diǎn)擊登錄
login_btn = driver.find_element_by_css_selector("#fm1 .logging")
login_btn.click()
# 保存登錄后的截圖
driver.save_screenshot("csdn2.png")
# 保存數(shù)據(jù)
with open("csdn.html", "w") as f:
? ? f.write(driver.page_source.encode("utf-8"))
# 退出瀏覽器
driver.quit()