成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---37、動(dòng)態(tài)渲染頁面抓取:Selenium

zhjx922 / 2287人閱讀

摘要:不過動(dòng)態(tài)渲染的頁面不止這一種。再有淘寶這種頁面,它即使是獲取的數(shù)據(jù),但是其接口含有很多加密參數(shù),我們難以直接找出其規(guī)律,也很難直接分析來抓取。我們用一個(gè)實(shí)例來感受一下在這里們依然是先打開知乎頁面,然后獲取提問按鈕這個(gè)節(jié)點(diǎn),再將其

上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---36、分析Ajax爬取今日頭條街拍美圖
下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---38、動(dòng)態(tài)渲染頁面抓取:Splash的使用

在前面一章我們了解了 Ajax 的分析和抓取方式,這種頁面其實(shí)也是 JavaScript 動(dòng)態(tài)渲染的頁面的一種情形,通過直接分析 Ajax 我們?nèi)匀豢梢越柚?Requests 或 Urllib 來實(shí)現(xiàn)數(shù)據(jù)的抓取。

不過 JavaScript 動(dòng)態(tài)渲染的頁面不止 Ajax 這一種。比如中國青年網(wǎng):http://news.youth.cn/gn/,它的分頁部分是由 JavaScript 生成的,并非原始 HTML 代碼,這其中并不包含 Ajax 請(qǐng)求。如 ECharts 的官方實(shí)例:http://echarts.baidu.com/demo...,其圖形都是經(jīng)過 JavaScript 計(jì)算之后生成的。再有淘寶這種頁面,它即使是 Ajax 獲取的數(shù)據(jù),但是其 Ajax 接口含有很多加密參數(shù),我們難以直接找出其規(guī)律,也很難直接分析 Ajax 來抓取。

但是數(shù)據(jù)總歸是要抓取的,為了解決這些問題,我們可以直接使用模擬瀏覽器運(yùn)行的方式來實(shí)現(xiàn),這樣我們就可以做到瀏覽器看到是什么樣,抓取的源碼就是什么樣,也就是可見即可爬。這樣我們就不用再去管網(wǎng)頁內(nèi)部的 JavaScript 用了什么算法渲染頁面,不用管網(wǎng)頁后臺(tái)的 Ajax 接口到底有哪些參數(shù),利用模擬瀏覽器的方式我們都可以直接獲取 JavaScript 渲染的最終結(jié)果,只要能在瀏覽器中看到,我們都能抓取。

在 Python 中提供了許多模擬瀏覽器運(yùn)行的庫,如 Selenium、Splash、PyV8、Ghost 等等,本章我們介紹一下其中 Selenium 和 Splash 的用法,有了它們,我們就不用再為動(dòng)態(tài)渲染的頁面發(fā)愁了。

Selenium的使用

Selenium 是一個(gè)自動(dòng)化測試工具,利用它我們可以驅(qū)動(dòng)瀏覽器執(zhí)行特定的動(dòng)作,如點(diǎn)擊、下拉等等操作,同時(shí)還可以獲取瀏覽器當(dāng)前呈現(xiàn)的頁面的源代碼,做到可見即可爬。對(duì)于一些 JavaScript 動(dòng)態(tài)渲染的頁面來說,此種抓取方式非常有效,本節(jié)讓我們來感受一下它的強(qiáng)大之處吧。

1. 準(zhǔn)備工作

本節(jié)以 Chrome 為例來講解 Selenium 的用法,在本節(jié)開始之前請(qǐng)確保已經(jīng)正確安裝好了 Chrome 瀏覽器并配置好了 ChromeDriver,另外還需要正確安裝好 Python 的 Selenium 庫,詳細(xì)的過程可以參考第一章的安裝和配置說明。

2. 基本使用

準(zhǔn)備工作做好之后,首先我們來大體看一下 Selenium 有一些怎樣的功能,先用一段實(shí)例代碼來感受一下:

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

browser = webdriver.Chrome()
try:
??? browser.get("https://www.baidu.com")
??? input = browser.find_element_by_id("kw")
??? input.send_keys("Python")
??? input.send_keys(Keys.ENTER)
??? wait = WebDriverWait(browser, 10)
??? wait.until(EC.presence_of_element_located((By.ID, "content_left")))
??? print(browser.current_url)
??? print(browser.get_cookies())
??? print(browser.page_source)
finally:
??? browser.close()

