Python 爬蟲(四):Selenium 框架

Selenium 是一個用於測試 Web 應用程序的框架,該框架測試直接在瀏覽器中運行,就像真實用戶操作一樣。它支持多種平臺:Windows、Linux、Mac,支持多種語言:Python、Perl、PHP、C# 等,支持多種瀏覽器:Chrome、IE、Firefox、Safari 等。

1 安裝

1)安裝 Selenium

pip install selenium

2)安裝 WebDriver

主要瀏覽器 WebDriver 地址如下:

Chrome:http://chromedriver.storage.googleapis.com/index.html
Firefox:https://github.com/mozilla/geckodriver/releases/
IE:http://selenium-release.storage.googleapis.com/index.html

本文以 Chrome 爲例,本機爲 Windows 系統,WebDriver 使用版本 78.0.3904.11,Chrome 瀏覽器版本爲 78.0.3880.4 驅動程序下載好後解壓,將 chromedriver.exe 放到 Python 安裝目錄下即可。

2 操作瀏覽器

2.1 打開瀏覽器

1)普通方式

以打開去 163 郵箱爲例,使用 Chrome 瀏覽器

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://mail.163.com/')

使用 Firefox 瀏覽器

from selenium import webdriver

browser = webdriver.Firefox()
browser.get('https://mail.163.com/')

使用 IE 瀏覽器

from selenium import webdriver

browser = webdriver.Ie()
browser.get('https://mail.163.com/')

2)加載配置方式

以 Chrome 爲例,在 Chrome 瀏覽器地址欄輸入 chrome://version/ 打開,如圖所示:

在這裏插入圖片描述

我們可以看到個人資料路徑這一項,取到路徑:C:\Users\admin\AppData\Local\Google\Chrome\User Data,取到 User Data 使用自己設置的配置,取到 Default 使用默認配置。看下示例:

from selenium import webdriver

option = webdriver.ChromeOptions()
# 自己的數據目錄(需要將複製的路徑中的 \ 替換成 / 或進行轉義 \\)
# option.add_argument('--user-data-dir=C:/Users/admin/AppData/Local/Google/Chrome/User Data')
option.add_argument('--user-data-dir=C:\\Users\\admin\\AppData\\Local\\Google\\Chrome\\User Data')
browser = webdriver.Chrome(chrome_options=option)
browser.get('https://mail.163.com/')
# 關閉
browser.quit()

如果執行時報錯沒有打開指定頁面,可先將瀏覽器關閉再執行。

3)Headless 方式

前兩種方式都是有瀏覽器界面的方式,Headless 模式是 Chrome 瀏覽器的無界面形態,可以在不打開瀏覽器的前提下,使用所有 Chrome 支持的特性運行我們的程序。這種方式更加方便測試 Web 應用、獲得網站的截圖、做爬蟲抓取信息等。看下示例:

from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
# 使用 headless 無界面瀏覽器模式
chrome_options.add_argument('--headless')
# 禁用 gpu 加速
chrome_options.add_argument('--disable-gpu')

# 啓動瀏覽器,獲取網頁源代碼
browser = webdriver.Chrome(chrome_options=chrome_options)
url = 'https://mail.163.com/'
browser.get(url)
print('browser text = ',browser.page_source)
browser.quit()

2.2 設置瀏覽器窗口

最大化顯示

browser.maximize_window()

最小化顯示

browser.minimize_window()

自定義大小

# 寬 500,高 800
browser.set_window_size(500,800)

2.3 前進後退

前進

browser.forward()

後退

browser.back()

3 元素定位

當我們想要操作一個元素時,首先需要找到它,Selenium 提供了多種元素定位方式,我們以 Chrome 瀏覽器 Headless 方式爲例。看下示例:

from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu') 
browser = webdriver.Chrome(chrome_options=chrome_options)
url = 'https://xxx.xxx.com/'
browser.get(url)
data = browser.page_source

假設訪問地址 https://xxx.xxx.com/,返回 data 爲如下內容。

<html>
 <body>
  <form>
   <input id="fid" name="fid" type="text" />
   <input id="firstName" name="fname" class="fname" type="text" />
   <input id="lastName" name="fname" class="fname" type="text" />
   <a href="index.html">index</a>
  </form>
 </body>
<html>

1)根據 id 定位

browser.find_element_by_id('fid')

2)根據 name 定位

# 返回第一個元素
browser.find_element_by_name('fname')
# 返回所有元素
browser.find_elements_by_name('fname')

3)根據 class 定位

# 返回第一個元素
browser.find_element_by_class_name('fname')
# 返回所有元素
browser.find_elements_by_class_name('fname')

4)根據標籤名定位

# 返回第一個元素
browser.find_element_by_tag_name('input')
# 返回所有元素
browser.find_elements_by_tag_name('input')

5)使用 CSS 定位

# 返回第一個元素
browser.find_element_by_css_selector('.fname')
# 返回所有元素
browser.find_elements_by_css_selector('.fname')

6)使用鏈接文本定位超鏈接

# 返回第一個元素
browser.find_element_by_link_text('index')
# 返回所有元素
browser.find_elements_by_link_text('index')

