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操作

  1. 獲取所有的cookie
    for cookie in driver.get_cookies():
        print(cookie)
    
  2. 根據cookie的key獲取value:
    cookie = driver.get_cookie('BD_HOME')
    print(cookie)
    
  3. 刪除所有cookie:
    driver.delete_all_cookies()
    
  4. 刪除某個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是一個字典對象,必須要有namevalue兩個鍵,可選的鍵有: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類中其他方法

  1. title_is:判斷title,返回布爾值
    • WebDriverWait(driver,10).until(EC.title_is(u"百度一下,你就知道"))
  2. title_contains:判斷title,返回布爾值
    • WebDriverWait(driver,10).until(EC.title_contains(u"百度一下"))
  3. presence_of_element_located:判斷元素對象是否被加載到dom樹裏; 並不代表該元素一定可見, 如果定位到就返回Webelement
    • WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'some')))
  4. visibility_of_element_located:判斷元素對象是否被加載到dom裏並且可見, 一般在對象可能會被其他元素對象遮擋的情況下使用
    • WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,'some')))
  5. visibility_of:判斷元素是否可見,如果可見就返回這個元素.
    • WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID,value='some')))
  6. presence_of_all_elements_located:判斷是否至少有1個元素存在dom樹中,如果定位(找)到就返回列表.
    WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'some')))
  7. visibility_of_any_elements_located:判斷是否至少有一個元素在頁面中可見,如果定位到就返回列表.
    • WebDriverWait(driver,10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR,'some')))
  8. text_to_be_present_in_element:判斷指定的元素中是否包含了預期的字符串,返回布爾值.
    • WebDriverWait(driver,10).until(EC.text_to_be_present_in_element((By.XPATH,"some"),u'設置'))
  9. text_to_be_present_in_element_value:判斷指定元素的屬性值中是否包含了預期的字符串,返回布爾值.
    • WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'some'),u'百度一下'))
  10. invisibility_of_element_located:判斷某個元素在是否存在於dom或不可見,如果可見返回False,不可見返回這個元素.
    • WebDriverWait(driver,10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR,'some')))
  11. element_to_be_clickable:判斷某個元素中是否有可見並且是enable(可點擊)的.
    • WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"some"))).click()
  12. element_to_be_selected: 判斷某個元素是否被選中了,一般用在下拉列表.
    • WebDriverWait(driver,10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"some")))
  13. 更多方法請參考: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是一個列表,裏面裝的都是窗口句柄.
# 它會按照打開頁面的順序來存儲窗口的句柄.

其他博文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章