運(yùn)行代碼之后可以發(fā)現(xiàn)會(huì)自動(dòng)彈出一個(gè) Chrome 瀏覽器,瀏覽器首先會(huì)跳轉(zhuǎn)到百度,然后在搜索框中輸入 Python 進(jìn)行搜索,然后跳轉(zhuǎn)到搜索結(jié)果頁,等待搜索結(jié)果加載出來之后,控制臺(tái)分別會(huì)輸出當(dāng)前的 URL,當(dāng)前的 Cookies 還有網(wǎng)頁源代碼,如圖 7-1 所示:

圖 7-1 運(yùn)行結(jié)果
在jon g zhi tai可以看到我們得到的當(dāng)前的 URL、Cookies、源代碼都是瀏覽器中的真實(shí)內(nèi)容。
所以說,如果我們用 Selenium 來驅(qū)動(dòng)瀏覽器加載網(wǎng)頁的話,我們就可以直接拿到 JavaScript 渲染的結(jié)果了,不管是什么加密統(tǒng)統(tǒng)不用再需要擔(dān)心。
下面我們來詳細(xì)了解一下Selenium的用法。

3. 聲明瀏覽器對(duì)象

Selenium 支持非常多的瀏覽器,如 Chrome、Firefox、Edge 等,還有手機(jī)端的瀏覽器 Android、BlackBerry 等,另外無界面瀏覽器 PhantomJS 也同樣支持。
我們可以用如下的方式初始化:

from selenium import webdriver

browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()

這樣我們就完成了瀏覽器對(duì)象的初始化并賦值為 browser 對(duì)象,接下來我們要做的就是調(diào)用 browser 對(duì)象,讓其執(zhí)行各個(gè)動(dòng)作,就可以模擬瀏覽器操作了。

3. 訪問頁面

我們可以用 get() 方法來請(qǐng)求一個(gè)網(wǎng)頁,參數(shù)傳入鏈接 URL 即可,比如在這里我們用 get() 方法訪問淘寶,然后打印出源代碼,代碼如下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
print(browser.page_source)
browser.close()

運(yùn)行之后我們便發(fā)現(xiàn)彈出了 Chrome 瀏覽器,自動(dòng)訪問了淘寶,然后控制臺(tái)輸出了淘寶頁面的源代碼,隨后瀏覽器關(guān)閉。
通過這幾行簡單的代碼我們便可以實(shí)現(xiàn)瀏覽器的驅(qū)動(dòng)并獲取網(wǎng)頁源碼,非常便捷。

4. 查找節(jié)點(diǎn)

Selenium 可以驅(qū)動(dòng)瀏覽器完成各種操作,比如填充表單、模擬點(diǎn)擊等等,比如我們想要完成向某個(gè)輸入框輸入文字的操作,總得需要知道這個(gè)輸入框在哪里吧?所以 Selenium 提供了一系列查找節(jié)點(diǎn)的方法,我們可以用這些方法來獲取想要的節(jié)點(diǎn),以便于下一步執(zhí)行一些動(dòng)作或者提取信息。

單個(gè)節(jié)點(diǎn)

比如我們想要從淘寶頁面中提取搜索框這個(gè)節(jié)點(diǎn),首先觀察它的源代碼,如圖 7-2 所示:

圖 7-2 源代碼
可以發(fā)現(xiàn)它的 ID 是 q,Name 也是 q,還有許多其他屬性,那我們獲取它的方式就有多種形式了,比如find_element_by_name() 是根據(jù) Name 值獲取,ind_element_by_id() 是根據(jù) ID 獲取,另外還有根據(jù)XPath、CSS Selector 等獲取的方式。
我們用代碼實(shí)現(xiàn)一下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
input_first = browser.find_element_by_id("q")
input_second = browser.find_element_by_css_selector("#q")
input_third = browser.find_element_by_xpath("http://*[@id="q"]")
print(input_first, input_second, input_third)
browser.close()

在這里我們使用了三種方式獲取輸入框,根據(jù) ID、CSS Selector 和 XPath 獲取,它們返回的結(jié)果是完全一致的。
運(yùn)行結(jié)果:




可以看到三個(gè)節(jié)點(diǎn)都是 WebElement 類型,是完全一致的。
在這里列出所有獲取單個(gè)節(jié)點(diǎn)的方法:

find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

另外 Selenium 還提供了通用的 find_element() 方法,它需要傳入兩個(gè)參數(shù),一個(gè)是查找的方式 By,另一個(gè)就是值,實(shí)際上它就是 find_element_by_id() 這種方法的通用函數(shù)版本,比如 find_element_by_id(id) 就等價(jià)于 find_element(By.ID, id),二者得到的結(jié)果完全一致。
我們用代碼實(shí)現(xiàn)一下:

