動態渲染網頁爬取-selenium


Selenium 簡介

  Selenium是一個自動化測試工具,利用它可以驅動瀏覽器執行特定的操作例如點擊、下拉等操作。同事它還能夠獲取瀏覽器當前呈現的頁面的源代碼,即可以做到可見可爬。這對於一些JavaScript渲染的頁面我就就可以使用它進行爬取,而不用去分析后台接口參數。#應用:(以google瀏覽器為例))安裝selenium並且將google驅動chromedirver.exe程序與python代碼文件的放置在同一個目錄中,即可使用selenium驅動google瀏覽器.以下為一個簡單示例:

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
#聲明瀏覽器對象(也可以是其他瀏覽器:火狐、IE等)
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()

結果(輸出當前url,源代碼,cookies)
.............................................................................................省略
<script>
if(bds.comm.supportis){
    window.__restart_confirm_timeout=true;
    window.__confirm_timeout=8000;
    window.__disable_is_guide=true;
    window.__disable_swap_to_empty=true;
}
initPreload({
    'isui':true,
    'index_form':"#form",
    'index_kw':"#kw",
    'result_form':"#form",
    'result_kw':"#kw"
});
</script>

<script>
if(navigator.cookieEnabled){
    document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";
}
</script>
</body></html>
View Code

Selenium聲明瀏覽器對象

from selenium import webdriver
#聲明谷歌瀏覽器對象
browser = webdriver.Chrome()
#聲明火狐瀏覽器對象
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser =webdriver.Safari()
View Code

Selenium訪問頁面

from selenium import webdriver

browser = webdriver.Chrome()
#訪問淘寶網頁面獲取網頁原代碼
browser.get('https://www.taobao.com')
#獲取網頁原代碼
print(browser.page_source)
#關閉瀏覽器
browser.close()
View Code

Selenium查找節點

1.單節點查找

單個節點查找find_element()方法

常見方法有:

  • 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_css_selector()

  或

  find_element()傳入兩個參數查找方式By和值,例如:

  find_element(By.ID,id)

*取以淘寶搜索框網頁為例
<input id="q" name="q" aria-label="請輸入搜索文字" accesskey="s" autofocus="autofocus" autocomplete="off" class="search-combobox-input" aria-haspopup="true" aria-combobox="list" role="combobox" x-webkit-grammar="builtin:translate" tabindex="0">

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
#根據id獲取淘寶搜索框
input_first = browser.find_element_by_id('q')
#根據css選擇器獲取
input_second = browser.find_element_by_css_selector('#q')
#根據xpath獲取
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first,input_second,input_third)
browser.close()

結果(三個結果一致)
<selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")>
View Code

2.多節點查找

多個節點查找find_elements()方法

  • 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_css_selector()

   或

  find_elements()傳入兩個參數查找方式By和值,例如:

  find_element(By.ID,id)

*以淘寶導航欄為例
from selenium import webdriver

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


或者以下方法
Liss = browser.find_elements(By.CSS_SELECTOR,’.server-bd li’)#結果一致
print(lis)
browser.close()

結果
[<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-1")>...<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-16")>]
View Code

節點交互,常用的有以下幾個:

  • 輸入文字用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')
#搜索框輸入iphone,但是未點擊搜索按鈕所以不進行搜索
input.send_keys('iphone')
time.sleep(1)
#清空輸入框
input.clear()
input.send_keys('ipad')
#獲取搜索按鈕
button = browser.find_element_by_class_name('btn-search')
#點擊按鈕完成搜索任務
button.click()
#關閉瀏覽器
browser.close()
View Code

動作鏈:例如鼠拖曳和鍵盤按鍵等操作就稱之為動作鏈,它們沒有特定的執行對象

*舉例:實現一個節點的拖曳操作
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')
#聲明ActionChains對象
actions = ActionChains(browser)
#action調用以下兩個方法完成拖曳操作
actions.drag_and_drop(source,target)
actions.perform()
browser.close()
View Code

執行JavaScript:例如下拉進度條可以直接模擬運行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)')
#彈出alert提示框
browser.execute_script('alert("To Bottom")')
browser.close()
View Code

獲取節點信息(包括屬性,文本以及id位置標簽名和大小)

*獲取屬性
from selenium import webdriver

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'))
browser.close()

