摘要:不過動態(tài)渲染的頁面不止這一種。再有淘寶這種頁面,它即使是獲取的數(shù)據(jù),但是其接口含有很多加密參數(shù),我們難以直接找出其規(guī)律,也很難直接分析來抓取。我們用一個實例來感受一下在這里們依然是先打開知乎頁面,然后獲取提問按鈕這個節(jié)點,再將其
上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---36、分析Ajax爬取今日頭條街拍美圖
下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---38、動態(tài)渲染頁面抓取:Splash的使用
在前面一章我們了解了 Ajax 的分析和抓取方式,這種頁面其實也是 JavaScript 動態(tài)渲染的頁面的一種情形,通過直接分析 Ajax 我們?nèi)匀豢梢越柚?Requests 或 Urllib 來實現(xiàn)數(shù)據(jù)的抓取。
不過 JavaScript 動態(tài)渲染的頁面不止 Ajax 這一種。比如中國青年網(wǎng):http://news.youth.cn/gn/,它的分頁部分是由 JavaScript 生成的,并非原始 HTML 代碼,這其中并不包含 Ajax 請求。如 ECharts 的官方實例:http://echarts.baidu.com/demo...,其圖形都是經(jīng)過 JavaScript 計算之后生成的。再有淘寶這種頁面,它即使是 Ajax 獲取的數(shù)據(jù),但是其 Ajax 接口含有很多加密參數(shù),我們難以直接找出其規(guī)律,也很難直接分析 Ajax 來抓取。
但是數(shù)據(jù)總歸是要抓取的,為了解決這些問題,我們可以直接使用模擬瀏覽器運行的方式來實現(xiàn),這樣我們就可以做到瀏覽器看到是什么樣,抓取的源碼就是什么樣,也就是可見即可爬。這樣我們就不用再去管網(wǎng)頁內(nèi)部的 JavaScript 用了什么算法渲染頁面,不用管網(wǎng)頁后臺的 Ajax 接口到底有哪些參數(shù),利用模擬瀏覽器的方式我們都可以直接獲取 JavaScript 渲染的最終結(jié)果,只要能在瀏覽器中看到,我們都能抓取。
在 Python 中提供了許多模擬瀏覽器運行的庫,如 Selenium、Splash、PyV8、Ghost 等等,本章我們介紹一下其中 Selenium 和 Splash 的用法,有了它們,我們就不用再為動態(tài)渲染的頁面發(fā)愁了。
Selenium的使用Selenium 是一個自動化測試工具,利用它我們可以驅(qū)動瀏覽器執(zhí)行特定的動作,如點擊、下拉等等操作,同時還可以獲取瀏覽器當前呈現(xiàn)的頁面的源代碼,做到可見即可爬。對于一些 JavaScript 動態(tài)渲染的頁面來說,此種抓取方式非常有效,本節(jié)讓我們來感受一下它的強大之處吧。
1. 準備工作本節(jié)以 Chrome 為例來講解 Selenium 的用法,在本節(jié)開始之前請確保已經(jīng)正確安裝好了 Chrome 瀏覽器并配置好了 ChromeDriver,另外還需要正確安裝好 Python 的 Selenium 庫,詳細的過程可以參考第一章的安裝和配置說明。
2. 基本使用準備工作做好之后,首先我們來大體看一下 Selenium 有一些怎樣的功能,先用一段實例代碼來感受一下:
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()
運行代碼之后可以發(fā)現(xiàn)會自動彈出一個 Chrome 瀏覽器,瀏覽器首先會跳轉(zhuǎn)到百度,然后在搜索框中輸入 Python 進行搜索,然后跳轉(zhuǎn)到搜索結(jié)果頁,等待搜索結(jié)果加載出來之后,控制臺分別會輸出當前的 URL,當前的 Cookies 還有網(wǎng)頁源代碼,如圖 7-1 所示:
圖 7-1 運行結(jié)果
在jon g zhi tai可以看到我們得到的當前的 URL、Cookies、源代碼都是瀏覽器中的真實內(nèi)容。
所以說,如果我們用 Selenium 來驅(qū)動瀏覽器加載網(wǎng)頁的話,我們就可以直接拿到 JavaScript 渲染的結(jié)果了,不管是什么加密統(tǒng)統(tǒng)不用再需要擔(dān)心。
下面我們來詳細了解一下Selenium的用法。
Selenium 支持非常多的瀏覽器,如 Chrome、Firefox、Edge 等,還有手機端的瀏覽器 Android、BlackBerry 等,另外無界面瀏覽器 PhantomJS 也同樣支持。
我們可以用如下的方式初始化:
from selenium import webdriver browser = webdriver.Chrome() browser = webdriver.Firefox() browser = webdriver.Edge() browser = webdriver.PhantomJS() browser = webdriver.Safari()
這樣我們就完成了瀏覽器對象的初始化并賦值為 browser 對象,接下來我們要做的就是調(diào)用 browser 對象,讓其執(zhí)行各個動作,就可以模擬瀏覽器操作了。
3. 訪問頁面我們可以用 get() 方法來請求一個網(wǎng)頁,參數(shù)傳入鏈接 URL 即可,比如在這里我們用 get() 方法訪問淘寶,然后打印出源代碼,代碼如下:
from selenium import webdriver browser = webdriver.Chrome() browser.get("https://www.taobao.com") print(browser.page_source) browser.close()
運行之后我們便發(fā)現(xiàn)彈出了 Chrome 瀏覽器,自動訪問了淘寶,然后控制臺輸出了淘寶頁面的源代碼,隨后瀏覽器關(guān)閉。
通過這幾行簡單的代碼我們便可以實現(xiàn)瀏覽器的驅(qū)動并獲取網(wǎng)頁源碼,非常便捷。
Selenium 可以驅(qū)動瀏覽器完成各種操作,比如填充表單、模擬點擊等等,比如我們想要完成向某個輸入框輸入文字的操作,總得需要知道這個輸入框在哪里吧?所以 Selenium 提供了一系列查找節(jié)點的方法,我們可以用這些方法來獲取想要的節(jié)點,以便于下一步執(zhí)行一些動作或者提取信息。
單個節(jié)點比如我們想要從淘寶頁面中提取搜索框這個節(jié)點,首先觀察它的源代碼,如圖 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 等獲取的方式。
我們用代碼實現(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é)果是完全一致的。
運行結(jié)果:
可以看到三個節(jié)點都是 WebElement 類型,是完全一致的。
在這里列出所有獲取單個節(jié)點的方法:
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() 方法,它需要傳入兩個參數(shù),一個是查找的方式 By,另一個就是值,實際上它就是 find_element_by_id() 這種方法的通用函數(shù)版本,比如 find_element_by_id(id) 就等價于 find_element(By.ID, id),二者得到的結(jié)果完全一致。
我們用代碼實現(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ù)更加靈活。
多個節(jié)點如果我們查找的目標在網(wǎng)頁中只有一個,那么完全可以用 find_element() 方法,但如果有多個節(jié)點,再用 find_element() 方法查找就只能得到第一個節(jié)點了,如果要查找所有滿足條件的節(jié)點,那就需要用 find_elements() 這樣的方法,方法名稱中 element 多了一個 s ,注意區(qū)分。
比如我們在這里查找淘寶左側(cè)導(dǎo)航條的所有條目,如圖 7-3 所示:
圖 7-3 導(dǎo)航欄
就可以這樣來實現(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()
運行結(jié)果:
[, , ···]
在此簡化了一下輸出結(jié)果,中間部分省略。
可以看到得到的內(nèi)容就變成了列表類型,列表的每個節(jié)點都是 WebElement 類型。
也就是說,如果我們用 find_element() 方法,只能獲取匹配的第一個節(jié)點,結(jié)果是 WebElement 類型,如果用 find_elements() 方法,則結(jié)果是列表類型,列表的每個節(jié)點是 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
當然我們和剛才一樣,也可可以直接 find_elements() 方法來選擇,所以也可以這樣來寫:
lis = browser.find_elements(By.CSS_SELECTOR, ".service-bd li")
結(jié)果是完全一致的。
5. 節(jié)點交互Selenium 可以驅(qū)動瀏覽器來執(zhí)行一些操作,也就是說我們可以讓瀏覽器模擬執(zhí)行一些動作,比較常見的用法有:
輸入文字用 send_keys() 方法,清空文字用 clear() 方法,另外還有按鈕點擊,用 click() 方法。
我們用一個實例來感受一下:
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ū)動瀏覽器打開淘寶,然后用 find_element_by_id() 方法獲取輸入框,然后用 send_keys() 方法輸入 iPhone 文字,等待一秒之后用 clear() 方法清空輸入框,再次調(diào)用 send_keys() 方法輸入 iPad 文字,之后再用 find_element_by_class_name() 方法獲取搜索按鈕,最后調(diào)用 click() 方法完成搜索動作。
通過上面的方法我們就完成了一些常見節(jié)點的動作操作,更多的操作可以參見官方文檔的交互動作介紹:http://selenium-python.readth...。
在上面的實例中,一些交互動作都是針對某個節(jié)點執(zhí)行的,比如輸入框我們就調(diào)用它的輸入文字和清空文字方法,按鈕就調(diào)用它的點擊方法,其實還有另外的一些操作它是沒有特定的執(zhí)行對象的,比如鼠標拖拽、鍵盤按鍵等操作。所以這些動作我們有另一種方式來執(zhí)行,那就是動作鏈。
比如我們現(xiàn)在實現(xiàn)一個節(jié)點的拖拽操作,將某個節(jié)點從一處拖拽到另外一處,可以用代碼這樣實現(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)頁中的一個拖拽實例,然后依次選中要被拖拽的節(jié)點和拖拽到的目標節(jié)點,然后聲明了 ActionChains 對象賦值為 actions 變量,然后通過調(diào)用 actions 變量的 drag_and_drop() 方法,然后再調(diào)用 perform() 方法執(zhí)行動作,就完成了拖拽操作,如圖 7-4 和 7-5 所示:
圖 7-4 拖拽前頁面
圖 7-5 拖拽后頁面
以上兩圖分別為在拖拽前和拖拽后的結(jié)果。
更多的動作鏈操作可以參考官方文檔的動作鏈介紹:http://selenium-python.readth...。
對于某些操作,Selenium API 是沒有提供的,如下拉進度條等,可以直接模擬運行 JavaScript,使用 execute_script() 方法即可實現(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() 方法將進度條下拉到最底部,然后彈出 alert 提示框。
所以說有了這個,基本上 API 沒有提供的所有的功能都可以用執(zhí)行 JavaScript 的方式來實現(xiàn)了。
我們在前面說過通過 page_source 屬性可以獲取網(wǎng)頁的源代碼,獲取源代碼之后就可以使用解析庫如正則、BeautifulSoup、PyQuery 等來提取信息了。
不過既然 Selenium 已經(jīng)提供了選擇節(jié)點的方法,返回的是WebElement 類型,那么它也有相關(guān)的方法和屬性來直接提取節(jié)點信息,如屬性、文本等等。這樣的話我們就可以不用通過解析源代碼來提取信息了,非常方便。
那接下來我們就看一下可以通過怎樣的方式來獲取節(jié)點信息吧。
我們可以使用 get_attribute() 方法來獲取節(jié)點的屬性,那么這個的前提就是先選中這個節(jié)點。
我們用一個實例來感受一下:
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"))
運行之后程序便會驅(qū)動瀏覽器打開知乎的頁面,然后獲取知乎的 LOGO 節(jié)點,然后將它的 class 打印出來。
控制臺輸出結(jié)果:
zu-top-link-logo
我們通過 get_attribute() 方法,然后傳入想要獲取的屬性名,就可以得到它的值了。
獲取文本值每個 WebEelement 節(jié)點都有 text 屬性,我們可以通過直接調(diào)用這個屬性就可以得到節(jié)點內(nèi)部的文本信息了,就相當于 BeautifulSoup 的 get_text() 方法、PyQuery 的 text() 方法。
我們用一個實例來感受一下:
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)
在這里們依然是先打開知乎頁面,然后獲取提問按鈕這個節(jié)點,再將其文本值打印出來。
控制臺輸出結(jié)果:
提問獲取ID、位置、標簽名、大小
另外 WebElement 節(jié)點還有一些其他的屬性,比如 id 屬性可以獲取節(jié)點 id,location 可以獲取該節(jié)點在頁面中的相對位置,tag_name 可以獲取標簽名稱,size 可以獲取節(jié)點的大小,也就是寬高,這些屬性有時候還是很有用的。
我們用實例來感受一下:
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)
在這里我們首先獲得了提問按鈕這個節(jié)點,然后調(diào)用其 id、location、tag_name、size 屬性即可獲取對應(yīng)的屬性值。
9. 切換Frame我們知道在網(wǎng)頁中有這樣一種節(jié)點叫做 iframe,也就是子Frame,相當于頁面的子頁面,它的結(jié)構(gòu)和外部網(wǎng)頁的結(jié)構(gòu)是完全一致的。Selenium 打開頁面后,它默認是在父級Frame 里面操作,而此時如果頁面中還有子 Frame,它是不能獲取到子 Frame 里面的節(jié)點的。所以這時候我們就需要使用 switch_to.frame() 方法來切換 Frame。
我們首先用一個實例來感受一下:
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)
控制臺輸出:
NO LOGORUNOOB.COM
我們還是以上文演示動作鏈操作的網(wǎng)頁為實例,首先我們通過 switch_to.frame() 方法切換到子 Frame 里面,然后我們嘗試獲取父級 Frame 里的 LOGO 節(jié)點,是不能找到的,找不到的話就會拋出 NoSuchElementException 異常,異常被捕捉之后就會輸出 NO LOGO,接下來我們重新切換回父Frame,然后再次重新獲取節(jié)點,發(fā)現(xiàn)就可以成功獲取了。
所以,當頁面中包含子 Frame 時,如果我們想獲取子Frame 中的節(jié)點,需要先調(diào)用 switch_to.frame() 方法切換到對應(yīng)的 Frame,然后再進行操作即可。
在 Selenium 中,get() 方法會在網(wǎng)頁框架加載結(jié)束之后就結(jié)束執(zhí)行,此時如果獲取 page_source 可能并不是瀏覽器完全加載完成的頁面,如果某些頁面有額外的 Ajax 請求,我們在網(wǎng)頁源代碼中也不一定能成功獲取到。所以這里我們需要延時等待一定時間確保節(jié)點已經(jīng)加載出來。
在這里等待的方式有兩種,一種隱式等待,一種顯式等待。
當使用了隱式等待執(zhí)行測試的時候,如果 Selenium 沒有在DOM 中找到節(jié)點,將繼續(xù)等待,超出設(shè)定時間后則拋出找不到節(jié)點的異常, 換句話說,當查找節(jié)點而節(jié)點并沒有立即出現(xiàn)的時候,隱式等待將等待一段時間再查找 DOM,默認的時間是 0。
我們用一個實例來感受一下:
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() 方法實現(xiàn)了隱式等待。
顯式等待隱式等待的效果其實并沒有那么好,因為我們只是規(guī)定了一個固定時間,而頁面的加載時間是受到網(wǎng)絡(luò)條件影響的。
所以在這里還有一種更合適的顯式等待方法,它指定好要查找的節(jié)點,然后指定一個最長等待時間。如果在規(guī)定時間內(nèi)加載出來了這個節(jié)點,那就返回查找的節(jié)點,如果到了規(guī)定時間依然沒有加載出該節(jié)點,則會拋出超時異常。
我們用一個實例來感受一下:
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 這個對象,指定好最長等待時間,然后調(diào)用它的 until() 方法,傳入要等待條件 expected_conditions,比如在這里我們傳入了 presence_of_element_located 這個條件,就代表節(jié)點出現(xiàn)的意思,其參數(shù)是節(jié)點的定位元組,也就是 ID 為 q 的節(jié)點搜索框。
所以這樣可以做到的效果就是,在 10 秒內(nèi)如果 ID 為 q 的節(jié)點即搜索框成功加載出來了,那就返回該節(jié)點,如果超過10 秒還沒有加載出來,那就拋出異常。
對于按鈕,可以更改一下等待條件,比如改為 element_to_be_clickable,也就是可點擊,所以查找按鈕時是查找 CSS 選擇器為 .btn-search 的按鈕,如果 10 秒內(nèi)它是可點擊的也就是成功加載出來了,那就返回這個按鈕節(jié)點,如果超過 10 秒還不可點擊,也就是沒有加載出來,那就拋出異常。
運行代碼,在網(wǎng)速較佳的情況下是可以成功加載出來的。
控制臺輸出:
可以看到控制臺成功輸出了兩個節(jié)點,都是 WebElement 類型。
如果網(wǎng)絡(luò)有問題,10 秒內(nèi)沒有成功加載,那就拋出TimeoutException,控制臺輸出如下:
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)于等待條件,其實還有很多,比如判斷標題內(nèi)容,判斷某個節(jié)點內(nèi)是否出現(xiàn)了某文字,在這里將所有的加載條件列舉如下:
等待條件 | 含義 |
---|---|
title_is | 標題是某內(nèi)容 |
title_contains | 標題包含某內(nèi)容 |
presence_of_element_located | 節(jié)點加載出,傳入定位元組,如(By.ID, "p") |
visibility_of_element_located | 節(jié)點可見,傳入定位元組 |
visibility_of | 可見,傳入節(jié)點對象 |
presence_of_all_elements_located | 所有節(jié)點加載出 |
text_to_be_present_in_element | 某個節(jié)點文本包含某文字 |
text_to_be_present_in_element_value | 某個節(jié)點值包含某文字 |
frame_to_be_available_and_switch_to_it frame | 加載并切換 |
invisibility_of_element_located | 節(jié)點不可見 |
element_to_be_clickable | 節(jié)點可點擊 |
staleness_of | 判斷一個節(jié)點是否仍在DOM,可判斷頁面是否已經(jīng)刷新 |
element_to_be_selected | 節(jié)點可選擇,傳節(jié)點對象 |
element_located_to_be_selected | 節(jié)點可選擇,傳入定位元組 |
element_selection_state_to_be | 傳入節(jié)點對象以及狀態(tài),相等返回True,否則返回False |
element_located_selection_state_to_be | 傳入定位元組以及狀態(tài),相等返回True,否則返回False |
alert_is_present | 是否出現(xiàn)Alert |
更多詳細的等待條件的參數(shù)及用法介紹可以參考官方文檔:http://selenium-python.readth...。
11. 前進后退我們平常使用瀏覽器都有前進和后退功能,使用 Selenium 也可以完成這個操作,使用 back() 方法可以后退,forward() 方法可以前進。
我們用一個實例來感受一下:
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ù)訪問三個頁面,然后調(diào)用 back() 方法就可以回到第二個頁面,接下來再調(diào)用 forward() 方法又可以前進到第三個頁面。
12. Cookies使用 Selenium 還可以方便地對 Cookies 進行操作,例如獲取、添加、刪除 Cookies 等等。
我們再用實例來感受一下:
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())
首先我們訪問了知乎,然后加載完成之后,瀏覽器實際上已經(jīng)生成了 Cookies 了,我們調(diào)用 get_cookies() 方法就可以獲取所有的 Cookies,然后我們添加一個 Cookie,傳入一個字典,有 name、domain、value 等內(nèi)容。接下來我們再次獲取所有的 Cookies,可以發(fā)現(xiàn)結(jié)果就多了這一項 Cookie。最后我們調(diào)用 delete_all_cookies() 方法,刪除所有的 Cookies,再重新獲取,結(jié)果就為空了。
控制臺輸出:
[{"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. 選項卡管理我們在訪問網(wǎng)頁的時候會開啟一個個選項卡,那么在 Selenium 中也可以對選項卡進行操作。
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")
控制臺輸出:
["CDwindow-4f58e3a7-7167-4587-bedf-9cd8c867f435", "CDwindow-6e05f076-6d77-453a-a36c-32baacc447df"]
首先我們訪問了百度,然后調(diào)用了 execute_script() 方法,傳入 window.open() 的 JavaScript 語句新開啟一個選項卡,然后接下來我們想切換到該選項卡,可以調(diào)用 window_handles 屬性獲取當前開啟的所有選項卡,返回的是選項卡的代號列表,要想切換選項卡只需要調(diào)用 switch_to_window() 方法,傳入選項卡的代號即可。在這里我們將第二個選項卡代號傳入,即跳轉(zhuǎn)到了第二個選項卡,然后接下來在第二個選項卡下打開一個新的頁面,然后切換回第一個選項卡可以重新調(diào)用 switch_to_window() 方法,再執(zhí)行其他操作即可。
如此以來我們便實現(xiàn)了選項卡的管理。
在使用 Selenium 過程中,難免會遇到一些異常,例如超時、節(jié)點未找到等錯誤,一旦出現(xiàn)此類錯誤,程序便不會繼續(xù)運行了,所以異常處理在程序中是十分重要的。
在這里我們可以使用 try except 語句來捕獲各種異常。
首先我們演示一下節(jié)點未找到的異常,示例如下:
from selenium import webdriver browser = webdriver.Chrome() browser.get("https://www.baidu.com") browser.find_element_by_id("hello")
在這里我們打開百度頁面,然后嘗試選擇一個并不存在的節(jié)點,這樣就會遇到異常。
運行之后控制臺輸出如下:
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é)點未找到的異常,為了防止程序遇到異常而中斷,我們需要捕獲一下這些異常。
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 來捕獲各類異常,比如我們對 find_element_by_id() 查找節(jié)點的方法捕獲 NoSuchElementException 異常,這樣一旦出現(xiàn)這樣的錯誤,就進行異常處理,程序也不會中斷了。
控制臺輸出:
No Element
更多的異常累可以參考官方文檔:http://selenium-python.readth...,如果出現(xiàn)了某個異常,我們對它進行捕獲即可。
到此我們就基本對 Selenium 的常用用法有了大體的了解,有了 Selenium,處理 JavaScript 不再是難事。
上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---36、分析Ajax爬取今日頭條街拍美圖
下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---38、動態(tài)渲染頁面抓取:Splash的使用
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/44108.html
摘要:上一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)數(shù)據(jù)爬取下一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)動態(tài)渲染頁面抓取本節(jié)我們以今日頭條為例來嘗試通過分析請求來抓取網(wǎng)頁數(shù)據(jù)的方法,我們這次要抓取的目標是今日頭條的街拍美圖,抓取完成之后將每組圖片分文件夾下載到本地保存下來。 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---35、 Ajax數(shù)據(jù)爬取下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---37、動態(tài)渲染頁面抓取:Selenium 本節(jié)我們...
摘要:下一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)請求庫安裝爬蟲可以簡單分為幾步抓取頁面分析頁面存儲數(shù)據(jù)。相關(guān)鏈接官方網(wǎng)站官方文檔中文文檔安裝驗證安裝進入命令行交互模式,導(dǎo)入一下包,如果沒有報錯,則證明安裝成功。 下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---2、請求庫安裝:GeckoDriver、PhantomJS、Aiohttp 爬蟲可以簡單分為幾步:抓取頁面、分析頁面、存儲數(shù)據(jù)。 在第一步抓取頁面的過程中,...
摘要:時間永遠都過得那么快,一晃從年注冊,到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時候把他們整理一下了。那是因為收藏夾太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...
摘要:在前面我們講到了和的概念,我們向網(wǎng)站的服務(wù)器發(fā)送一個,返回的的便是網(wǎng)頁源代碼。渲染頁面有時候我們在用或抓取網(wǎng)頁時,得到的源代碼實際和瀏覽器中看到的是不一樣的。所以使用基本請求庫得到的結(jié)果源代碼可能跟瀏覽器中的頁面源代碼不太一樣。 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---16、Web網(wǎng)頁基礎(chǔ)下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---18、Session和Cookies 爬蟲,即網(wǎng)...
摘要:上一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)請求庫安裝下一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)解析庫的安裝的安裝在上一節(jié)我們了解了的配置方法,配置完成之后我們便可以用來驅(qū)動瀏覽器來做相應(yīng)網(wǎng)頁的抓取。上一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)請求庫安裝下一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)解析庫的安裝 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---1、請求庫安裝:Requests、Selenium、ChromeDriver下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)--...
閱讀 3197·2021-11-10 11:36
閱讀 3145·2021-11-02 14:39
閱讀 1726·2021-09-26 10:11
閱讀 4928·2021-09-22 15:57
閱讀 1685·2021-09-09 11:36
閱讀 2053·2019-08-30 12:56
閱讀 3487·2019-08-30 11:17
閱讀 1701·2019-08-29 17:17