from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
input_first = browser.find_element(By.ID, "q")
print(input_first)
browser.close()

這樣的查找方式實(shí)際上功能和上面列舉的查找函數(shù)完全一致,不過參數(shù)更加靈活。

多個(gè)節(jié)點(diǎn)

如果我們查找的目標(biāo)在網(wǎng)頁中只有一個(gè),那么完全可以用 find_element() 方法,但如果有多個(gè)節(jié)點(diǎn),再用 find_element() 方法查找就只能得到第一個(gè)節(jié)點(diǎn)了,如果要查找所有滿足條件的節(jié)點(diǎn),那就需要用 find_elements() 這樣的方法,方法名稱中 element 多了一個(gè) s ,注意區(qū)分。
比如我們?cè)谶@里查找淘寶左側(cè)導(dǎo)航條的所有條目,如圖 7-3 所示:

圖 7-3 導(dǎo)航欄
就可以這樣來實(shí)現(xiàn):

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
lis = browser.find_elements_by_css_selector(".service-bd li")
print(lis)
browser.close()

運(yùn)行結(jié)果:

[, , ···]

在此簡化了一下輸出結(jié)果,中間部分省略。
可以看到得到的內(nèi)容就變成了列表類型,列表的每個(gè)節(jié)點(diǎn)都是 WebElement 類型。
也就是說,如果我們用 find_element() 方法,只能獲取匹配的第一個(gè)節(jié)點(diǎn),結(jié)果是 WebElement 類型,如果用 find_elements() 方法,則結(jié)果是列表類型,列表的每個(gè)節(jié)點(diǎn)是 WebElement 類型。
函數(shù)的列表如下:

find_elements_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

當(dāng)然我們和剛才一樣,也可可以直接 find_elements() 方法來選擇,所以也可以這樣來寫:

lis = browser.find_elements(By.CSS_SELECTOR, ".service-bd li")

結(jié)果是完全一致的。

5. 節(jié)點(diǎn)交互

Selenium 可以驅(qū)動(dòng)瀏覽器來執(zhí)行一些操作,也就是說我們可以讓瀏覽器模擬執(zhí)行一些動(dòng)作,比較常見的用法有:
輸入文字用 send_keys() 方法,清空文字用 clear() 方法,另外還有按鈕點(diǎn)擊,用 click() 方法。
我們用一個(gè)實(shí)例來感受一下:

from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
input = browser.find_element_by_id("q")
input.send_keys("iPhone")
time.sleep(1)
input.clear()
input.send_keys("iPad")
button = browser.find_element_by_class_name("btn-search")
button.click()

在這里我們首先驅(qū)動(dòng)瀏覽器打開淘寶,然后用 find_element_by_id() 方法獲取輸入框,然后用 send_keys() 方法輸入 iPhone 文字,等待一秒之后用 clear() 方法清空輸入框,再次調(diào)用 send_keys() 方法輸入 iPad 文字,之后再用 find_element_by_class_name() 方法獲取搜索按鈕,最后調(diào)用 click() 方法完成搜索動(dòng)作。
通過上面的方法我們就完成了一些常見節(jié)點(diǎn)的動(dòng)作操作,更多的操作可以參見官方文檔的交互動(dòng)作介紹:http://selenium-python.readth...。

6. 動(dòng)作鏈

在上面的實(shí)例中,一些交互動(dòng)作都是針對(duì)某個(gè)節(jié)點(diǎn)執(zhí)行的,比如輸入框我們就調(diào)用它的輸入文字和清空文字方法,按鈕就調(diào)用它的點(diǎn)擊方法,其實(shí)還有另外的一些操作它是沒有特定的執(zhí)行對(duì)象的,比如鼠標(biāo)拖拽、鍵盤按鍵等操作。所以這些動(dòng)作我們有另一種方式來執(zhí)行,那就是動(dòng)作鏈。
比如我們現(xiàn)在實(shí)現(xiàn)一個(gè)節(jié)點(diǎn)的拖拽操作,將某個(gè)節(jié)點(diǎn)從一處拖拽到另外一處,可以用代碼這樣實(shí)現(xiàn):

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
browser.get(url)
browser.switch_to.frame("iframeResult")
source = browser.find_element_by_css_selector("#draggable")
target = browser.find_element_by_css_selector("#droppable")
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()

