當(dāng)你需要執(zhí)行復(fù)雜的操作時,比如將一個元素按住拖動到另一個元素上去,需要移動鼠標(biāo)然后點(diǎn)擊并按下鍵盤某個按鍵等等。
當(dāng)然,在 Web 頁面上,這種操作好像比較少。
但是,如果遇到了怎么辦呢?這就需要用到 ActionChains 這個類啦。
ActionChains 提供了對動作的鏈?zhǔn)讲僮?/strong>,也就是可以生成一個操作的隊(duì)列,將復(fù)雜的操作過程分解成單個操作,然后組合起來一次性執(zhí)行。
這里面主要是鼠標(biāo)操作,加上一些鍵盤操作。
以簡單的鼠標(biāo)移動為例,京東首頁上的商品二級分類默認(rèn)處于隱藏狀態(tài),需要將鼠標(biāo)移動到一級分類上才會顯示。

我們可以模擬鼠標(biāo)移動,到元素上然后再點(diǎn)擊二級菜單,比如我們先點(diǎn)擊家用電器,再點(diǎn)擊超薄電視。
# 兩種寫法,一種是直接鏈?zhǔn)秸{(diào)用,另一種分別調(diào)用
# 直接鏈?zhǔn)秸{(diào)用
from selenium.webdriver import ActionChains
# ... 省略打開過程
e = driver.find_element_by_link_text("家用電器")
# 將鼠標(biāo)懸停在家用電器上,暫停0.1s
ActionChains(driver).move_to_element(e).pause(0.1).perform()
# 第二種
action = ActionChains(driver)
action.move_to_element(e)
action.pause(0.1)
action.perform()
無論哪種方式,動作都是按照它們被調(diào)用的順序執(zhí)行。
通過 ActionChains 的對象生成操作隊(duì)列,在沒有執(zhí)行提交 perform() 之前,所有操作只是暫存于隊(duì)列中,不會實(shí)際在頁面上操作,需要執(zhí)行 perform() 時才會實(shí)際執(zhí)行操作。
除了上面的鼠標(biāo)懸停 move_to_element 操作外,還有其他的一些操作:
鼠標(biāo)懸停
1. move_by_offset(xoffset, yoffset) 鼠標(biāo)移動偏移量
ActionChains(driver).move_by_offset(100, 100).perform()
偏移量: 從當(dāng)前位置增加和減少的坐標(biāo)值, 正數(shù)為增加,負(fù)數(shù)為減少。
從當(dāng)前鼠標(biāo)位置向右下移動,假設(shè)當(dāng)前位置為(300,500),則移動到(400, 600)。
2. move_to_element(to_element)鼠標(biāo)移動到指定元素
e = driver.find_element_by_id('su')
ActionChains(driver).move_to_element(e).perform()
3. move_to_element_with_offset(to_element, xoffset, yoffset) 將鼠標(biāo)移動到基于元素的偏移量,偏移量基于鼠標(biāo)左上角的坐標(biāo)點(diǎn)
e = driver.find_element_by_id('su')
ActionChains(driver).move_to_element_with_offset(e, 100, 100).perform()
移動到 id 為 su 的元素右下方。
鼠標(biāo)點(diǎn)擊
1. click(on_element=None) 點(diǎn)擊指定元素,如果沒有指定元素,則點(diǎn)擊當(dāng)前鼠標(biāo)所在位置
e = driver.find_element_by_id('su')
ActionChains(driver).click(e).perform()
2. double_click(on_element=None) 雙擊元素,如果沒有指定元素則在當(dāng)前鼠標(biāo)位置雙擊
e = driver.find_element_by_id('su')
ActionChains(driver).double_click(e).perform()
3. context_click(on_element=None) 在元素上點(diǎn)擊鼠標(biāo)右鍵,如果沒有指定則在當(dāng)前鼠標(biāo)位置單擊右鍵
e = driver.find_element_by_id('su')
ActionChains(driver).context_click(e).perform()
4. click_and_hold(on_element=None) 鼠標(biāo)按下不松
e = driver.find_element_by_id('su')
ActionChains(driver).click_and_hold(e).perform()
注意,此時鼠標(biāo)一直處于按下狀態(tài),直到執(zhí)行 release() 釋放鼠標(biāo)的操作。
拖動元素
這類操作相當(dāng)于是鼠標(biāo)按住某個元素,然后移動鼠標(biāo),實(shí)現(xiàn)對元素的拖動操作。當(dāng)然前提是你操作的元素要能夠支持拖動。
1. drag_and_drop(source, target) 在 source 元素上按下鼠標(biāo)左鍵,并拖動到 target 元素并松開鼠標(biāo)
e1 = driver.find_element_by_id('source')
e2 = driver.find_element_by_id('target')
ActionChains(driver).drag_and_drop(e1, e2).perform()
按住 e1 元素,拖動到 e2 元素。
2. drag_and_drop_by_offset(source, xoffset, yoffset) 在source元素上按下鼠標(biāo)左鍵,并按偏移量拖動
e = driver.find_element_by_id('source')
ActionChains(driver).drag_and_drop_by_offset(e, -100, -100).perform()
從 e 元素的位置向左上角移動。
鍵盤操作
1. send_keys(*keys_to_send)在當(dāng)前焦點(diǎn)元素發(fā)送按鍵
ActionChains(driver).send_keys('手機(jī)').perform()
2. send_keys_to_element(self, element, *keys_to_send)向指定元素發(fā)送按鍵
e = driver.find_element_by_id('kw')
ActionChains(driver).send_keys_to_element(e, '測試').perform()
3. key_down(value, element=None) 按下一個特殊按鍵
只能用于 Ctrl, Alt,Shift 鍵,注意此時按鍵只是按下并沒有松開,用于進(jìn)行按鍵組合操作,如 Ctrl+A。
4. key_up( value, element=None) 釋放一個按下的鍵
與 key_down() 配套使用,用于釋放一個已按下的按鍵,只能用于 Ctrl, Alt,Shift 鍵
如果要發(fā)送組合鍵,要這么寫:
ActionChains(driver).key_down(Keys.CONTROL) \
.send_keys('c').key_up(Keys.CONTROL).perform()
隊(duì)列操作
1. perform() 提交隊(duì)列中的所有操作
所有操作都需要通過 perform() 才會實(shí)際提交到瀏覽器。
2. rest_actions() 清空隊(duì)列中的操作
將隊(duì)列中已存儲的操作清空。
3. pause(seconds) 暫停所有動作
相當(dāng)于等待,用于鏈?zhǔn)讲僮鬟^程中的等待。
4. release(on_element=None) 松開按下的鼠標(biāo)
如果有鼠標(biāo)按下的操作,那么需要通過 release() 釋放鼠標(biāo)。