在前面一章咱們瞭解了 Ajax 的分析和抓取方式,這種頁面其實也是 JavaScript 動態渲染的頁面的一種情形,經過直接分析 Ajax 咱們仍然能夠藉助於 Requests 或 Urllib 來實現數據的抓取。php
不過 JavaScript 動態渲染的頁面不止 Ajax 這一種。好比中國青年網:http://news.youth.cn/gn/,它的分頁部分是由 JavaScript 生成的,並不是原始 HTML 代碼,這其中並不包含 Ajax 請求。如 ECharts 的官方實例:http://echarts.baidu.com/demo...,其圖形都是通過 JavaScript 計算以後生成的。再有淘寶這種頁面,它即便是 Ajax 獲取的數據,可是其 Ajax 接口含有不少加密參數,咱們難以直接找出其規律,也很難直接分析 Ajax 來抓取。css
可是數據總歸是要抓取的,爲了解決這些問題,咱們能夠直接使用模擬瀏覽器運行的方式來實現,這樣咱們就能夠作到瀏覽器看到是什麼樣,抓取的源碼就是什麼樣,也就是可見便可爬。這樣咱們就不用再去管網頁內部的 JavaScript 用了什麼算法渲染頁面,不用管網頁後臺的 Ajax 接口到底有哪些參數,利用模擬瀏覽器的方式咱們均可以直接獲取 JavaScript 渲染的最終結果,只要能在瀏覽器中看到,咱們都能抓取。html
在 Python 中提供了許多模擬瀏覽器運行的庫,如 Selenium、Splash、PyV八、Ghost 等等,本章咱們介紹一下其中 Selenium 和 Splash 的用法,有了它們,咱們就不用再爲動態渲染的頁面發愁了。python
Selenium 是一個自動化測試工具,利用它咱們能夠驅動瀏覽器執行特定的動做,如點擊、下拉等等操做,同時還能夠獲取瀏覽器當前呈現的頁面的源代碼,作到可見便可爬。對於一些 JavaScript 動態渲染的頁面來講,此種抓取方式很是有效,本節讓咱們來感覺一下它的強大之處吧。jquery
本節以 Chrome 爲例來說解 Selenium 的用法,在本節開始以前請確保已經正確安裝好了 Chrome 瀏覽器並配置好了 ChromeDriver,另外還須要正確安裝好 Python 的 Selenium 庫,詳細的過程能夠參考第一章的安裝和配置說明。web
準備工做作好以後,首先咱們來大致看一下 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() Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這裏是Python學習者的彙集地,零基礎,進階,都歡迎
運行代碼以後能夠發現會自動彈出一個 Chrome 瀏覽器,瀏覽器首先會跳轉到百度,而後在搜索框中輸入 Python 進行搜索,而後跳轉到搜索結果頁,等待搜索結果加載出來以後,控制檯分別會輸出當前的 URL,當前的 Cookies 還有網頁源代碼,如圖 7-1 所示:api
圖 7-1 運行結果
在jon g zhi tai能夠看到咱們獲得的當前的 URL、Cookies、源代碼都是瀏覽器中的真實內容。
因此說,若是咱們用 Selenium 來驅動瀏覽器加載網頁的話,咱們就能夠直接拿到 JavaScript 渲染的結果了,無論是什麼加密通通不用再須要擔憂。
下面咱們來詳細瞭解一下Selenium的用法。瀏覽器
Selenium 支持很是多的瀏覽器,如 Chrome、Firefox、Edge 等,還有手機端的瀏覽器 Android、BlackBerry 等,另外×××面瀏覽器 PhantomJS 也一樣支持。
咱們能夠用以下的方式初始化:cookie
from selenium import webdriver browser = webdriver.Chrome() browser = webdriver.Firefox() browser = webdriver.Edge() browser = webdriver.PhantomJS() browser = webdriver.Safari()
這樣咱們就完成了瀏覽器對象的初始化並賦值爲 browser 對象,接下來咱們要作的就是調用 browser 對象,讓其執行各個動做,就能夠模擬瀏覽器操做了。
咱們能夠用 get() 方法來請求一個網頁,參數傳入連接 URL 便可,好比在這裏咱們用 get() 方法訪問淘寶,而後打印出源代碼,代碼以下:
from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') print(browser.page_source) browser.close()
運行以後咱們便發現彈出了 Chrome 瀏覽器,自動訪問了淘寶,而後控制檯輸出了淘寶頁面的源代碼,隨後瀏覽器關閉。
經過這幾行簡單的代碼咱們即可以實現瀏覽器的驅動並獲取網頁源碼,很是便捷。
Selenium 能夠驅動瀏覽器完成各類操做,好比填充表單、模擬點擊等等,好比咱們想要完成向某個輸入框輸入文字的操做,總得須要知道這個輸入框在哪裏吧?因此 Selenium 提供了一系列查找節點的方法,咱們能夠用這些方法來獲取想要的節點,以便於下一步執行一些動做或者提取信息。
好比咱們想要從淘寶頁面中提取搜索框這個節點,首先觀察它的源代碼,如圖 7-2 所示:
圖 7-2 源代碼
能夠發現它的 ID 是 q,Name 也是 q,還有許多其餘屬性,那咱們獲取它的方式就有多種形式了,好比find_element_by_name() 是根據 Name 值獲取,ind_element_by_id() 是根據 ID 獲取,另外還有根據XPath、CSS Selector 等獲取的方式。
咱們用代碼實現一下:
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('//*[@id="q"]') print(input_first, input_second, input_third) browser.close()
在這裏咱們使用了三種方式獲取輸入框,根據 ID、CSS Selector 和 XPath 獲取,它們返回的結果是徹底一致的。
運行結果:
<selenium.webdriver.remote.webelement.WebElement (session="764d5dc3113b4c60c143c4d69f91e60d", element="43e07ede-d084-474e-a03c-20451c4a4f51")> <selenium.webdriver.remote.webelement.WebElement (session="764d5dc3113b4c60c143c4d69f91e60d", element="43e07ede-d084-474e-a03c-20451c4a4f51")> <selenium.webdriver.remote.webelement.WebElement (session="764d5dc3113b4c60c143c4d69f91e60d", element="43e07ede-d084-474e-a03c-20451c4a4f51")>
能夠看到三個節點都是 WebElement 類型,是徹底一致的。
在這裏列出全部獲取單個節點的方法:
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() 方法,它須要傳入兩個參數,一個是查找的方式 By,另外一個就是值,實際上它就是 find_element_by_id() 這種方法的通用函數版本,好比 find_element_by_id(id) 就等價於 find_element(By.ID, id),兩者獲得的結果徹底一致。
咱們用代碼實現一下:
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()
這樣的查找方式實際上功能和上面列舉的查找函數徹底一致,不過參數更加靈活。
若是咱們查找的目標在網頁中只有一個,那麼徹底能夠用 find_element() 方法,但若是有多個節點,再用 find_element() 方法查找就只能獲得第一個節點了,若是要查找全部知足條件的節點,那就須要用 find_elements() 這樣的方法,方法名稱中 element 多了一個 s ,注意區分。
好比咱們在這裏查找淘寶左側導航條的全部條目,如圖 7-3 所示:
圖 7-3 導航欄
就能夠這樣來實現:
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()
運行結果:
[<selenium.webdriver.remote.webelement.WebElement (session="de61fc129db58e372b39e6a56452fcdf", element="f460bc2b-04a7-4659-a08f-e39026f44f78")>, <selenium.webdriver.remote.webelement.WebElement (session="de61fc129db58e372b39e6a56452fcdf", element="64d9673d-967e-4c45-bb09-60b6efc5ee2b")>, ···]
在此簡化了一下輸出結果,中間部分省略。
能夠看到獲得的內容就變成了列表類型,列表的每一個節點都是 WebElement 類型。
也就是說,若是咱們用 find_element() 方法,只能獲取匹配的第一個節點,結果是 WebElement 類型,若是用 find_elements() 方法,則結果是列表類型,列表的每一個節點是 WebElement 類型。
函數的列表以下:
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')
結果是徹底一致的。
Selenium 能夠驅動瀏覽器來執行一些操做,也就是說咱們可讓瀏覽器模擬執行一些動做,比較常見的用法有:
輸入文字用 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()
在這裏咱們首先驅動瀏覽器打開淘寶,而後用 find_element_by_id() 方法獲取輸入框,而後用 send_keys() 方法輸入 iPhone 文字,等待一秒以後用 clear() 方法清空輸入框,再次調用 send_keys() 方法輸入 iPad 文字,以後再用 find_element_by_class_name() 方法獲取搜索按鈕,最後調用 click() 方法完成搜索動做。
經過上面的方法咱們就完成了一些常見節點的動做操做,更多的操做能夠參見官方文檔的交互動做介紹:http://selenium-python.readth...。
在上面的實例中,一些交互動做都是針對某個節點執行的,好比輸入框咱們就調用它的輸入文字和清空文字方法,按鈕就調用它的點擊方法,其實還有另外的一些操做它是沒有特定的執行對象的,好比鼠標拖拽、鍵盤按鍵等操做。因此這些動做咱們有另外一種方式來執行,那就是動做鏈。
好比咱們如今實現一個節點的拖拽操做,將某個節點從一處拖拽到另一處,能夠用代碼這樣實現:
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()
首先咱們打開網頁中的一個拖拽實例,而後依次選中要被拖拽的節點和拖拽到的目標節點,而後聲明瞭 ActionChains 對象賦值爲 actions 變量,而後經過調用 actions 變量的 drag_and_drop() 方法,而後再調用 perform() 方法執行動做,就完成了拖拽操做,如圖 7-4 和 7-5 所示:
圖 7-4 拖拽前頁面
圖 7-5 拖拽後頁面
以上兩圖分別爲在拖拽前和拖拽後的結果。
更多的動做鏈操做能夠參考官方文檔的動做鏈介紹:http://selenium-python.readth...。
對於某些操做,Selenium API 是沒有提供的,以下拉進度條等,能夠直接模擬運行 JavaScript,使用 execute_script() 方法便可實現,代碼以下:
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 沒有提供的全部的功能均可以用執行 JavaScript 的方式來實現了。
咱們在前面說過經過 page_source 屬性能夠獲取網頁的源代碼,獲取源代碼以後就可使用解析庫如正則、BeautifulSoup、PyQuery 等來提取信息了。
不過既然 Selenium 已經提供了選擇節點的方法,返回的是WebElement 類型,那麼它也有相關的方法和屬性來直接提取節點信息,如屬性、文本等等。這樣的話咱們就能夠不用經過解析源代碼來提取信息了,很是方便。
那接下來咱們就看一下能夠經過怎樣的方式來獲取節點信息吧。
咱們可使用 get_attribute() 方法來獲取節點的屬性,那麼這個的前提就是先選中這個節點。
咱們用一個實例來感覺一下:
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'))
運行以後程序便會驅動瀏覽器打開知乎的頁面,而後獲取知乎的 LOGO 節點,而後將它的 class 打印出來。
控制檯輸出結果:
<selenium.webdriver.remote.webelement.WebElement (session="e08c0f28d7f44d75ccd50df6bb676104", element="0.7236390660048155-1")> zu-top-link-logo
咱們經過 get_attribute() 方法,而後傳入想要獲取的屬性名,就能夠獲得它的值了。
每一個 WebEelement 節點都有 text 屬性,咱們能夠經過直接調用這個屬性就能夠獲得節點內部的文本信息了,就至關於 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)
在這裏們依然是先打開知乎頁面,而後獲取提問按鈕這個節點,再將其文本值打印出來。
控制檯輸出結果:
提問
另外 WebElement 節點還有一些其餘的屬性,好比 id 屬性能夠獲取節點 id,location 能夠獲取該節點在頁面中的相對位置,tag_name 能夠獲取標籤名稱,size 能夠獲取節點的大小,也就是寬高,這些屬性有時候仍是頗有用的。
咱們用實例來感覺一下:
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)
在這裏咱們首先得到了提問按鈕這個節點,而後調用其 id、location、tag_name、size 屬性便可獲取對應的屬性值。
咱們知道在網頁中有這樣一種節點叫作 iframe,也就是子Frame,至關於頁面的子頁面,它的結構和外部網頁的結構是徹底一致的。Selenium 打開頁面後,它默認是在父級Frame 裏面操做,而此時若是頁面中還有子 Frame,它是不能獲取到子 Frame 裏面的節點的。因此這時候咱們就須要使用 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 LOGO <selenium.webdriver.remote.webelement.WebElement (session="4bb8ac03ced4ecbdefef03ffdc0e4ccd", element="0.13792611320464965-2")> RUNOOB.COM
咱們仍是以上文演示動做鏈操做的網頁爲實例,首先咱們經過 switch_to.frame() 方法切換到子 Frame 裏面,而後咱們嘗試獲取父級 Frame 裏的 LOGO 節點,是不能找到的,找不到的話就會拋出 NoSuchElementException 異常,異常被捕捉以後就會輸出 NO LOGO,接下來咱們從新切換回父Frame,而後再次從新獲取節點,發現就能夠成功獲取了。
因此,當頁面中包含子 Frame 時,若是咱們想獲取子Frame 中的節點,須要先調用 switch_to.frame() 方法切換到對應的 Frame,而後再進行操做便可。
在 Selenium 中,get() 方法會在網頁框架加載結束以後就結束執行,此時若是獲取 page_source 可能並非瀏覽器徹底加載完成的頁面,若是某些頁面有額外的 Ajax 請求,咱們在網頁源代碼中也不必定能成功獲取到。因此這裏咱們須要延時等待必定時間確保節點已經加載出來。
在這裏等待的方式有兩種,一種隱式等待,一種顯式等待。
當使用了隱式等待執行測試的時候,若是 Selenium 沒有在DOM 中找到節點,將繼續等待,超出設定時間後則拋出找不到節點的異常, 換句話說,當查找節點而節點並無當即出現的時候,隱式等待將等待一段時間再查找 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) Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這裏是Python學習者的彙集地,零基礎,進階,都歡迎
在這裏咱們用 implicitly_wait() 方法實現了隱式等待。
隱式等待的效果其實並無那麼好,由於咱們只是規定了一個固定時間,而頁面的加載時間是受到網絡條件影響的。
因此在這裏還有一種更合適的顯式等待方法,它指定好要查找的節點,而後指定一個最長等待時間。若是在規定時間內加載出來了這個節點,那就返回查找的節點,若是到了規定時間依然沒有加載出該節點,則會拋出超時異常。
咱們用一個實例來感覺一下:
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 這個對象,指定好最長等待時間,而後調用它的 until() 方法,傳入要等待條件 expected_conditions,好比在這裏咱們傳入了 presence_of_element_located 這個條件,就表明節點出現的意思,其參數是節點的定位元組,也就是 ID 爲 q 的節點搜索框。
因此這樣能夠作到的效果就是,在 10 秒內若是 ID 爲 q 的節點即搜索框成功加載出來了,那就返回該節點,若是超過10 秒尚未加載出來,那就拋出異常。
對於按鈕,能夠更改一下等待條件,好比改成 element_to_be_clickable,也就是可點擊,因此查找按鈕時是查找 CSS 選擇器爲 .btn-search 的按鈕,若是 10 秒內它是可點擊的也就是成功加載出來了,那就返回這個按鈕節點,若是超過 10 秒還不可點擊,也就是沒有加載出來,那就拋出異常。
運行代碼,在網速較佳的狀況下是能夠成功加載出來的。
控制檯輸出:
<selenium.webdriver.remote.webelement.WebElement (session="07dd2fbc2d5b1ce40e82b9754aba8fa8", element="0.5642646294074107-1")> <selenium.webdriver.remote.webelement.WebElement (session="07dd2fbc2d5b1ce40e82b9754aba8fa8", element="0.5642646294074107-2")>
能夠看到控制檯成功輸出了兩個節點,都是 WebElement 類型。
若是網絡有問題,10 秒內沒有成功加載,那就拋出TimeoutException,控制檯輸出以下:
TimeoutException Traceback (most recent call last) <ipython-input-4-f3d73973b223> in <module>() 7 browser.get('https://www.taobao.com/') 8 wait = WebDriverWait(browser, 10) ----> 9 input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
關於等待條件,其實還有不少,好比判斷標題內容,判斷某個節點內是否出現了某文字,在這裏將全部的加載條件列舉以下:
等待條件 | 含義 |
---|---|
title_is | 標題是某內容 |
title_contains | 標題包含某內容 |
presence_of_element_located | 節點加載出,傳入定位元組,如(By.ID, 'p') |
visibility_of_element_located | 節點可見,傳入定位元組 |
visibility_of | 可見,傳入節點對象 |
presence_of_all_elements_located | 全部節點加載出 |
text_to_be_present_in_element | 某個節點文本包含某文字 |
text_to_be_present_in_element_value | 某個節點值包含某文字 |
frame_to_be_available_and_switch_to_it frame | 加載並切換 |
invisibility_of_element_located | 節點不可見 |
element_to_be_clickable | 節點可點擊 |
staleness_of | 判斷一個節點是否仍在DOM,可判斷頁面是否已經刷新 |
element_to_be_selected | 節點可選擇,傳節點對象 |
element_located_to_be_selected | 節點可選擇,傳入定位元組 |
element_selection_state_to_be | 傳入節點對象以及狀態,相等返回True,不然返回False |
element_located_selection_state_to_be | 傳入定位元組以及狀態,相等返回True,不然返回False |
alert_is_present | 是否出現Alert |
更多詳細的等待條件的參數及用法介紹能夠參考官方文檔:http://selenium-python.readth...。
咱們日常使用瀏覽器都有前進和後退功能,使用 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()
在這裏咱們連續訪問三個頁面,而後調用 back() 方法就能夠回到第二個頁面,接下來再調用 forward() 方法又能夠前進到第三個頁面。
使用 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())
首先咱們訪問了知乎,而後加載完成以後,瀏覽器實際上已經生成了 Cookies 了,咱們調用 get_cookies() 方法就能夠獲取全部的 Cookies,而後咱們添加一個 Cookie,傳入一個字典,有 name、domain、value 等內容。接下來咱們再次獲取全部的 Cookies,能夠發現結果就多了這一項 Cookie。最後咱們調用 delete_all_cookies() 方法,刪除全部的 Cookies,再從新獲取,結果就爲空了。
控制檯輸出:
[{'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 仍是很是方便的。
咱們在訪問網頁的時候會開啓一個個選項卡,那麼在 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']
首先咱們訪問了百度,而後調用了 execute_script() 方法,傳入 window.open() 的 JavaScript 語句新開啓一個選項卡,而後接下來咱們想切換到該選項卡,能夠調用 window_handles 屬性獲取當前開啓的全部選項卡,返回的是選項卡的代號列表,要想切換選項卡只須要調用 switch_to_window() 方法,傳入選項卡的代號便可。在這裏咱們將第二個選項卡代號傳入,即跳轉到了第二個選項卡,而後接下來在第二個選項卡下打開一個新的頁面,而後切換回第一個選項卡能夠從新調用 switch_to_window() 方法,再執行其餘操做便可。
如此以來咱們便實現了選項卡的管理。
在使用 Selenium 過程當中,不免會遇到一些異常,例如超時、節點未找到等錯誤,一旦出現此類錯誤,程序便不會繼續運行了,因此異常處理在程序中是十分重要的。
在這裏咱們可使用 try except 語句來捕獲各類異常。
首先咱們演示一下節點未找到的異常,示例以下:
from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.baidu.com') browser.find_element_by_id('hello')
在這裏咱們打開百度頁面,而後嘗試選擇一個並不存在的節點,這樣就會遇到異常。
運行以後控制檯輸出以下:
NoSuchElementException Traceback (most recent call last) <ipython-input-23-978945848a1b> in <module>() 3 browser = webdriver.Chrome() 4 browser.get('https://www.baidu.com') ----> 5 browser.find_element_by_id('hello')
能夠看到拋出了 NoSuchElementException 這類異常,這一般是節點未找到的異常,爲了防止程序遇到異常而中斷,咱們須要捕獲一下這些異常。
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() Python資源分享qun 784758214 ,內有安裝包,PDF,學習視頻,這裏是Python學習者的彙集地,零基礎,進階,都歡迎
如上例所示,這裏咱們使用 try except 來捕獲各種異常,好比咱們對 find_element_by_id() 查找節點的方法捕獲 NoSuchElementException 異常,這樣一旦出現這樣的錯誤,就進行異常處理,程序也不會中斷了。
控制檯輸出:
No Element
更多的異常累能夠參考官方文檔:http://selenium-python.readth...,若是出現了某個異常,咱們對它進行捕獲便可。
到此咱們就基本對 Selenium 的經常使用用法有了大致的瞭解,有了 Selenium,處理 JavaScript 再也不是難事。