首先我們打開網(wǎng)頁中的一個(gè)拖拽實(shí)例,然后依次選中要被拖拽的節(jié)點(diǎn)和拖拽到的目標(biāo)節(jié)點(diǎn),然后聲明了 ActionChains 對(duì)象賦值為 actions 變量,然后通過調(diào)用 actions 變量的 drag_and_drop() 方法,然后再調(diào)用 perform() 方法執(zhí)行動(dòng)作,就完成了拖拽操作,如圖 7-4 和 7-5 所示:

圖 7-4 拖拽前頁面

圖 7-5 拖拽后頁面
以上兩圖分別為在拖拽前和拖拽后的結(jié)果。
更多的動(dòng)作鏈操作可以參考官方文檔的動(dòng)作鏈介紹:http://selenium-python.readth...。

7. 執(zhí)行JavaScript

對(duì)于某些操作,Selenium API 是沒有提供的,如下拉進(jìn)度條等,可以直接模擬運(yùn)行 JavaScript,使用 execute_script() 方法即可實(shí)現(xiàn),代碼如下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.zhihu.com/explore")
browser.execute_script("window.scrollTo(0, document.body.scrollHeight)")
browser.execute_script("alert("To Bottom")")

在這里我們就利用了 execute_script() 方法將進(jìn)度條下拉到最底部,然后彈出 alert 提示框。
所以說有了這個(gè),基本上 API 沒有提供的所有的功能都可以用執(zhí)行 JavaScript 的方式來實(shí)現(xiàn)了。

8. 獲取節(jié)點(diǎn)信息

我們?cè)谇懊嬲f過通過 page_source 屬性可以獲取網(wǎng)頁的源代碼,獲取源代碼之后就可以使用解析庫如正則、BeautifulSoup、PyQuery 等來提取信息了。
不過既然 Selenium 已經(jīng)提供了選擇節(jié)點(diǎn)的方法,返回的是WebElement 類型,那么它也有相關(guān)的方法和屬性來直接提取節(jié)點(diǎn)信息,如屬性、文本等等。這樣的話我們就可以不用通過解析源代碼來提取信息了,非常方便。
那接下來我們就看一下可以通過怎樣的方式來獲取節(jié)點(diǎn)信息吧。

獲取屬性

我們可以使用 get_attribute() 方法來獲取節(jié)點(diǎn)的屬性,那么這個(gè)的前提就是先選中這個(gè)節(jié)點(diǎn)。
我們用一個(gè)實(shí)例來感受一下:

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
logo = browser.find_element_by_id("zh-top-link-logo")
print(logo)
print(logo.get_attribute("class"))

運(yùn)行之后程序便會(huì)驅(qū)動(dòng)瀏覽器打開知乎的頁面,然后獲取知乎的 LOGO 節(jié)點(diǎn),然后將它的 class 打印出來。
控制臺(tái)輸出結(jié)果:


zu-top-link-logo

我們通過 get_attribute() 方法,然后傳入想要獲取的屬性名,就可以得到它的值了。

獲取文本值

每個(gè) WebEelement 節(jié)點(diǎn)都有 text 屬性,我們可以通過直接調(diào)用這個(gè)屬性就可以得到節(jié)點(diǎn)內(nèi)部的文本信息了,就相當(dāng)于 BeautifulSoup 的 get_text() 方法、PyQuery 的 text() 方法。
我們用一個(gè)實(shí)例來感受一下:

from selenium import webdriver

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
input = browser.find_element_by_class_name("zu-top-add-question")
print(input.text)

在這里們依然是先打開知乎頁面,然后獲取提問按鈕這個(gè)節(jié)點(diǎn),再將其文本值打印出來。
控制臺(tái)輸出結(jié)果:

提問
獲取ID、位置、標(biāo)簽名、大小

另外 WebElement 節(jié)點(diǎn)還有一些其他的屬性,比如 id 屬性可以獲取節(jié)點(diǎn) id,location 可以獲取該節(jié)點(diǎn)在頁面中的相對(duì)位置,tag_name 可以獲取標(biāo)簽名稱,size 可以獲取節(jié)點(diǎn)的大小,也就是寬高,這些屬性有時(shí)候還是很有用的。
我們用實(shí)例來感受一下:

 from selenium import webdriver

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
input = browser.find_element_by_class_name("zu-top-add-question")
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)

在這里我們首先獲得了提問按鈕這個(gè)節(jié)點(diǎn),然后調(diào)用其 id、location、tag_name、size 屬性即可獲取對(duì)應(yīng)的屬性值。

