04- 動態渲染頁面爬取
文章目錄
4-1 Selenium的安裝
Selenium是一個自動化測試工具,利用它可以驅動瀏覽器執行特定的動作,如點擊、下拉等操作,同時還可以獲取瀏覽器當前呈現的頁面的源代碼,做到可見即可爬。對於一些JavaScipt
動態渲染的頁面來說,此種抓取方式非常有效。
4 -2 Selenium相關鏈接
- 官方網站 :https://www.selenium.dev/
- GitHub : https://github.com/SeleniumHQ/selenium/tree/master/py
- 官方文檔 : https://selenium-python.readthedocs.io/
- 中文文檔 :https://selenium-python-zh.readthedocs.io/en/latest/
4-3 pip 安裝
pip install selenium
4-4 ChromeDriver 的安裝
安裝ChromeDriver。因爲只有安裝ChromeDriver.才能驅動Chrom瀏覽器完成相對應的操作
4-5 ChromeDriver 的相關鏈接
- 下載地址 : https://chromedriver.storage.googleapis.com/index.html
- 下載要對應自己谷歌瀏覽器的版本
4-6 ChromeDriver環境配置
在Windows下,建議直接將chromedriver.exe文件拖到Python的根目錄下
在配置Python的時候系統會自動把Python配置到環境中,到時候我們可以直接使用驅動就可以不用寫路徑問題
4-7 Selenium聲明瀏覽器對象
Selenium支持多種的瀏覽器,如chrome、Firefox、Edge等
# @Time : 2020/5/11 15:01
# @Author : SmallJ
# 支持的瀏覽器
from selenium import webdriver
browser = webdriver.Chrome()
borwser = webdriver.Android()
borwser = webdriver.Firefox()
borwser = webdriver.Ie()
4-8 Selenium訪問頁面
我們可以用get()
方法來請求網頁,參數傳入鏈接URL即可。
- get : 請求的網址
- page_source : 爲反映頁面源代碼
- close : 爲關閉瀏覽器
# @Time : 2020/5/11 15:01
# @Author : SmallJ
# 支持的瀏覽器
from selenium import webdriver
# 實例化瀏覽器
browser = webdriver.Chrome()
# 用browser這個對象來發送請求
url = 'https://www.taobao.com/'
browser.get(url)
# page_source 爲頁面源代碼
# 用browser這個對象來獲取頁面源代碼
html = browser.page_source
print(html)
# close 爲關閉瀏覽器
browser.close()
4-9 Selenium查找節點
- 單個節點
語法 | 描述 |
---|---|
find_element_by_id |
根據頁面中的id屬性來查找值 |
find_element_by_xpath |
根據xpath語法來進行查找值 |
find_element_by_link_text | 根據文本來進行查詢 |
find_element_by_partial_link_text |
根據文本進行查詢模糊查詢 |
find_element_by_name |
根據name屬性來進行查詢 |
find_element_by_class_name |
根據class屬性來進行查詢 |
find_element_by_css_selector |
根據css語法來進行查找 |
- 多個節點
- 注意 : 多節點在這個方法的名稱中,elment多了一個s。注意區分
Selenium可以驅動瀏覽器完成各種操作,比如填充表單、模擬點擊等。比如,我們想要完成向某個輸入框輸入文字的操作,總需要知道
from selenium import webdriver
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
# 根據id來進行查找
first_input = browser.find_element_by_id('q')
# 根據css來進行查找
second_input = browser.find_element_by_css_selector('#q')
# 根據Xpath來進行查找
three_input = browser.find_element_by_xpath('//*[@id="q"]')
# 關閉瀏覽器
browser.close()
這裏我們使用3種方式獲取輸入框,分別是根據ID、CSS選擇器、XPath獲取
另外,Selenium還提供了通過方法find_element()
,它需要傳入兩個參數:查找方式和By值。實際上,它就是find_element_by_id()
這種方法的通過函數版本,比如 **find_element_by_id(id)
** 等價於 **find_element(By.ID)
**兩者的結果是一樣。
京東
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
# 實例化對象
browser = webdriver.Chrome()
# 請求url
url = 'https://www.jd.com/'
browser.get(url)
time.sleep(3)
# 單節點查找
# 查找京東的搜索框
browser.find_element(By.ID, 'key').send_keys('Python人工智能')
# 查找點擊按鈕並進行點擊事件
browser.find_element(By.XPATH, '//*[@id="search"]/div/div[2]/button/i').click()
time.sleep(5)
# 關閉瀏覽器
browser.close()
淘寶
from selenium import webdriver
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
time.sleep(5)
# 單個節點
# 查找節點採用find來進行查找
# 在輸入框輸入Python send_keys 爲輸入內容
browser.find_element_by_css_selector('#q').send_keys('Python')
# 定位到搜索框,並進行點擊事件 click爲點擊事件
browser.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button').click()
time.sleep(5)
browser.close()
4-10 Selenium節點交互
Selenium可以驅動瀏覽器來執行一些操作,也就是說可以讓瀏覽器去模擬人的行爲去執行一些操作。比較常見的操作用法有:輸入文字時用send_keys()
方法,清空文字時用clear()
方法,點擊按鈕用click()
方法
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
browser = webdriver.Chrome()
url = 'https://www.taobao.com/'
browser.get(url)
time.sleep(2)
input = browser.find_element(By.ID, 'q')
# 輸入內容
input.send_keys('Python')
# 清空內容
input.clear()
# 強制停止兩秒
time.sleep(2)
input.send_keys('Python人工智能')
button = browser.find_element(By.XPATH, '//*[@id="J_TSearchForm"]/div[1]/button')
# 進行點擊事件
button.click()
# 強制等待
time.sleep(2)
# 關閉瀏覽器
browser.close()
4-11 Selenium動作鏈
在上面的實例中,一些交互動作都是針對某個節點執行的。比如,對於輸入框,我們就調用它的輸入文字和清空文字方法;對於按鈕,就調用它的點擊方法。其實,還有另外一些操作,它們沒有特定的執行對象,比如鼠標拖拽、鍵盤按鈕等,這些動作用另外一種方式來執行,那就是動作鏈。
drag_and_drop(source, target)
:- drop :中文意思起點
- drag : 中文意思結束
- source : 爲要拖拽元素的起點
- target : 爲要拖拽元素的終點
perform(self)
- 該方法爲執行動作
# @Time : 2020/5/11 20:50
# @Author : SmallJ
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
# ActionChains爲動作鏈
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser = webdriver.Chrome()
browser.get(url)
# 該請求的頁面中存在頁面嵌套所以需使用switch_to.frame
# switch_to.frame 爲頁面嵌套 根據id來取值
# 切換到頁面嵌套
browser.switch_to.frame('iframeResult')
# 元素定位
# 請拖住我 source 中文意思 源代碼
source = browser.find_element_by_css_selector('#draggable')
# 元素定位
# 請放置到這裏 target 中文意思 目標
target = browser.find_element_by_css_selector('#droppable')
time.sleep(3)
# 進行實例化動作行爲鏈
actions = ActionChains(browser)
# drag_and_drop
# source : 爲拖拽元素的起點
# target : 爲拖拽元素的終點
actions.drag_and_drop(source, target)
# perform 爲方法執行動作
actions.perform()
首先,打開網頁中的一個拖拽實例,然後依次選中要拖拽的節點和拖拽到目標節點,接着聲明ActionChains對象並將其賦值爲actions變量的drag_and_drop()
方法,再調用perform()
方法執行動作,此時就完成了拖拽操作。
4-12 Selenium執行JavaScript
對於某些操作,Selenium API並沒有提供。比如,下拉進度條,它可以直接模擬運行JavaScipt此時使用execute_script()
方法即可實現
# @Time : 2020/5/12 0:31
# @Author : SmallJ
from selenium import webdriver
url = 'https://www.zhihu.com/explore'
browser = webdriver.Chrome()
browser.get(url)
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("TO Bottom")')
4-13 Selenium獲取節點信息
語法 | 描述 |
---|---|
get_attribute() |
獲取屬性值 |
get_text() |
獲取文本值 |
get_id |
獲取節點 |
get_location |
獲取節點在頁面中的相對位置 |
tag_name |
獲取標籤名稱 |
size |
獲取節點大小 |
前面說過,通過page_source
屬性可以獲取網頁源代碼可以獲取網頁的源代碼,接着就可以使用解析庫(如正則表達式、Beautiful Soup
、pyquery
等)來提取信息
不過,既然Selenium
已經提供了選擇節點的方法,返回的是WebElement
類型,那麼它也有相關的方法和屬性來直接提取節點信息,如屬性、文本等。這樣的話,我們就可以不用通過解析源代碼來提取信息了。
- 獲取屬性
我們可以使用get_attribute()
方法來獲取節點的屬性,但是其前提是先選其中的這個節點。
# @Time : 2020/5/12 14:53
# @Author : SmallJ
# ActionChains 爲動作行爲鏈
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
# 請求該網頁
browser.get(url)
# 查找屬性
logo = browser.find_element(By.CLASS_NAME, 'Input')
print(logo)
print(logo.get_attribute('placeholder'))
4-14 Selenium切換Frame
我們知道網頁中有一種節點叫作iframe
,也就是子Frame,相當於頁面的子頁面,它的結構和外部網頁內容的結構完全一致。Selenium打開頁面後,它的默認是在父級Frame裏面的操作,而此時如果頁面中還有子Frame,它是不能獲取子Frame裏面的節點。這時就需要使用switch_to.frame()
方法來切換Frame。
# @Time : 2020/5/12 15:21
# @Author : SmallJ
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.common.exceptions import NoSuchElementException
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser = webdriver.Chrome()
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)
首先通過switch_to.frame()
方法切換到子Frame裏面,然後嘗試獲取子Frame裏的logo節點(這是不能找到的)如果找不到的話,就會拋出NoSuchElementException
異常,異常被捕捉之後,就會輸出NO LOGO。接下來,重新切換到父級Frame然後再次重新獲取節點。
3-15 延時等待
隱式等待
當使用隱式等待執行測試的時候,如果Selenium沒有在DOM中找到節點,將繼續等待,超出設定時間後,則拋出找不到節點的異常。換句話說,當查找節點而節點並沒有立即出現的時候,隱式等待將等待一段時間再查找DOM,默認的時間爲0秒
# @Time : 2020/5/12 16:02
# @Author : SmallJ
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.baidu.com/'
# 隱式等待
# 隱式等待的含義就是超出時間的範圍的時候就不會繼續查找,拋出異常
# time_to_wait : 爲時間
browser.implicitly_wait(10)
browser.get(url)
input = browser.find_element_by_id('wrapper_wrapper')
print(input)
顯示等待
隱式等待的效果並不是很好,因爲我們在規定了一個固定時間,而頁面的加載時間會受到網絡條件的影響
這裏還有一種更合適的顯示等待方法,它指定要查找的節點,然後指定一個最長的等待時間。如果在規定時間內加載出來了這個節點;如果到規定時間依然沒有加載出來該節點,則拋出異常。
# 顯式等待
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()
url = 'https://www.taobao.com/'
browser.get(url)
# WebDriverWait 裏面傳遞兩個參數
# driver 引擎
# timeout 爲超時時間
wait = WebDriverWait(browser, 10)
input_data = 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_data, button)
- 這裏首先引入WebDriverWait這個對象,指定最長等待時間,然後調用它的
until()
方法,傳入要等待條件expected_conditions
。比如,這裏傳入了presence_of_element_located
這個條件,代表節點出現的意思,其參數是節點的定位元組,也就是ID爲q
的節點搜索。 - 這樣可以做到的效果就是,在10秒內如果ID爲
element_to_clickable
,也就是可點擊,所以查找按鈕時查找CSS選擇器爲.btn-search
的按鈕,如果10內它是可點擊的,也就是成功加載出來了,也就是返回這個按鈕節點。 - 如果超過10秒還不可以點擊,就拋出異常。