結果
<selenium.webdriver.remote.webelement.WebElement (session="52975bfa983727a2a7f26b9972c414a2", element="0.9714708708818114-1")>
zu-top-link-logo

*獲取文本值
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)
browser.close()

結果
提問
View Code

獲取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')
#獲取id值
print(input.id)
#獲取位置
print(input.location)
#獲取標簽名
print(input.tag_name)
#獲取大小
print(input.size)
browser.close()

結果
0.8772617338808859-1
{'x': 760, 'y': 7}
button
{'height': 32, 'width': 66}
View Code

切換Frame:網頁中有一種節點叫做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)
#通過switch_to.frame()切換到子頁面Frame里面
browser.switch_to.frame('iframeResult')
try:
    #獲取子Frame里面的logo節點
    logo = browser.find_element_by_class_name('logo')
    #若不存在打印No Logo
except NoSuchElementException:
    print('No Logo')
#通過switch_to_.parent_frame切回父級Frame
browser.switch_to.parent_frame()
#重新獲取logo節點
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)

結果
No Logo
<selenium.webdriver.remote.webelement.WebElement (session="342ed5d025ac85c06d872fdf337edc82", element="0.12105089091907728-2")>
RUNOOB.COM
View Code

延時等待:

  seleniumget()方法會在網頁加載結束后結束執行,此時如果要獲取page_source,可能並不是瀏覽器完全加載完成的頁面,如果某些頁面有額外的Ajax請求,我們在網頁源代碼中不一定能成功獲取,所以需要等待一定的時間從而確保頁面加載出來而等待又分為隱式等待和和顯式等待。

  • 隱式等待::當時用隱式等待執行測試的時候,若Selenium沒有在DOM中找到節點,將繼續等待,超出設定時間后,則會拋出找不到的節點的異常,即當查找節點而節點並沒有立即出現的時候,隱式等待將等待一段時間在查找DOM,默認時間為0
  • 顯式等待:指定要查找的節點,然后指定一個最長的等待時間。若在規定的時間內加載出來這個節點,就返回查找的節點,若到了規定時間沒有加載出來這個節點則會拋出超時異常。

隱式等待

from selenium import webdriver

browser = webdriver.Chrome()
#調用implicitly_wait()方法實現隱式等待
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

結果
<selenium.webdriver.remote.webelement.WebElement (session="9bc5b8f1ae5203fd98654d854b8b70e6", element="0.6674161481100129-1")>
View Code

顯式等待條件

        等待條件                                  含義
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       加載並切換
invisibility_of_element_located              節點不可見
element_to_be_clickable                      節點可點擊
staleness_of                            判斷一個節點是否仍然在DOM,可判斷頁面是否已經刷新
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')
#創建WebDriverWait對象,指定最長等待時間 10秒
wait = WebDriverWait(browser,10)
#調用until()方法傳入等待條件(條件為id為q的節點出現10秒內是否出現)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
#查找CSS選擇器為.btn-serch的按鈕,若在10秒內是可點擊的,則成功加載出來
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search')))
print(input,button)
browser.close()

結果
<selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-1")> <selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-2")>
View Code

 前進和后退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()
View Code

Cookies

*使用selenium可以方便的對cookies進行獲取、添加、刪除等操作
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
#獲取所有cookies
print(browser.get_cookies())
#添加cookies
browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
print(browser.get_cookies())
#刪除所有cookies
browser.delete_all_cookies()
#重新獲取結果為空
print(browser.get_cookies())
browser.close()
View Code

選項卡管理

*當我們在訪問網頁的時候會開啟一個選項卡,可以使用selenuim對選項卡進行操作

import time
from selenium import webdriver

browser = webdriver.Chrome()
#訪問百度網頁
browser.get('https://www.baidu.com')
#開啟一個新的選項卡
browser.execute_script('window.open()')
#調用window_handles屬性獲取當前開啟的所有選項卡
print(browser.window_handles)
#調用switch_to_window()方法切換到第二個選項卡
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
#調用switch_to_window()方法切換到第一個選項卡
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')

結果
['CDwindow-E4ECA535D3501ED974B9B9E0AD36995B', 'CDwindow-C362F44E7078475E2676DD6C5DF455DF']
View Code

異常處理

*在使用selenium的過程中難免會遇到一些錯誤,一旦出現錯誤程序便不會在運行了,而我們可以使用try excep語句來捕獲各種異常

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()

結果
No Element
View Code

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM