selenium
selenium是一個支持各大瀏覽器的自動化測試工具,包括 Chrome,Safari,Firefox ,ie等。再構造爬蟲時,如果我們加入了User-Agent,那么變偽裝成了瀏覽器,可以騙過一些技術水平不太高的網站。但如果使用selenium,則就不是偽裝瀏覽器,而是真正的用瀏覽器去訪問。有時我們可能會遇到這種情況,前端頁面展示出來的東西,並不在后端源代碼中,自然無法通過使用requests請求獲得源碼進行爬取。這時候就可以使用selenium進行爬取數據,因為他就是用真實的瀏覽器去訪問頁面的,所以出現的內容和我們在前端看到的是一模一樣的。
0x01:selenium安裝
python下使用pip安裝
pip install selenium
此外,因為selenium是配合瀏覽器一起使用,所以需要下載瀏覽器的驅動(webdriver),以chrome為例
chrome的webdriver: http://chromedriver.storage.googleapis.com/index.html
不同的Chrome的版本對應的chromedriver.exe 版本也不一樣,下載時不要搞錯了。如果是最新的Chrome, 下載最新的chromedriver.exe 就可以了。把chromedriver的路徑也加到環境變量里。
檢測:運行這段代碼,會自動打開百度
from selenium import webdriver # 引入webdriver api
driver = webdriver.Chrome() # 使用chrome瀏覽器聲明一個webdriver對象
driver.get('http://www.baidu.com/') # 表示使用chrome以get的方式請求百度的url
driver.find_element_by_id("kw").send_keys("selenium") # 檢索到百度的輸入框,輸入selenium
driver.find_element_by_id("su").click() # 檢索到百度的搜索按鈕並點擊
0x02:元素選取
在上面的實例中,最重要的就是找到搜索框和搜索按鈕對應的元素,然后再進行相應的操作(輸入關鍵字、點擊),強大的selenium提供了多種提取元素的方法。
單個元素提取
find_element_by_id # 通過元素id
find_element_by_name # 通過name屬性
find_element_by_xpath # 通過xpath
find_element_by_link_text # 通過鏈接文本
find_element_by_partial_link_text
find_element_by_tag_name # 通過標簽名
find_element_by_class_name # 通過class名稱定位
find_element_by_css_selector # 通過css選擇器定位
多個元素提取
,返回一個列表
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
0x03:操作元素方法
- clear 清除元素的內容:clear(self)
- send_keys 模擬按鍵輸入:send_keys(self, *value)
- click 點擊元素:click(self)
- submit 提交表單:submit(self)
- 獲取元素屬性:get_attribute(self, name)
- 獲取元素文本:text
0x04:頁面操作方法
from selenium import webdriver
- 打開瀏覽器:driver = webdriver.Chrome()
- 請求一個url:driver.get("www.baidu.com")
- 返回當前頁面的title:title = driver.title
- 返回當前頁面的url:url = driver.current_url
- 返回當前頁面的源碼:source = driver.page_source
- 關閉當前頁面:driver.close()
- 注銷並關閉瀏覽器:driver.quit()
- 瀏覽器前進:driver.forward()
- 瀏覽器后退:driver.back()
- 刷新當前頁面:driver.refresh()
- 獲取當前session中的全部cookie:get_cookies(self)
- 獲取當前會中中的指定cookie:get_cookie(self, name)
- 在當前會話中添加cookie:add_cookie(self, cookie_dict)
- 添加瀏覽器User-Agent:
options.add_argument('User-Agent=Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30') - 添加設置項Chrome Options:
options = webdriver.ChromeOptions()
options.add_argument('xxxx')
driver = webdriver.Chrome(chrome_options=options)
0x05:頁面等待
既然selenium是使用瀏覽器發送請求,那么勢必會加載一些東西,而且現在的網頁越來越多采用了ajax技術。如果代碼運行到了提取元素的地方,而這個元素尚未被加載,那么就會報錯。為了解決這個問題,selenium提供了兩種等待方式,隱式等待
、顯示等待
。隱式等待是等待特定的時間,顯式等待是指定某一條件直到這個條件成立時繼續執行。
-
隱式等待
隱式等待比較簡單,就是簡單地設置一個等待時間,單位為秒。from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(10) # seconds driver.get("http://somedomain/url_that_delays_loading") myDynamicElement = driver.find_element_by_id("myDynamicElement")
-
顯式等待
顯式等待指定某個條件,然后設置最長等待時間。如果在這個時間還沒有找到元素,那么便會拋出異常了。from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait driver = webdriver.Chrome() driver.get("http://somedomain/url_that_delays_loading") try: element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) ) finally: driver.quit()
wait模塊的WebDriverWait類是顯性等待類,參數如下:
WebDriverWait(driver, 超時時長, 調用頻率, 忽略異常).until(可執行方法, 超時時返回的信息)
這里需要特別注意的是until或until_not中的可執行方法method參數,很多人傳入了WebElement對象,如下:
WebDriverWait(driver, 10).until(driver.find_element_by_id('kw')) # 錯誤
這是錯誤的用法,這里的參數一定要是可以調用的,即這個對象一定有 call() 方法,否則會拋出異常:
TypeError: 'xxx' object is not callable
在這里,你可以用selenium提供的 expected_conditions 模塊中的各種條件,也可以用WebElement的 is_displayed() 、is_enabled()、is_selected() 方法,或者用自己封裝的方法都可以。那么接下來我們看一下selenium提供的條件有哪些:
expected_conditions:
xpected_conditions是selenium的一個模塊,其中包含一系列可用於判斷的條件:
selenium.webdriver.support.expected_conditions(模塊)
這兩個條件類驗證title,驗證傳入的參數title是否等於或包含於driver.title
title_is
title_contains
這兩個人條件驗證元素是否出現,傳入的參數都是元組類型的locator,如(By.ID, 'kw')
顧名思義,一個只要一個符合條件的元素加載出來就通過;另一個必須所有符合條件的元素都加載出來才行
presence_of_element_located
presence_of_all_elements_located
這三個條件驗證元素是否可見,前兩個傳入參數是元組類型的locator,第三個傳入WebElement
第一個和第三個其實質是一樣的
visibility_of_element_located
invisibility_of_element_located
visibility_of
這兩個人條件判斷某段文本是否出現在某元素中,一個判斷元素的text,一個判斷元素的value
text_to_be_present_in_element
text_to_be_present_in_element_value
這個條件判斷frame是否可切入,可傳入locator元組或者直接傳入定位方式:id、name、index或WebElement
frame_to_be_available_and_switch_to_it
這個條件判斷是否有alert出現
alert_is_present
這個條件判斷元素是否可點擊,傳入locator
element_to_be_clickable
這四個條件判斷元素是否被選中,第一個條件傳入WebElement對象,第二個傳入locator元組
第三個傳入WebElement對象以及狀態,相等返回True,否則返回False
第四個傳入locator以及狀態,相等返回True,否則返回False
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
最后一個條件判斷一個元素是否仍在DOM中,傳入WebElement對象,可以判斷頁面是否刷新了
staleness_of
上面是所有17個condition,與until、until_not組合能夠實現很多判斷,如果能自己靈活封裝,將會大大提高腳本的穩定性。
0x06:鼠標操作
在現實的自動化測試中關於鼠標的操作不僅僅是click()單擊操作,還有很多包含在ActionChains類中的操作。如下:
- context_click(elem) 右擊鼠標點擊元素elem,另存為等行為
- double_click(elem) 雙擊鼠標點擊元素elem,地圖web可實現放大功能
- drag_and_drop(source,target) 拖動鼠標,源元素按下左鍵移動至目標元素釋放
- move_to_element(elem) 鼠標移動到一個元素上
- click_and_hold(elem) 按下鼠標左鍵在一個元素上
- perform() 在通過調用該函數執行ActionChains中存儲行為
舉例如下圖所示,獲取通過鼠標右鍵另存為百度圖片logo。代碼:
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#鼠標移動至圖片上 右鍵保存圖片
elem_pic = driver.find_element_by_xpath("//div[@id='lg']/img")
print elem_pic.get_attribute("src")
action = ActionChains(driver).move_to_element(elem_pic)
action.context_click(elem_pic)
#重點:當右鍵鼠標點擊鍵盤光標向下則移動至右鍵菜單第一個選項
action.send_keys(Keys.ARROW_DOWN)
time.sleep(3)
action.send_keys('v') #另存為
action.perform()
#獲取另存為對話框(失敗)
alert.switch_to_alert()
alert.accept()
0x07:鍵盤操作
在webdriver的Keys類中提供了鍵盤所有的按鍵操作,當然也包括一些常見的組合鍵操作如Ctrl+A(全選)、Ctrl+C(復制)、Ctrl+V(粘貼)。
- send_keys(Keys.ENTER) 按下回車鍵
- send_keys(Keys.TAB) 按下Tab制表鍵
- send_keys(Keys.SPACE) 按下空格鍵space
- send_keys(Kyes.ESCAPE) 按下回退鍵Esc
- send_keys(Keys.BACK_SPACE) 按下刪除鍵BackSpace
- send_keys(Keys.SHIFT) 按下shift鍵
- send_keys(Keys.CONTROL) 按下Ctrl鍵
- send_keys(Keys.ARROW_DOWN) 按下鼠標光標向下按鍵
- send_keys(Keys.CONTROL,'a') 組合鍵全選Ctrl+A
- send_keys(Keys.CONTROL,'c') 組合鍵復制Ctrl+C
- send_keys(Keys.CONTROL,'x') 組合鍵剪切Ctrl+X
- send_keys(Keys.CONTROL,'v') 組合鍵粘貼Ctrl+V
這里使用的例子參考蟲師的書籍《selenium2 python自動化測試》
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#輸入框輸入內容
elem = driver.find_element_by_id("kw")
elem.send_keys("Eastmount CSDN")
time.sleep(3)
#刪除一個字符CSDN 回退鍵
elem.send_keys(Keys.BACK_SPACE)
elem.send_keys(Keys.BACK_SPACE)
elem.send_keys(Keys.BACK_SPACE)
elem.send_keys(Keys.BACK_SPACE)
time.sleep(3)
#輸入空格+"博客"
elem.send_keys(Keys.SPACE)
elem.send_keys(u"博客")
time.sleep(3)
#ctrl+a 全選輸入框內容
elem.send_keys(Keys.CONTROL,'a')
time.sleep(3)
#ctrl+x 剪切輸入框內容
elem.send_keys(Keys.CONTROL,'x')
time.sleep(3)
#輸入框重新輸入搜索
elem.send_keys(Keys.CONTROL,'v')
time.sleep(3)
#通過回車鍵替代點擊操作
driver.find_element_by_id("su").send_keys(Keys.ENTER)
time.sleep(3)
driver.quit()