10 selenium的基本使用

10 selenium的基本使用

一、selenium簡介

Selenium是一個用于web自動化測試的工具,Selenium測試直接運行在瀏覽器中,就好像一個真正的用戶在操作一樣, 支持大部分主流的瀏覽器,包括IE(7,8,9,10,11),Firefox,Safari,Chrome,Opera等。

?我們可以利用它來模擬用戶點擊訪問網站,繞過一些復雜的認證場景

通過selnium+驅動瀏覽器這種組合可以直接渲染解析js,繞過大部分的參數構造和反爬。

注意事項:

新版本的Selenium已經不在支持phantomjs,原作者也已經放棄維護該項目了。

還有在做爬蟲的時候盡量不要用這種方法,Selenium+瀏覽器的組合速度慢,應付不了數據量比較大的爬取以及并發爬取。并且很吃電腦資源。

二、selenium配置

Selenium安裝非常簡單,直接pip就可以搞定: pip install selenium

使用selenium驅動chrome瀏覽器需要下載chromedriver,而且chromedriver版本需要與chrome的版本對應,版本錯誤的話則會運行報錯。

Chromedriver下載地址:https://chromedriver.storage.googleapis.com/index.html

Windows: 下載對應版本的chromedriver解壓后,將文件移動到一個配置了環境變量的文件夾中,例如Python安裝文件夾

Linux/Mac: 解壓后,將文件移動至/usr/local/bin目錄中

Selenium驅動其他瀏覽器的也是需要下載對應的驅動

三、基本使用

1、啟動/關閉

獲取頁面內容:page_source

from selenium import webdriver
import time

driver = webdriver.Chrome()

driver.get('https://www.baidu.com')

# 獲取頁面內容
resp = driver.page_source
print(resp)

time.sleep(5)

driver.close()

2、元素選取

在一個頁面中有很多不同的策略可以定位一個元素。我們可以選擇最合適的方法去查找元素。Selenium提供了下列的方法:

注: 其中的element加上一個s,則是對應的多個元素的查找方法

單個元素查找方法 作用
find_element_by_xpath() 通過Xpath查找
find_element_by_class_name() 通過class屬性查找
find_element_by_css_selector() 通過css選擇器查找
find_element_by_id() 通過id查找
find_element_by_link_text() 通過鏈接文本查找
find_element_by_name() 通過name屬性進行查找
find_element_by_partial_link_text() 通過鏈接文本的部分匹配查找
find_element_by_tag_name() 通過標簽名查找
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

driver.get('https://www.baidu.com')

# 通過Xpath查找
a1 = driver.find_element_by_xpath('//input[@value="百度一下"]')
print('find_element_by_xpath',a1)
# 通過id查找
a2 = driver.find_element_by_id('su')
print('find_element_by_id',a2)
# 通過class屬性查找
a3 = driver.find_element_by_class_name('fm')
print('find_element_by_class_name',a3)
# 通過css選擇器查找
a4 = driver.find_element_by_css_selector('#su')
print('find_element_by_class_name',a4)
# 通過鏈接文本查找
a5 = driver.find_element_by_link_text('新聞')
print('find_element_by_link_text',a5)
# 通過name屬性查找
a6 = driver.find_element_by_name('rn')
print('find_element_by_name',a6)
# 通過鏈接文本的部分匹配查找
a7 = driver.find_element_by_partial_link_text('新')
print('find_element_by_partial_link_text',a7)
# 通過標簽名查找
a8 = driver.find_element_by_tag_name('input')
print('find_element_by_tag_name',a8)
# 查找多個
a9 = driver.find_elements_by_tag_name('div')
print('find_elements_by_tag_name',a9)

除了以上的多種查找方式,還有兩種私有方法集成了上面的所有的查找方法,讓我們更方便的使用