9. 切換Frame

我們知道在網(wǎng)頁中有這樣一種節(jié)點(diǎn)叫做 iframe,也就是子Frame,相當(dāng)于頁面的子頁面,它的結(jié)構(gòu)和外部網(wǎng)頁的結(jié)構(gòu)是完全一致的。Selenium 打開頁面后,它默認(rèn)是在父級(jí)Frame 里面操作,而此時(shí)如果頁面中還有子 Frame,它是不能獲取到子 Frame 里面的節(jié)點(diǎn)的。所以這時(shí)候我們就需要使用 switch_to.frame() 方法來切換 Frame。
我們首先用一個(gè)實(shí)例來感受一下:

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
browser.get(url)
browser.switch_to.frame("iframeResult")
try:
??? logo = browser.find_element_by_class_name("logo")
except NoSuchElementException:
??? print("NO LOGO")
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name("logo")
print(logo)
print(logo.text)

控制臺(tái)輸出:

NO LOGO

RUNOOB.COM

我們還是以上文演示動(dòng)作鏈操作的網(wǎng)頁為實(shí)例,首先我們通過 switch_to.frame() 方法切換到子 Frame 里面,然后我們嘗試獲取父級(jí) Frame 里的 LOGO 節(jié)點(diǎn),是不能找到的,找不到的話就會(huì)拋出 NoSuchElementException 異常,異常被捕捉之后就會(huì)輸出 NO LOGO,接下來我們重新切換回父Frame,然后再次重新獲取節(jié)點(diǎn),發(fā)現(xiàn)就可以成功獲取了。
所以,當(dāng)頁面中包含子 Frame 時(shí),如果我們想獲取子Frame 中的節(jié)點(diǎn),需要先調(diào)用 switch_to.frame() 方法切換到對(duì)應(yīng)的 Frame,然后再進(jìn)行操作即可。

10. 延時(shí)等待

在 Selenium 中,get() 方法會(huì)在網(wǎng)頁框架加載結(jié)束之后就結(jié)束執(zhí)行,此時(shí)如果獲取 page_source 可能并不是瀏覽器完全加載完成的頁面,如果某些頁面有額外的 Ajax 請(qǐng)求,我們?cè)诰W(wǎng)頁源代碼中也不一定能成功獲取到。所以這里我們需要延時(shí)等待一定時(shí)間確保節(jié)點(diǎn)已經(jīng)加載出來。
在這里等待的方式有兩種,一種隱式等待,一種顯式等待。

隱式等待

當(dāng)使用了隱式等待執(zhí)行測試的時(shí)候,如果 Selenium 沒有在DOM 中找到節(jié)點(diǎn),將繼續(xù)等待,超出設(shè)定時(shí)間后則拋出找不到節(jié)點(diǎn)的異常, 換句話說,當(dāng)查找節(jié)點(diǎn)而節(jié)點(diǎn)并沒有立即出現(xiàn)的時(shí)候,隱式等待將等待一段時(shí)間再查找 DOM,默認(rèn)的時(shí)間是 0。
我們用一個(gè)實(shí)例來感受一下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get("https://www.zhihu.com/explore")
input = browser.find_element_by_class_name("zu-top-add-question")
print(input)

在這里我們用 implicitly_wait() 方法實(shí)現(xiàn)了隱式等待。

顯式等待

隱式等待的效果其實(shí)并沒有那么好,因?yàn)槲覀冎皇且?guī)定了一個(gè)固定時(shí)間,而頁面的加載時(shí)間是受到網(wǎng)絡(luò)條件影響的。
所以在這里還有一種更合適的顯式等待方法,它指定好要查找的節(jié)點(diǎn),然后指定一個(gè)最長等待時(shí)間。如果在規(guī)定時(shí)間內(nèi)加載出來了這個(gè)節(jié)點(diǎn),那就返回查找的節(jié)點(diǎn),如果到了規(guī)定時(shí)間依然沒有加載出該節(jié)點(diǎn),則會(huì)拋出超時(shí)異常。
我們用一個(gè)實(shí)例來感受一下:

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://www.taobao.com/")
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, "q")))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".btn-search")))
print(input, button)

