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