方法 作用
find_element(By.XPATH, ‘//button/span’) 通過Xpath查找一個
find_elements(By.XPATH, ‘//button/span’) 通過Xpath查找多個

其中的第一個參數可以選擇使用查找的方法,By.xxx 使用xxx方式解析,解析方法如下:

注:By對象導入: from selenium.webdriver.common.by import By

ID = "id" 
XPATH = "xpath" 
LINK_TEXT = "link text" 
PARTIAL_LINK_TEXT = "partial link text" 
NAME = "name" 
TAG_NAME = "tag name" 
CLASS_NAME = "class name" 
CSS_SELECTOR = "css selector" 
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

driver.get('https://www.baidu.com')
# by_id
a1 = driver.find_element(by=By.ID, value='su')
print('By.ID',a1)
# by_xpath
a2 = driver.find_element(by=By.XPATH, value='//input[@value="百度一下"]')
print('By.XPATH',a2)
# by_link_text
a3 = driver.find_element(by=By.LINK_TEXT, value='新聞')
print('By.LINK_TEXT',a3)
# by_partial_link_text
a4 = driver.find_element(by=By.PARTIAL_LINK_TEXT, value='新')
print('By.PARTIAL_LINK_TEXT',a4)
# by_name
a5 = driver.find_element(by=By.NAME, value='rn')
print('By.NAME',a5)
# by_tag_name
a6 = driver.find_element(by=By.TAG_NAME, value='input')
print('By.NAME',a6)
# by_class_name
a7 = driver.find_element(by=By.CLASS_NAME, value='fm')
print('By.CLASS_NAME',a7)
# by_css_selector
a8 = driver.find_element(by=By.CSS_SELECTOR, value='#su')
print('By.CSS_SELECTOR',a8)
# 查找多個
a9 = driver.find_elements(by=By.TAG_NAME, value='div')
print('find_elements', a9)

三、窗口/頁面/彈窗切換

1、窗口切換

用selenium操作瀏覽器如果需要在打開新的頁面,這個時候會有問題,因為我們用selenium操作的是第一個打開的窗口,所以新打開的頁面我們是無法去操作的,所以我們要用到切換窗口:既handle切換的方法

方法 作用
window_handles 獲取所有頁面窗口的句柄
current_window_handle 獲取當前頁面窗口的句柄
switch_to.window(window_name) 定位頁面轉到指定的window_name頁面
from selenium import webdriver
import time
driver = webdriver.Chrome()

driver.get('https://www.baidu.com')

time.sleep(10)

# 獲取所有窗口的句柄
handles = driver.window_handles
# 獲取當前窗口的句柄
current = driver.current_window_handle
# 定位頁面轉到指定的window_name頁面
driver.switch_to.window(handles[1])
print(handles)
print(current)
time.sleep(2)
# 獲取當前窗口的句柄
current = driver.current_window_handle
print(current)

2、頁面(frame)切換

在實際的爬蟲中,有時候我們會遇到找不到元素的問題,明明定位的路徑沒問題,這個時候我們可以考慮一下是否是該頁面存在frame的問題導致的定位不到元素。

方法 作用
switch_to.frame(frame_reference) 切到指定frame,可用id或name(str)、index(int)、元素(WebElement)定位
switch_to.parent_frame() 切到父級frame,如果已是主文檔,則無效果, 相當于后退回去
switch_to_default_content() 切換到主頁面,DOM樹最開始的frame

3、頁面彈窗

有的時候還會遇到彈窗的問題, 主要有兩種一種是瀏覽器彈窗(alert/prompt),一種是自定義彈窗

自定義彈窗,就是一個自定義的div層,是隱藏頁面中的,當觸發了這個彈窗后,他就顯示出來,這種方式我們通過正常的定位方式是可以定位到的。

alert彈窗,就要用下面的方法處理:

方法 作用
switch_to_alert 定位到alert彈窗,返回一個彈窗的對象
dismiss() 對彈窗對象的取消操作(相當于點擊彈窗上的取消按鈕)
accept() 對彈窗對象的確定操作(相當于點擊彈窗上的確定按鈕)
send_keys(key) 對彈窗對象內的輸入框輸入數據(針對于prompt彈窗)
text 獲取彈窗內的文本

四、等待/動作鏈

1、等待

在selenium操作瀏覽器的過程中,每一次請求url,selenium都會等待頁面加載完成以后,才會將操作權限在交給我們的程序。

但是,由于ajax和各種JS代碼的異步加載問題,當一個頁面被加載到瀏覽器時,該頁面內的元素可以在不同的時間點被加載,這就使得元素的定位變得十分困難,當元素不再頁面中時,使用selenium去查找的時候會拋出ElementNotVisibleException異常。

為了解決這個問題,selenium提供了兩種等待頁面加載的方式,顯示等待和隱式等待,讓我們可以等待元素加載完成后在進行操作。

1)顯示等待

顯示等待: 顯式等待指定某個條件,然后設置最長等待時間,程序每隔XX時間看一眼,如果條件成立,則執行下一步,否則繼續等待,直到超過設置的最長時間,然后拋出超時異常(TimeoutException)。

顯示等待主要使用了WebDriverWait類與expected_conditions模塊。

一般寫法:

WebDriverWait(driver, timeout, poll_frequency, igonred_exceptions).until(method, message)

Driver:傳入WebDriver實例。
timeout: 超時時間,等待的最長時間(同時要考慮隱性等待時間)
poll_frequency: 調用until中的方法的間隔時間,默認是0.5秒
ignored_exceptions: 忽略的異常,如果在調用until的過程中拋出這個元組中的異常,則不中斷代碼,繼續等待.
Method:可執行方法
Message: 超時時返回的信息
WebDriverWait包:from selenium.webdriver.support.wait import WebDriverWait
expected_conditions包:from selenium.webdriver.support import expected_conditions as EC

expected_conditions條件

expected_conditions是selenium的一個子模塊,其中包含一系列可用于判斷的條件,配合該類的方法,就能夠根據條件而進行靈活地等待了

ActionChains提供的方法 作用
title_is title_contains 這兩個條件類驗證title,驗證傳入的參數title是否等于或包含于driver
presence_of_element_located presence_of_all_elements_located 這兩個條件驗證元素是否出現,傳入的參數都是元組類型的locator,如(By.ID, 'kw') 顧名思義,一個只要一個符合條件的元素加載出來就通過;另一個必須所有符合條件的元素都加載出來才行
visibility_of_element_located invisibility_of_element_located visibility_of 這三個條件驗證元素是否可見,前兩個傳入參數是元組類型的locator,第三個傳入WebElement
text_to_be_present_in_element text_to_be_present_in_element_value 判斷某段文本是否出現在某元素中,一個判斷元素的text,一個判斷元素的value
frame_to_be_available_and_switch_to_it 判斷frame是否可切入,可傳入locator元組或者直接傳入定位方式:id、name、index或WebElement
alert_is_present 判斷是否有alert出現
element_to_be_clickable 判斷元素是否可點擊,傳入locator
# 顯示等待
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

driver.get('https://www.baidu.com')

locator = (By.LINK_TEXT, '貼吧')

try:
    # 等待鏈接text'貼吧'出現,然后點擊、打印其href屬性
    WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located(locator))
    element = driver.find_element(*locator)
    print(element.get_attribute('href'))
    element.click()