在這里我們首先引入了 WebDriverWait 這個(gè)對(duì)象,指定好最長等待時(shí)間,然后調(diào)用它的 until() 方法,傳入要等待條件 expected_conditions,比如在這里我們傳入了 presence_of_element_located 這個(gè)條件,就代表節(jié)點(diǎn)出現(xiàn)的意思,其參數(shù)是節(jié)點(diǎn)的定位元組,也就是 ID 為 q 的節(jié)點(diǎn)搜索框。
所以這樣可以做到的效果就是,在 10 秒內(nèi)如果 ID 為 q 的節(jié)點(diǎn)即搜索框成功加載出來了,那就返回該節(jié)點(diǎn),如果超過10 秒還沒有加載出來,那就拋出異常。
對(duì)于按鈕,可以更改一下等待條件,比如改為 element_to_be_clickable,也就是可點(diǎn)擊,所以查找按鈕時(shí)是查找 CSS 選擇器為 .btn-search 的按鈕,如果 10 秒內(nèi)它是可點(diǎn)擊的也就是成功加載出來了,那就返回這個(gè)按鈕節(jié)點(diǎn),如果超過 10 秒還不可點(diǎn)擊,也就是沒有加載出來,那就拋出異常。
運(yùn)行代碼,在網(wǎng)速較佳的情況下是可以成功加載出來的。
控制臺(tái)輸出:


可以看到控制臺(tái)成功輸出了兩個(gè)節(jié)點(diǎn),都是 WebElement 類型。
如果網(wǎng)絡(luò)有問題,10 秒內(nèi)沒有成功加載,那就拋出TimeoutException,控制臺(tái)輸出如下:

TimeoutException Traceback (most recent call last)
 in ()
      7 browser.get("https://www.taobao.com/")
      8 wait = WebDriverWait(browser, 10)
----> 9 input = wait.until(EC.presence_of_element_located((By.ID, "q")))

關(guān)于等待條件,其實(shí)還有很多,比如判斷標(biāo)題內(nèi)容,判斷某個(gè)節(jié)點(diǎn)內(nèi)是否出現(xiàn)了某文字,在這里將所有的加載條件列舉如下:

等待條件 含義
title_is 標(biāo)題是某內(nèi)容
title_contains 標(biāo)題包含某內(nèi)容
presence_of_element_located 節(jié)點(diǎn)加載出,傳入定位元組,如(By.ID, "p")
visibility_of_element_located 節(jié)點(diǎn)可見,傳入定位元組
visibility_of 可見,傳入節(jié)點(diǎn)對(duì)象
presence_of_all_elements_located 所有節(jié)點(diǎn)加載出
text_to_be_present_in_element 某個(gè)節(jié)點(diǎn)文本包含某文字
text_to_be_present_in_element_value 某個(gè)節(jié)點(diǎn)值包含某文字
frame_to_be_available_and_switch_to_it frame 加載并切換
invisibility_of_element_located 節(jié)點(diǎn)不可見
element_to_be_clickable 節(jié)點(diǎn)可點(diǎn)擊
staleness_of 判斷一個(gè)節(jié)點(diǎn)是否仍在DOM,可判斷頁面是否已經(jīng)刷新
element_to_be_selected 節(jié)點(diǎn)可選擇,傳節(jié)點(diǎn)對(duì)象
element_located_to_be_selected 節(jié)點(diǎn)可選擇,傳入定位元組
element_selection_state_to_be 傳入節(jié)點(diǎn)對(duì)象以及狀態(tài),相等返回True,否則返回False
element_located_selection_state_to_be 傳入定位元組以及狀態(tài),相等返回True,否則返回False
alert_is_present 是否出現(xiàn)Alert

更多詳細(xì)的等待條件的參數(shù)及用法介紹可以參考官方文檔:http://selenium-python.readth...。

11. 前進(jìn)后退

我們平常使用瀏覽器都有前進(jìn)和后退功能,使用 Selenium 也可以完成這個(gè)操作,使用 back() 方法可以后退,forward() 方法可以前進(jìn)。
我們用一個(gè)實(shí)例來感受一下:

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.baidu.com/")
browser.get("https://www.taobao.com/")
browser.get("https://www.python.org/")
browser.back()
time.sleep(1)
browser.forward()
browser.close()

在這里我們連續(xù)訪問三個(gè)頁面,然后調(diào)用 back() 方法就可以回到第二個(gè)頁面,接下來再調(diào)用 forward() 方法又可以前進(jìn)到第三個(gè)頁面。

12. Cookies

使用 Selenium 還可以方便地對(duì) Cookies 進(jìn)行操作,例如獲取、添加、刪除 Cookies 等等。
我們?cè)儆脤?shí)例來感受一下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.zhihu.com/explore")
print(browser.get_cookies())
browser.add_cookie({"name": "name", "domain": "www.zhihu.com", "value": "germey"})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())