# 返回第一個元素
browser.find_element_by_partial_link_text('index')
# 返回所有元素
browser.find_elements_by_partial_link_text('index')

7)使用 xpath 定位

# 返回第一個元素
browser.find_elements_by_xpath("//input[@id='fid']")
# 返回所有元素
browser.find_elements_by_xpath("//input[@name='fname']")

4 等待事件

Web 應用大多都使用 AJAX 技術進行加載,瀏覽器載入一個頁面時,頁面內的元素可能會在不同的時間載入,這會加大定位元素的困難程度,因爲元素不在 DOM 裏,會拋出 ElementNotVisibleException 異常,使用 Waits,我們就可以解決這個問題。

Selenium WebDriver 提供了顯式和隱式兩種 Waits 方式,顯式的 Waits 會讓 WebDriver 在更深一步的執行前等待一個確定的條件觸發,隱式的 Waits 則會讓 WebDriver 試圖定位元素的時候對 DOM 進行指定次數的輪詢。

4.1 顯示等待

WebDriverWait 配合該類的 until()until_not() 方法,就能夠根據判斷條件而進行靈活地等待了。它主要流程是:程序每隔 x 秒檢查一下,如果條件成立了,則執行下一步操作,否則繼續等待,直到超過設置的最長時間,然後拋出 TimeoutException 異常。先看一下方法:

__init__(driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None)

  • driver: 傳入 WebDriver 實例;
  • timeout: 超時時間,單位爲秒;
  • poll_frequency: 調用 until 或 until_not 中方法的間隔時間,默認是 0.5 秒;
  • ignored_exceptions: 忽略的異常,如果在調用 until 或 until_not 的過程中拋出這個元組中的異常,則不中斷代碼,繼續等待,如果拋出的是這個元組外的異常,則中斷代碼,拋出異常。默認只有 NoSuchElementException。

until(method, message='')

  • method: 在等待期間,每隔一段時間(init 中的 poll_frequency)調用這個方法,直到返回值不是 False;
  • message: 如果超時,拋出 TimeoutException,將 message 傳入異常。

until_not(method, message='')

until 方法是當某條件成立則繼續執行,until_not 方法與之相反,它是當某條件不成立則繼續執行,參數與 until 方法相同。

以去 163 郵箱爲例,看一下示例:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
browser.get('https://mail.163.com/')
try:
    # 超時時間爲 5 秒
    data = WebDriverWait(browser,5).until(
        EC.presence_of_element_located((By.ID,'lbNormal'))
    )
    print(data)
finally:
    browser.quit()

示例中代碼會等待 5 秒,如果 5 秒內找到元素則立即返回,否則會拋出 TimeoutException 異常,WebDriverWait 默認每 0.5 秒調用一下 ExpectedCondition 直到它返回成功爲止。

4.2 隱式等待

當我們要找一個或者一些不能立即可用的元素的時候,隱式 Waits 會告訴 WebDriver 輪詢 DOM 指定的次數,默認設置是 0 次,一旦設定,WebDriver 對象實例的整個生命週期的隱式調用也就設定好了。看一下方法:

implicitly_wait(time_to_wait)

隱式等待是設置了一個最長等待時間 time_to_wait,該時間是針對全局設置的,如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間截止,然後執行下一步。看到了這裏,我們會感覺有點像 time.sleep(),它們的區別是:time.sleep() 必須等待指定時間後才能繼續執行, time_to_wait 是在指定的時間範圍加載完成即執行,time_to_wait 比 time.sleep() 更靈活一些。

看下示例:

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(5)
browser.get('https://mail.163.com/')
data = browser.find_element_by_id('lbNormal')
print(data)
browser.quit()

5 登錄 163 郵箱

最後,我們用 Selenium 來做個登錄 163 郵箱的實戰例子。

5.1 方式一

我們通過地址 https://email2.163.com/ 登錄,如圖所示:

從圖中我們發現直接進了 163 郵箱用戶名、密碼登錄頁,我們直接輸入用戶名、密碼,點擊登錄按鈕即可。示例如下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(2)
browser.get('https://email2.163.com/')
browser.switch_to.frame(browser.find_element_by_xpath('//iframe[starts-with(@id,"x-URS")]'))
# 自己的用戶名
browser.find_element_by_xpath('//input[@name="email"]').send_keys('xxx')
# 自己的密碼
browser.find_element_by_xpath('//input[@name="password"]').send_keys('xxx')
browser.find_element_by_xpath('//*[@id="dologin"]').click()
print(browser.page_source)
# 關閉
browser.quit()

5.2 方式二

第二種方式我們使用地址 https://mail.163.com/,先手動打開看一下:

從圖中我們會發現,登錄頁面首先展示的是二維碼登錄方式,因此我們需要先點擊上圖紅框圈住的位置切換到用戶名、密碼的登錄方式,如圖所示:


此時,我們先輸入用戶名、密碼,然後點擊登錄按鈕即可。詳細代碼見如下 GitHub 倉庫。

使用 Selenium 登錄 163 郵箱示例代碼

歡迎關注文末公衆號,免費領取海量學習資料!



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