except:
    print('發生錯誤')
finally:
    driver.close()

2)隱式等待

隱性等待implicitly_wait(xx) :設置了一個最長等待時間,如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間截止,然后執行下一步。

弊端就是程序會一直等待整個頁面加載完成,就算你需要的元素加載出來了還是需要等待。,也就是一般情況下你看到瀏覽器標簽欄那個小圈不再轉,才會執行下一步,

隱性等待對整個driver的周期都起作用,所以只要設置一次即可

隱性等待和顯性等待可以同時用,但要注意:等待的最長時間取兩者之中的大者

默認等待時間為0,可以通過下面的方式設置:

# 隱式等待
from selenium import webdriver

driver = webdriver.Chrome()

driver.implicitly_wait(10)        #隱式等待,最長10s

driver.get('https://www.baidu.com')

2、動作鏈(ActionChains)

在selenium當中除了簡單的點擊動作外,還有一些稍微復雜的動作,就需要用到ActionChains(動作鏈)這個子模塊來滿足我們的需求。

ActionChains可以完成復雜一點的頁面交互行為,例如元素的拖拽,鼠標移動,懸停行為,內容菜單交互。

它的執行原理就是當調用ActionChains方法的時候不會立即執行,而是將所有的操作暫時儲存在一個隊列中,當調用perform()方法的時候,會按照隊列中放入的先后順序執行前面的操作。

ActionChains包:from selenium.webdriver.common.action_chains import ActionChains

ActionChains提供的方法 作用
click(on_element=None) 鼠標左鍵單擊傳入的元素
double_click(on_element=None) 雙擊鼠標左鍵
context_click(on_element=None) 點擊鼠標右鍵
click_and_hold(on_element=None) 點擊鼠標左鍵,按住不放
release(on_element=None) 在某個元素位置松開鼠標左鍵
drag_and_drop(source, target) 拖拽到某個元素然后松開
drag_and_drop_by_offset(source, xoffset, yoffset) 拖拽到某個坐標然后松開
move_to_element(to_element) 鼠標移動到某個元素
move_by_offset(xoffset, yoffset) 移動鼠標到指定的x,y位置
move_to_element_with_offset(to_element, xoffset, yoffset) 將鼠標移動到距某個元素多少距離的位置
perform() 執行鏈中的所有動作
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
try:
    driver.get('http://www.treejs.cn/v3/demo/cn/exedit/drag.html')
    locator1 = (By.ID,'treeDemo_2_span')
    locator2 = (By.ID,'treeDemo_3_span')
    locator3 = (By.ID,'treeDemo_11_span')
    element = WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator1))
    target1 = WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator2))
    target2 = WebDriverWait(driver, 20, 0.5).until(EC.presence_of_element_located(locator3))

    ActionChains(driver).drag_and_drop(element,target1).perform()
    time.sleep(5)
    ActionChains(driver).drag_and_drop(element,target2).perform()
    time.sleep(5)
    ActionChains(driver).move_to_element(target2)
    time.sleep(5)
finally:
    driver.quit()

3、微博登錄

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

url = 'https://weibo.com/'
driver.get(url)

locator1 = (By.ID, 'loginname')
locator2 = (By.XPATH, '//div[@class="input_wrap"]/input[@name="password"]')
locator3 = (By.XPATH,'//a[@class="W_btn_a btn_32px"]')

username = WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located(locator1))
password = WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located(locator2))
login = WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located(locator3))
username.send_keys('username')
password.send_keys('password')
login.click()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370