Python爬虫新手进阶版:怎样读取非结构化网页、图像、视频、语音数据
導讀:常見的數據來源和獲取方式,你或許已經了解很多。本文將拓展數據來源方式和格式的獲取,主要集中在非結構化的網頁、圖像、視頻和語音。
?
?
01 從網頁中爬取運營數據
?
要從網頁中爬蟲數據,可使用Python內置標準庫或第三方庫,例如urllib、urllib2、httplib、httplib2、requests等。本文使用requests方法獲取網頁數據。
?
import requests # 導入庫
url = 'http://www.dataivy.cn/blog/dbscan/' # 定義要抓取的網頁地址
res = requests.get(url) # 獲得返回請求
html = res.text # 返回文本信息
print (html) # 打印輸出網頁源代碼
?
在代碼中,先導入用到的網絡請求處理庫requests,然后定義一個用來抓取的url,通過requests的get方法獲取url的返回請求,并通過返回請求的text方法獲取內容(源代碼),最終打印輸出,部分結果如下:
?
<!DOCTYPE html>
<html lang="zh-CN" class="no-js">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="profile" href="http://gmpg.org/xfn/11">
......
</body>
</html>
?
從網頁中讀取的信息其實是網頁的源代碼,源代碼經過瀏覽器的解析才是我們看到的不同的頁面內容和效果。
?
?
02 讀取圖像數據
?
Python讀取圖像通常使用PIL和OpenCV兩個庫,相對而言,筆者使用后者的情況更多。以下圖為例進行說明。
?
▲文件名:cat.jpg
?
1. 使用PIL讀取圖像
?
Python Imaging Library中包含很多庫,常用的是其中的Image,通過使用其中的open方法來讀取圖像,用法如下:
?
import Image ?# 導入庫
file = 'cat.jpg' ?# 定義圖片地址
img = Image.open(file, mode="r") ?# 讀取文件內容
img.show() ?# 展示圖像內容
?
其中關鍵的方法是open,其中的參數包括兩個:
?
-
file:文件對象名稱,可以是文件名,也可以是圖像文件字符串。
-
mode:打開模式,默認只能是r模式,否則會報錯;當file是圖像字符串時,會調用系統的rb模式讀取。
?
通過open讀取之后會返回一個圖像文件對象,后續所有的圖像處理都基于該對象進行。上述代碼執行后,通過?img.show()?會調用系統默認的圖像瀏覽器查看打開圖像進行查看。如圖所示。
?
▲調用img.show()展示圖像
?
該對象包含了很多方法可以用來打印輸出文件的屬性,例如尺寸、格式、色彩模式等。
?
print ('img format: ', img.format) ?# 打印圖像格式
print ('img size: ', img.size) ?# 打印圖像尺寸
print ('img mode: ', img.mode) ?# 打印圖像色彩模式
?
上述代碼執行后返回的結果如下:
?
('img format: ', 'JPEG')
('img size: ', (435, 361))
('img mode: ', 'RGB')
?
其中圖像的類型是圖像本身的格式,例如jpg、gif、png等;圖像尺寸是指圖像分辨率,示例中的尺寸是435×361(單位是像素);圖像的模式指的是顏色模式,示例圖像是RGB模式。
?
相關知識點:圖像顏色模式
?
在不同的領域中,圖像的色彩模式有多種標準。比較常見的顏色模式包括:
?
-
RGB:自然界中所有的顏色都幾乎可以用紅、綠、藍這三種顏色波長的不同強度組合得到,這種顏色模式在數字顯示領域非常流行。
-
CMYK:這是一種工業四色印刷的亞蘭瑟標準,四個字母分別指代青(Cyan)、洋紅(Magenta)、黃(Yellow)、黑(Black)。
-
HSB:這種模式使用色澤(Hue)、飽和度(Saturation)和亮度(Brightness)來表達顏色的要素,這種模式更多基于人類心理的認識和感覺。
-
其他模式:其他模式還包括灰度模式、索引模式、位圖模式等,也在一定場景下較為常見。
?
不同的色彩模式下之間可以相互轉換,例如從RGB模式轉換為灰度模式:
?
img_gray = img.convert('L') ?# 轉換為灰度模式
img_gray.show() ?# 展示圖像
?
▲灰度圖像模式
?
除此以外,基于該文件對象也可以進行其他操作,例如圖像格式轉換、旋轉、裁剪、合并、濾波處理、色彩處理、縮略圖處理等。限于篇幅,在此不作過多介紹。
?
2. 使用OpenCV讀取圖像
?
OpenCV讀取和展示圖像主要有兩類方法,第一種是使用cv庫,第二種是使用cv2庫。
?
第一種:使用cv讀取圖像
?
import cv2.cv as cv ?# 導入庫
file = 'cat.jpg' ?# 定義圖片地址
img = cv.LoadImage(file) ?# 加載圖像
cv.NamedWindow('a_window', cv.CV_WINDOW_AUTOSIZE) ?# 創建一個自適應窗口用于展示圖像
cv.ShowImage('a_window', img) ?# 展示圖像
cv.WaitKey(0) ?# 與顯示參數配合使用
?
第二種:使用cv2讀取圖像
?
import cv2 ?# 導入庫
file = 'cat.jpg' ?# 定義圖片地址
img = cv2.imread(file) ?# 讀取圖像
cv2.imshow('image', img) ?# 展示圖像
cv2.waitKey(0) ?# 與顯示參數配合使用
?
通過PIL調用的是系統默認的圖像顯示工具,而在OpenCV中是通過自身創建的圖像功能顯示圖像。
?
另外,兩種方法中都有一個waitKey()的方法,該方法的作用是鍵盤綁定函數,其中的參數表示等待毫秒數。執行該方法后,程序將等待特定的毫秒數,看鍵盤是否有輸入,然后返回值對應的ASCII值。如果其參數為0,則表示無限期的等待直到鍵盤有輸入。
?
筆者通常使用第二種方法讀取圖像,因為方法更加簡單。其中imread方法細節如下:
?
語法
?
cv2.imread(filename[, flags])
?
描述
?
讀取圖像內容,如果圖像無法讀取則返回空信息,支持圖像格式幾乎包括了日常所有場景下的格式,具體包括:
?
-
Windows bitmaps文件:*.bmp、*.dib
-
JPEG文件:*.jpeg、*.jpg、*.jpe
-
JPEG 2000文件:*.jp2
-
PNG文件:*.png
-
WebP文件:*.webp
-
移動圖像格式:*.pbm、*.pgm、*.ppm *.pxm、*.pnm
-
Sun rasters文件:*.sr、*.ras
-
TIFF 文件:*.tiff、*.tif
-
OpenEXR文件:*.exr
-
Radiance HDR文件:*.hdr、*.pic
?
參數
?
-
filename必填,字符串,圖像地址。
-
flags可選,int型或對應字符串,顏色的讀取模式。如果flag>0或者cv2.IMREAD_COLOR,讀取具有R/G/B三通道的彩色圖像;如果flag=0或cv2.IMREAD_GRAYSCALE,讀取灰度圖像;如果flag<0或cv2.IMREAD_UNCHANGED,讀取包含Alpha通道的原始圖像。
?
返回
?
圖像內容,如果圖像無法讀取則返回NULL。
?
提示:除了使用OpenCV自帶的圖像展示方法外,OpenCV還經常和matplotlib配合展示圖像,這種場景更加常用。組合使用時可借用Matplotlib的強大圖像展示能力進行圖像的對比和參照以及不同圖像模式的輸出。
?
?
03 讀取視頻數據
?
Python讀取視頻最常用的庫也是Opencv。本文以名為Megamind.avi的視頻為例進行說明,如下是一段讀取視頻內容的代碼示例:
?
import cv2 ?# 導入庫
?
cap = cv2.VideoCapture("tree.avi") ?# 獲得視頻對象
status = cap.isOpened() ?# 判斷文件知否正確打開
if status: ?# 如果正確打開,則獲得視頻的屬性信息
? ? frame_width = cap.get(3) ?# 獲得幀寬度
? ? frame_height = cap.get(4) ?# 獲得幀高度
? ? frame_count = cap.get(7) ?# 獲得總幀數
? ? frame_fps = cap.get(5) ?# 獲得幀速率
? ? print ('frame width: ', frame_width) ?# 打印輸出
? ? print ('frame height: ', frame_height) ?# 打印輸出
? ? print ('frame count: ', frame_count) ?# 打印輸出
? ? print ('frame fps: ', frame_fps) ?# 打印輸出
success, frame = cap.read() ?# 讀取視頻第一幀
while success: ?# 如果讀取狀態為True
? ? cv2.imshow('vidoe frame', frame) ?# 展示幀圖像
? ? success, frame = cap.read() ?# 獲取下一幀
? ? k = cv2.waitKey(1000 / int(frame_fps)) ?# 每次幀播放延遲一定時間,同時等待輸入指令
? ? if k == 27: ?# 如果等待期間檢測到按鍵ESC
? ? ? ? break ?# 退出循環
cv2.destroyAllWindows() ?# 關閉所有窗口
cap.release() ?# 釋放視頻文件對象
?
上述代碼分為4個部分,以空行分隔。
?
第一部分為前3行,先導入庫,然后讀取視頻文件并獲得視頻對象,再獲得視頻讀取狀態。其中的關鍵方法是VideoCapture,用來讀取圖像。
?
語法
?
cv2.VideoCapture(VideoCapture ID|filename|apiPreference)
?
描述
?
讀取視頻設備或文件,并創建一個視頻對象實例
?
參數
?
必填,VideoCapture ID|filename
?
VideoCapture ID:int型,系統分配的設備對象的ID,默認的設備對象的ID為0。
?
Filename:
?
-
視頻文件的名稱,字符串,例如abc.avi。目前版本下只支持avi格式。
-
序列圖像,字符串,例如img_%2d.jpg(圖像序列包括img_00.jpg, img_01.jpg, img_02.jpg, ...)
-
視頻URL地址,字符串,例如protocol://host:port/script_name?script_params|auth
-
apiPreference:int型,后臺使用的API
?
返回
?
一個視頻對象實例
?
第二部分為if循環體內的9行代碼,該代碼主要用來在判斷文件被正確讀取的情況下,輸出視頻文件的整體信息。除了代碼中get方法使用的參數值外,OpenCV還支持更多圖像屬性,如下表所示。
?
| 值 | 屬性 | 描述 |
| 0 | CV_CAP_PROP_POS_MSEC | ?當前位置(單位:ms) |
| 1 | CV_CAP_PROP_POS_FRAMES | ?當前位置(單位:幀數,從0開始計) |
| 2 | CV_CAP_PROP_POS_AVI_RATIO | ?當前位置(單位:比率,?0表示開始,1表示結尾) |
| 3 | CV_CAP_PROP_FRAME_WIDTH | ?幀寬度 |
| 4 | CV_CAP_PROP_FRAME_HEIGHT | ?幀高度 |
| 5 | CV_CAP_PROP_FPS | ?幀速率 |
| 6 | CV_CAP_PROP_FOURCC | ?4-字符表示的視頻編碼(如:’M‘,?’J‘,?’P‘,?’G‘) |
| 7 | CV_CAP_PROP_FRAME_COUNT | ?總幀數 |
| 8 | CV_CAP_PROP_FORMAT | ?retrieve().調用返回的矩陣格式 |
| 9 | CV_CAP_PROP_MODE | ?后端變量指示的當前捕獲的模式 |
| 10 | CV_CAP_PROP_BRIGHTNESS | ?明亮度(僅用于攝像頭) |
| 11 | CV_CAP_PROP_CONTRAST | ?對比度(僅用于攝像頭) |
| 12 | CV_CAP_PROP_SATURATION | ?飽和度(僅用于攝像頭) |
| 13 | CV_CAP_PROP_HUE | ?色調(僅用于攝像頭) |
| 14 | CV_CAP_PROP_GAIN | ?增益(僅用于攝像頭) |
| 15 | CV_CAP_PROP_EXPOSURE | ?曝光度??(僅用于攝像頭) |
| 16 | CV_CAP_PROP_CONVERT_RGB | ?是否應該將圖像轉化為RGB圖像(布爾值) |
| 17 | CV_CAP_PROP_WHITE_BALANCE | ?白平衡(暫不支持?v2.4.3) |
▲get方法支持的圖像屬性
?
第三部分為具體讀取和展示視頻的每一幀內容。首先讀取視頻的第一幀,如果狀態為True,則展示圖像并讀取下一幀,期間通過cv2.waitKey參數做圖像延遲控制,同時延遲期間等待系統輸入指定,如果有輸入ESC則退出循環讀取幀內容。
?
相關知識點:動態圖像如何產生
?
我們視覺上看到的視頻(或動態圖)在計算機中其實是不存在的,計算機中存儲的是一幅一幅的圖像,在視頻里面被稱為幀,一幀對應的就是一幅圖像。當圖像連續播放的速度超過一定閥值間時,由于人類的視覺具有視覺暫留(延遲效應),多個暫留的疊加便形成了我們看到的動態圖像。一般情況下,如果一秒鐘播放超過16幀時,我們會認為這是一幅動態圖像。
?
在視頻中有幾個關鍵名詞:
?
幀率(FPS):每秒播放的幀數被定義為幀率,幀率越高,在視覺上認為圖像越連貫,就越沒有卡頓的現象。常見的幀率包括23.967(電影)、25(PAL電視),示例圖像大約為15。幀率與圖像清晰度無關,它只是決定了視頻的連貫性。
?
幀分辨率:幀分辨率基本決定了視頻的清晰度(當然除此之外還有視頻處理效果、設備播放差異等,這里指的是同等條件下的視頻源)。在同樣大小的圖像中,分辨率越高圖像通常就會越清晰。所以形容視頻時提到的1080P(1920*1080)、720P(1280*720)其實指的就是分辨率標準。當然,對于同樣分辨率下,在不同國家、不同電視規制、不同掃描標注下,也會更加細分。
?
注意:在OpenCV中的圖像讀取和處理,其實是不包括語音部分的,但從視頻文件的組成來講通常包括序列幀和與語音兩部分。目前的方式通常是對兩部分分開處理。
?
第四部分為當所有操作結束后,刪除所有由OpenCv創建的窗體,釋放視頻文件對象。
?
有關OpenCV的更多信息,具體查閱opencv.org
?
?
04 讀取語音數據
?
對于語音文件的讀取,可以使用Python的audioop、aifc、wav等庫實現。但針對語音處理這一細分領域,當前市場上已經具備非常成熟的解決方案,例如科大訊飛、百度語音等,大多數情況下,我們會通過調用其API實現語音分析處理的功能,或者作為分析處理前的預處理功能。
?
在具體實現過程中,既可以直接下載SDK做離線應用,也可以使用在線的服務。
?
?
▲科大訊飛語音服務
?
本文將以百度語音API服務應用為例,說明如何通過請求百度語音的API,將語音數據轉換為文字信息。
?
在正式應用百度語音API之前,請先建立百度賬戶以及注冊成為百度開發者。
?
基于該條件下,我們繼續開通語音識別服務。具體方法如下:
?
進入http://yuyin.baidu.com/app,在彈出的界面中點擊要針對哪個應用開通語音識別服務。我們默認使用在之前建立的API_For_Python應用中。因此,點擊該應用的“開通服務”。
?
▲開通服務
?
在彈出的窗口中,點擊選擇“語音識別”并確定。
?
▲選擇開通語音識別服務
?
開通成功后系統會提示“服務已開通”,然后點擊右側的“查看key”,會彈出如下信息:
?
▲圖2-32 應用key信息
?
上述彈出中的API Key和Secret Key為在后續語音識別中要使用的信息。
?
以下為完整代碼:
?
?
# 導入庫
import json ?# 用來轉換JSON字符串
import base64 ?# 用來做語音文件的Base64編碼
import requests ?# 用來發送服務器請求
?
# 獲得token
API_Key = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' ?# 從申請應用的key信息中獲得
Secret_Key = 'oiIboc5uLLUmUMPws3m0LUwb00HQidPx' ?# 從申請應用的key信息中獲得
token_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s" ?# 獲得token的地址
res = requests.get(token_url % (API_Key, Secret_Key)) ?# 發送請求
res_text = res.text ?# 獲得請求中的文字信息
token = json.loads(res_text)['access_token'] ?# 提取token信息
?
# 定義要發送的語音
voice_file = 'baidu_voice_test.pcm' ?# 要識別的語音文件
voice_fn = open(voice_file, 'rb') ?# 以二進制的方式打開文件
org_voice_data = voice_fn.read() ?# 讀取文件內容
org_voice_len = len(org_voice_data) ?# 獲得文件長度
base64_voice_data = base64.b64encode(org_voice_data) ?# 將語音內容轉換為base64編碼格式
?
# 發送信息
# 定義要發送的數據主體信息
headers = {'content-type': 'application/json'} ?# 定義header信息
payload = {
? ? "format": "pcm", ?# 以具體要識別的語音擴展名為準
? ? "rate": 8000, ?# 支持8000或16000兩種采樣率
? ? "channel": 1, ?# 固定值,單聲道
? ? "token": token, ?# 上述獲取的token
? ? "cuid": "B8-76-3F-41-3E-2B", ?# 本機的MAC地址或設備唯一識別標志
? ? "len": org_voice_len, ?# 上述獲取的原始文件內容長度
? ? "speech": base64_voice_data ?# 轉碼后的語音數據
}
data = json.dumps(payload) ?# 將數據轉換為JSON格式
vop_url = 'http://vop.baidu.com/server_api' ?# 語音識別的API
voice_res = requests.post(vop_url, data=data, headers=headers) ?# 發送語音識別請求
api_data = voice_res.text ?# 獲得語音識別文字返回結果
text_data = json.loads(api_data)['result']
print (api_data) ?# 打印輸出整體返回結果
print (text_data) ?# 打印輸出語音識別的文字
?
代碼以空行作為分隔,包括4個部分:
?
第一部分為導入需要的庫信息,具體用途見代碼注解。
?
第二部分為獲得要使用百度語音識別API的token信息。其中的API_Key和Secret_Key從“應用key信息”獲得。token_url通過占位符定義出完整字符串,并在請求時發送具體變量數據,從返回的信息中直接讀取token便于下面應用中使用。有關獲取token的更多信息,具體查閱http://yuyin.baidu.com/docs/asr/56。
?
提示:在請求獲取token時,可使用get或post(推薦使用)兩種方法,Token的有效期默認為1個月,如果過期需要重新申請。
?
第三部分主要用于獲取和處理語音文件數據。通過最常見的open方法以二進制的方式讀取語音數據,然后從獲得的語音數據中獲取原始數據長度并將原始數據轉換為base64編碼格式。
?
注意:百度語音識別API對于要識別的音頻源是有要求的:原始 PCM 的錄音參數必須符合 8k/16k 采樣率、16bit 位深、單聲道,支持的壓縮格式有:pcm(不壓縮)、wav、opus、amr、x-flac。
?
第四部分為本節內容的主體,發送請求獲取語音識別結果。本段落中先定義了發送頭信息;然后定義了一個字典,用于存儲要發送的key-value字符串并將其轉換為json格式;接著通過post方法以隱示發送的方式進行上傳并獲得返回結果,最后輸出返回結果和其中的語音轉文字的信息。該部分內容的細節比較多,具體參見百度語音API開發說明http://yuyin.baidu.com/docs/asr/57。
?
關于cuid的獲取,由于筆者是在本地電腦上測試的,因此使用的是MAC地址。獲取MAC地址的方法是:打開系統終端命令行窗口(Win+R,輸入cmd并回車),在命令行中輸入命令ipconfig/all,在列出的所有連接中找到其中媒體狀態不是“媒體已斷開”并且屬于當前連接的物理地址信息,如下圖為筆者電腦MAC信息:
?
▲獲取MAC地址信息
?
有關語音服務的更多信息,具體查閱http://www.xfyun.cn/。
?
上述代碼執行后返回如下結果:
?
{"corpus_no":"6409809149574448654","err_msg":"success.","err_no":0,"result":["百度語音提供技術支持,"],"sn":"83327679891492399988"}
[u'\u767e\u5ea6\u8bed\u97f3\u63d0\u4f9b\u6280\u672f\u652f\u6301\uff0c']
?
?
系統成功返回是識別結果,錄音的內容是“百度語音提供技術支持”,第二端的編碼是unicode編碼格式的中文。
?
總結:上述語音識別僅提供了關于語音轉文字的方法,其實語音本身包括非常多的信息,除了相對淺層的生理和物理特征,例如語速、音調、音長、音色、音強等外;還包括更深層次的社會屬性,這部分內容需要自然語音理解的深層次應用。目前的語音數據讀取后主要應用方向包括:
?
-
語音轉文字。這也是廣義上語音識別的一種,直接將語音信息轉為文字信息,例如微信中就有這個小功能。
-
語音識別。語音識別指的是對說話者通過選取語音識別單元、提取語音特征參數、模型訓練、模型匹配等階段實現其角色識別和個體識別的過程,例如通過某段語音識別出是哪個人說的話。
-
語音語義理解。在語音識別的基礎上,需要對語義特征進行分析,目的是通過計算得到語音對應的潛在知識或意圖,然后提供對應的響應內容或方法。語音識別和語音理解的差異之處在于,語音識別重在確定語音表達的字面含義,屬于表層意義;而語音理解重在挖掘語音的背后含義,屬于深層意義。
-
語音合成。語音合成就是讓計算機能夠“開口說話”,這是一種擬人的技術方法。語音合成,又稱文本轉語音(Text to Speech)技術,它通過機械的、電子的方法將文字信息轉變為人類可以聽得懂的語音。
-
應用集成。經過分析、識別后的信息可以與硬件集成,直接通過語音發送指令。例如通過跟Siri的“溝通”,除了可以進行日常溝通,它還可以告訴你天氣情況、幫你設置系統日程、介紹餐廳等。這是智能機器人在模式識別方面的典型應用。
?
基于上述的復雜應用場景,通常語音后續分析、處理和建模等過程都無法由數據工程師單獨完成,還需要大量的語料庫素材、社會學、信號工程、語言語法、語音學、自然語音處理、機器學習、知識搜索、知識處理等交叉學科和相關領域才有可能解開其中的密碼。
?
總結
以上是生活随笔為你收集整理的Python爬虫新手进阶版:怎样读取非结构化网页、图像、视频、语音数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NetCore基于SignalR、Re
- 下一篇: steam下载地址,千万别搞错!