Python爬蟲4.4 — selenium高級用法教程
綜述
本系列文檔用於對Python爬蟲技術的學習進行簡單的教程講解,鞏固自己技術知識的同時,萬一一不小心又正好對你有用那就更好了。
Python 版本是3.7.4
前面一篇文章講了selenium的基礎用法,這一篇我們講述一些selenium比較高級的用法。
Headless Chrome
上面的示例代碼在運行中都會彈出一個瀏覽器窗口,有時候會很不方便,這就需要我們不彈出窗口爬取數據。
Headless Chrome 是Chrome瀏覽器的無界面形態,可以在不打開瀏覽器的前提下,使用所有Chrome支持的特性,在命令行中運行你的腳本。以前在爬蟲要使用Phantomjs來實現這些功能,但Phantomjs已經暫停開發,現在可以使用Headless Chrome來代替。
示例代碼如下:
# 引入所需庫
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# 定製option
chrome_options = Options()
# 設置無頭
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
browser = webdriver.Chrome(executable_path=path, options=chrome_options)
# 打開百度
url = 'http://www.baidu.com/'
browser.get(url)
time.sleep(3)
# 保存頁面截圖
browser.save_screenshot('baidu.png')
browser.quit()
設置請求頭
from selenium import webdriver
# 進入瀏覽器設置
options = webdriver.ChromeOptions()
# 設置中文
options.add_argument('lang=zh_CN.UTF-8')
# 更換頭部
options.add_argument('user-agent="Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20"')
browser = webdriver.Chrome(chrome_options=options)
url = "https://httpbin.org/get?show_env=1"
browser.get(url)
browser.quit()
設置代理IP
有時候頻繁爬取一些網頁,服務器發現你是爬蟲後會瘋掉你的ip地址。這時我們可以更改代理ip來解決這個問題。更改代理ip,不同的瀏覽器有不同的實現方式,這裏以Chrome
瀏覽器爲例來講解:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--proxy-server-http://123.56.74.13:8080')
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
# 實例化Chrome
driver = webdriver.Chrome(executable_path=path, options=options)
driver.get('https://httpbin.org/ip')
常用啓動項參數options設置
啓動參數 | 作用 |
---|---|
–user-agent=”“ | 設置請求頭的User-Agent |
–window-size=長,寬 | 設置瀏覽器分辨率 |
–headless | 無界面運行 |
–start-maximized | 最大化運行 |
–incognito | 隱身模式 |
–disable-javascript | 禁用javascript |
–disable-infobars | 禁用瀏覽器正在被自動化程序控制的提示 |
更多參數說明:https://peter.sh/experiments/chromium-command-line-switches/
Cookie操作
- 獲取所有的
cookie
:for cookie in driver.get_cookies(): print(cookie)
- 根據cookie的key獲取value:
cookie = driver.get_cookie('BD_HOME') print(cookie)
- 刪除所有cookie:
driver.delete_all_cookies()
- 刪除某個cookie:
driver.delete_cookie('BD_HOME')
示例代碼如下:
# 引入所需庫
import time
from selenium import webdriver
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
# 實例化Chrome
# 如果時其他瀏覽器需要實例化爲對應的對象,例如火狐webdriver.firefox()
driver = webdriver.Chrome(path)
# 操作輸入框
driver.get('https://www.baidu.com/')
time.sleep(2)
# 獲取所有cookie
for cookie in driver.get_cookies():
print(cookie)
# 根據cookie的key獲取value
# cookie = driver.get_cookie('BD_HOME')
# print(cookie)
# 刪除所有cookie
# driver.delete_all_cookies()
# 刪除某個cookie
# driver.delete_cookie('BD_HOME')
driver.close()
selenium設置cookie
使用add_cookie(cookie_dict)
方法給當前會話可以添加一個cookie;cookie_dict
是一個字典對象,必須要有name
和value
兩個鍵,可選的鍵有:path
, domain
, secure
, expiry
。例如:
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’})
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’, ‘path’ : ‘/’})
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’, ‘path’ : ‘/’, ‘secure’:True})
使用示例代碼如下:
from selenium import webdriver
browser = webdriver.Chrome()
url = "https://www.baidu.com/"
browser.get(url)
# 通過js新打開一個窗口
newwindow='window.open("https://www.baidu.com");'
# 刪除原來的cookie
browser.delete_all_cookies()
# 攜帶cookie打開
browser.add_cookie({'name':'ABC','value':'DEF'})
# 通過js新打開一個窗口
browser.execute_script(newwindow)
input("查看效果")
browser.quit()
行爲鏈
有時候在也頁面中的操作可能要有很多很多,那麼這時候可以使用鼠標行爲鏈類ActionChains
來完成。比如現在要將鼠標移動到某個元素上並執行點擊事件,那麼示例代碼如下:
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
# 實例化Chrome
# 如果時其他瀏覽器需要實例化爲對應的對象,例如火狐webdriver.firefox()
driver = webdriver.Chrome(path)
# 操作輸入框
driver.get('https://www.baidu.com/')
time.sleep(2)
# 根據id獲取元素
input_kw = driver.find_element_by_id('kw')
submit_btn = driver.find_element_by_id('su')
# 實例化Action
action = ActionChains(driver)
action.move_to_element(input_kw)
action.send_keys_to_element(input_kw, 'python')
action.move_to_element(submit_btn)
action.click(submit_btn)
# 執行上述操作
action.perform()
time.sleep(5)
driver.close()
常用的行爲鏈操作方法(ActionChains類方法)
- click(on_element=None) : 左鍵單擊傳入的元素,如果不傳入的話,點擊鼠標當前位置。
- context_click(on_element=None): 右鍵單擊。
- double_click(on_element=None) : 雙擊。
- click_and_hold(on_element=None): 點擊但不鬆開鼠標
- drag_and_drop(source, target) : 在source元素上點擊抓起,移動到target元素上鬆開放下。
- drag_and_drop_by_offset(source,xoffset,yoffset):在source元素上點擊抓起,移動到相對於source元素偏移xoffset和yoffset的座標位置放下。
- send_keys(*keys_to_send): 將鍵發送到當前聚焦的元素。
- send_keys_to_element(element, *keys_to_send): 將鍵發送到指定的元素。
- reset_actions(): 清除已經存儲的動作。
- 更多方法請參考:http://sekenium-python.readthedocs.io/api.html
頁面等待
現在的網頁越來越多采用了Ajax技術,這樣程序便不能確定合適某個元素才完成加載出來。如果實際頁面等待事件過長導致某個DOM元素還沒出來,但是你的代碼直接使用了這個頁面元素,那麼就會拋出NullPointer的異常。爲了解決這個問題,所以Selenium提供了兩種等待方式,一種是隱式等待、一種是顯示等待。
1. 隱式等待
隱式等待指的是,在webdriver中進行find_element_*
這一類查找操作時,如果找不到元素,則會默認的輪詢等待一段時間。
調用driver.implicitly_wait(10)
。那麼在獲取不可用的元素之前,會先等待10秒的時間,示例代碼如下:
driver = webdriver.Chrome(path)
# 設置隱式等待
driver.implicitly_wait(10)
# 請求網頁
driver.get('https://www.baidu.com/')
2. 顯示等待
顯示等待是表明某個條件成立後才執行獲取元素的操作。也可以在等待的時候指定一個最大的時間,如果超過這個時間那麼就拋出一個異常。顯示等待應該使用selenium.webdriver.support.expected_conditions
期望條件和selenium.webdriver.support.ui.WebDriverWait
來配合完成。
示例代碼如下:
# 引入所需庫
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
# 實例化Chrome
# 如果時其他瀏覽器需要實例化爲對應的對象,例如火狐webdriver.firefox()
driver = webdriver.Chrome(path)
# 請求網頁
driver.get('https://www.baidu.com/')
# 設置顯示等待
try:
element = WebDriverWait(driver, 10).until(
# 只能傳一個參數,需要放到元組中
EC.presence_of_element_located((By.ID,'kw'))
)
print(element)
finally:
driver.close()
在上面例子中,我們在查找一個元素的時候,不再使用find_element_by_*
這樣的方式來查找元素,而是使用了WebDriverWait
。
try代碼塊中的代碼的意思是:在拋出元素不存在異常之前,最多等待10秒。在這10秒中,WebDriverWait
會默認每500ms運行一次until之中的內容,而until中的EC.presence_of_element_located
則是檢查元素是否已經被加載,檢查的元素則通過By.ID
這樣的方式來進行查找。
也就是說,在10秒內,默認每0.5秒檢查一次元素是否存在,存在則將元素賦值給element
這個變量。如果超過10秒這個元素仍不存在,則拋出超時異常。
expected_conditions類中其他方法
title_is
:判斷title,返回布爾值WebDriverWait(driver,10).until(EC.title_is(u"百度一下,你就知道"))
title_contains
:判斷title,返回布爾值WebDriverWait(driver,10).until(EC.title_contains(u"百度一下"))
presence_of_element_located
:判斷元素對象是否被加載到dom樹裏; 並不代表該元素一定可見, 如果定位到就返回WebelementWebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'some')))
visibility_of_element_located
:判斷元素對象是否被加載到dom裏並且可見, 一般在對象可能會被其他元素對象遮擋的情況下使用WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,'some')))
visibility_of
:判斷元素是否可見,如果可見就返回這個元素.WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID,value='some')))
presence_of_all_elements_located
:判斷是否至少有1個元素存在dom樹中,如果定位(找)到就返回列表.
WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'some')))
visibility_of_any_elements_located
:判斷是否至少有一個元素在頁面中可見,如果定位到就返回列表.WebDriverWait(driver,10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR,'some')))
text_to_be_present_in_element
:判斷指定的元素中是否包含了預期的字符串,返回布爾值.WebDriverWait(driver,10).until(EC.text_to_be_present_in_element((By.XPATH,"some"),u'設置'))
text_to_be_present_in_element_value
:判斷指定元素的屬性值中是否包含了預期的字符串,返回布爾值.WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'some'),u'百度一下'))
invisibility_of_element_located
:判斷某個元素在是否存在於dom或不可見,如果可見返回False,不可見返回這個元素.WebDriverWait(driver,10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR,'some')))
element_to_be_clickable
:判斷某個元素中是否有可見並且是enable(可點擊)的.WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"some"))).click()
element_to_be_selected
: 判斷某個元素是否被選中了,一般用在下拉列表.WebDriverWait(driver,10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"some")))
- 更多方法請參考:http://sekenium-python.readthedocs.io/waits.html
切換頁面
有時候窗口中有很多子tab,這時候肯定是需要進行切換的,selenuim
提供了一個叫做switch_to_window
來進行切換,具體切換到那個頁面,可以從driver.window_handles
中找到。示例代碼如下:
# 引入所需庫
from selenium import webdriver
# 聲明定義chromedriver路徑
path = r'E:\Python_Code\s1\chromedriver_win32\chromedriver.exe'
# 實例化Chrome
# 如果時其他瀏覽器需要實例化爲對應的對象,例如火狐webdriver.firefox()
driver = webdriver.Chrome(path)
# 操作輸入框
driver.get('https://www.baidu.com/')
driver.execute_script('window.open("http://www.douban.com/")')
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[1])
print(driver.current_url)
# 雖然在窗口中切換到了新頁面,但是driver中還沒有切換.
# 如果想要在代碼中切換到新的頁面,並且做一些爬蟲,
# 那麼應該使用driver.switch_to.window()來切換到指定窗口
# 從driver.window_handlers中取出jurisdiction第幾個窗口
# driver.window_handlers是一個列表,裏面裝的都是窗口句柄.
# 它會按照打開頁面的順序來存儲窗口的句柄.
其他博文鏈接
- Python爬蟲1.1 — urllib基礎用法教程
- Python爬蟲1.2 — urllib高級用法教程
- Python爬蟲1.3 — requests基礎用法教程
- Python爬蟲1.4 — requests高級用法教程
- Python爬蟲2.1 — BeautifulSoup用法教程
- Python爬蟲2.2 — xpath用法教程
- Python爬蟲3.1 — json用法教程
- Python爬蟲3.2 — csv用法教程
- Python爬蟲3.3 — txt用法教程
- Python爬蟲4.1 — threading(多線程)用法教程
- Python爬蟲4.2 — ajax(動態網頁數據抓取)用法教程
- Python爬蟲4.3 — selenium基礎用法教程