首先我們?cè)L問了知乎,然后加載完成之后,瀏覽器實(shí)際上已經(jīng)生成了 Cookies 了,我們調(diào)用 get_cookies() 方法就可以獲取所有的 Cookies,然后我們添加一個(gè) Cookie,傳入一個(gè)字典,有 name、domain、value 等內(nèi)容。接下來我們?cè)俅潍@取所有的 Cookies,可以發(fā)現(xiàn)結(jié)果就多了這一項(xiàng) Cookie。最后我們調(diào)用 delete_all_cookies() 方法,刪除所有的 Cookies,再重新獲取,結(jié)果就為空了。
控制臺(tái)輸出:

[{"secure": False, "value": ""NGM0ZTM5NDAwMWEyNDQwNDk5ODlkZWY3OTkxY2I0NDY=|1491604091|236e34290a6f407bfbb517888849ea509ac366d0"", "domain": ".zhihu.com", "path": "/", "httpOnly": False, "name": "l_cap_id", "expiry": 1494196091.403418}]
[{"secure": False, "value": "germey", "domain": ".www.zhihu.com", "path": "/", "httpOnly": False, "name": "name"}, {"secure": False, "value": ""NGM0ZTM5NDAwMWEyNDQwNDk5ODlkZWY3OTkxY2I0NDY=|1491604091|236e34290a6f407bfbb517888849ea509ac366d0"", "domain": ".zhihu.com", "path": "/", "httpOnly": False, "name": "l_cap_id", "expiry": 1494196091.403418}]
[]

通過以上方法來操作 Cookies 還是非常方便的。

13. 選項(xiàng)卡管理

我們?cè)谠L問網(wǎng)頁的時(shí)候會(huì)開啟一個(gè)個(gè)選項(xiàng)卡,那么在 Selenium 中也可以對(duì)選項(xiàng)卡進(jìn)行操作。

import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.baidu.com")
browser.execute_script("window.open()")
print(browser.window_handles)
browser.switch_to_window(browser.window_handles[1])
browser.get("https://www.taobao.com")
time.sleep(1)
browser.switch_to_window(browser.window_handles[0])
browser.get("https://python.org")

控制臺(tái)輸出:

["CDwindow-4f58e3a7-7167-4587-bedf-9cd8c867f435", "CDwindow-6e05f076-6d77-453a-a36c-32baacc447df"]

首先我們?cè)L問了百度,然后調(diào)用了 execute_script() 方法,傳入 window.open() 的 JavaScript 語句新開啟一個(gè)選項(xiàng)卡,然后接下來我們想切換到該選項(xiàng)卡,可以調(diào)用 window_handles 屬性獲取當(dāng)前開啟的所有選項(xiàng)卡,返回的是選項(xiàng)卡的代號(hào)列表,要想切換選項(xiàng)卡只需要調(diào)用 switch_to_window() 方法,傳入選項(xiàng)卡的代號(hào)即可。在這里我們將第二個(gè)選項(xiàng)卡代號(hào)傳入,即跳轉(zhuǎn)到了第二個(gè)選項(xiàng)卡,然后接下來在第二個(gè)選項(xiàng)卡下打開一個(gè)新的頁面,然后切換回第一個(gè)選項(xiàng)卡可以重新調(diào)用 switch_to_window() 方法,再執(zhí)行其他操作即可。
如此以來我們便實(shí)現(xiàn)了選項(xiàng)卡的管理。

14. 異常處理

在使用 Selenium 過程中,難免會(huì)遇到一些異常,例如超時(shí)、節(jié)點(diǎn)未找到等錯(cuò)誤,一旦出現(xiàn)此類錯(cuò)誤,程序便不會(huì)繼續(xù)運(yùn)行了,所以異常處理在程序中是十分重要的。
在這里我們可以使用 try except 語句來捕獲各種異常。
首先我們演示一下節(jié)點(diǎn)未找到的異常,示例如下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.baidu.com")
browser.find_element_by_id("hello")

在這里我們打開百度頁面,然后嘗試選擇一個(gè)并不存在的節(jié)點(diǎn),這樣就會(huì)遇到異常。
運(yùn)行之后控制臺(tái)輸出如下:

NoSuchElementException Traceback (most recent call last)
 in ()
      3 browser = webdriver.Chrome()
      4 browser.get("https://www.baidu.com")
----> 5 browser.find_element_by_id("hello")

