導讀:常見的資料來源和獲取方式,你或許已經瞭解很多。本文將拓展資料來源方式和格式的獲取,主要集中在非結構化的網頁、影象、影片和語音。
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方法獲取內容(原始碼),最終列印輸出,部分結果如下:
......
從網頁中讀取的資訊其實是網頁的原始碼,原始碼經過瀏覽器的解析才是我們看到的不同的頁面內容和效果。
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編碼格式
# 傳送資訊
# 定義要傳送的資料主體資訊
essay-headers = {'content-type': 'application/json'} # 定義essay-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, essay-headers=essay-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的“溝通”,除了可以進行日常溝通,它還可以告訴你天氣情況、幫你設定系統日程、介紹餐廳等。這是智慧機器人在樣式識別方面的典型應用。
基於上述的複雜應用場景,通常語音後續分析、處理和建模等過程都無法由資料工程師單獨完成,還需要大量的語料庫素材、社會學、訊號工程、語言語法、語音學、自然語音處理、機器學習、知識搜尋、知識處理等交叉學科和相關領域才有可能解開其中的密碼。
關於作者:宋天龍(TonySong),資深大資料技術專家,歷任軟通動力集團大資料研究院資料總監、Webtrekk中國區技術和諮詢負責人、國美線上大資料中心經理。
本文摘編自《Python資料分析與資料化運營》,經出版方授權釋出。
延伸閱讀《Python資料分析與資料化運營》
轉載請聯絡微信:togo-maruko
點選文末右下角“寫留言”發表你的觀點
推薦閱讀
Q: 你都想學習Python哪方面的內容?
歡迎留言與大家分享
覺得不錯,請把這篇文章分享給你的朋友
轉載 / 投稿請聯絡:baiyu@hzbook.com
更多精彩,請在後臺點選“歷史文章”檢視