可以看到拋出了 NoSuchElementException 這類異常,這通常是節(jié)點(diǎn)未找到的異常,為了防止程序遇到異常而中斷,我們需要捕獲一下這些異常。

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException

browser = webdriver.Chrome()
try:
??? browser.get("https://www.baidu.com")
except TimeoutException:
??? print("Time Out")
try:
??? browser.find_element_by_id("hello")
except NoSuchElementException:
??? print("No Element")
finally:
??? browser.close()

如上例所示,這里我們使用 try except 來捕獲各類異常,比如我們對(duì) find_element_by_id() 查找節(jié)點(diǎn)的方法捕獲 NoSuchElementException 異常,這樣一旦出現(xiàn)這樣的錯(cuò)誤,就進(jìn)行異常處理,程序也不會(huì)中斷了。
控制臺(tái)輸出:
No Element
更多的異常累可以參考官方文檔:http://selenium-python.readth...,如果出現(xiàn)了某個(gè)異常,我們對(duì)它進(jìn)行捕獲即可。

15. 結(jié)語

到此我們就基本對(duì) Selenium 的常用用法有了大體的了解,有了 Selenium,處理 JavaScript 不再是難事。

上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---36、分析Ajax爬取今日頭條街拍美圖
下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---38、動(dòng)態(tài)渲染頁面抓取:Splash的使用

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44108.html

相關(guān)文章

  • Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---36、分析Ajax爬取今日頭條街拍美圖

    摘要:上一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)數(shù)據(jù)爬取下一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)動(dòng)態(tài)渲染頁面抓取本節(jié)我們以今日頭條為例來嘗試通過分析請(qǐng)求來抓取網(wǎng)頁數(shù)據(jù)的方法,我們這次要抓取的目標(biāo)是今日頭條的街拍美圖,抓取完成之后將每組圖片分文件夾下載到本地保存下來。 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---35、 Ajax數(shù)據(jù)爬取下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---37、動(dòng)態(tài)渲染頁面抓取:Selenium 本節(jié)我們...

    Leck1e 評(píng)論0 收藏0
  • Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---1、請(qǐng)求庫安裝:Requests、Selenium、ChromeDr

    摘要:下一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)請(qǐng)求庫安裝爬蟲可以簡單分為幾步抓取頁面分析頁面存儲(chǔ)數(shù)據(jù)。相關(guān)鏈接官方網(wǎng)站官方文檔中文文檔安裝驗(yàn)證安裝進(jìn)入命令行交互模式,導(dǎo)入一下包,如果沒有報(bào)錯(cuò),則證明安裝成功。 下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---2、請(qǐng)求庫安裝:GeckoDriver、PhantomJS、Aiohttp 爬蟲可以簡單分為幾步:抓取頁面、分析頁面、存儲(chǔ)數(shù)據(jù)。 在第一步抓取頁面的過程中,...

    wawor4827 評(píng)論0 收藏0
  • 首次公開,整理12年積累的博客收藏夾,零距離展示《收藏夾吃灰》系列博客

    摘要:時(shí)間永遠(yuǎn)都過得那么快,一晃從年注冊(cè),到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時(shí)候把他們整理一下了。那是因?yàn)槭詹貖A太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...

    Harriet666 評(píng)論0 收藏0
  • Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---17、爬蟲基本原理

    摘要:在前面我們講到了和的概念,我們向網(wǎng)站的服務(wù)器發(fā)送一個(gè),返回的的便是網(wǎng)頁源代碼。渲染頁面有時(shí)候我們?cè)谟没蜃ト【W(wǎng)頁時(shí),得到的源代碼實(shí)際和瀏覽器中看到的是不一樣的。所以使用基本請(qǐng)求庫得到的結(jié)果源代碼可能跟瀏覽器中的頁面源代碼不太一樣。 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---16、Web網(wǎng)頁基礎(chǔ)下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---18、Session和Cookies 爬蟲,即網(wǎng)...

    hellowoody 評(píng)論0 收藏0
  • Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---2、請(qǐng)求庫安裝:GeckoDriver、PhantomJS、Aioh

    摘要:上一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)請(qǐng)求庫安裝下一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)解析庫的安裝的安裝在上一節(jié)我們了解了的配置方法,配置完成之后我們便可以用來驅(qū)動(dòng)瀏覽器來做相應(yīng)網(wǎng)頁的抓取。上一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)請(qǐng)求庫安裝下一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)解析庫的安裝 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---1、請(qǐng)求庫安裝:Requests、Selenium、ChromeDriver下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)--...

    Cristalven 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<