网站数据分析(5)——使用python获取运营数据

2,415 阅读22分钟

使用Python获取数据,目前主要的方法集中在文本文件、Excel文件、关系型和非关系型数据库、API、网页等方面。

获取数据所用到的包:

Numpy中文文档:www.numpy.org.cn/article/bas…

Pands中文文档:www.pypandas.cn/docs/

一、从文本文件读取运营数据

1.1 使用read、readline、readlines读取数据

Python可以读取任意格式的文本数据,使用Python读取文本数据的基本步骤是:

(1)定义数据文件;(2)获取文件对象; (3)读取文件内容; (4)关闭文件对象。

(1)定义数据文件

定义数据文件即定义要读取的文件,该步骤不是必须的,可以跟“获取文件对象”整合。但为了后续操作的便捷性、全局数据对象的可 维护性以及减少代码冗余,建议读者养成习惯,将数据文件预先赋值给一个对象。

定义文本数据文件的方法是:

file_name = [文件名称]

实例:

file_name = 'text.txt'

文件名称中可以只写文件名,此时默认Python读取当前工作目录下 的文件;也可以加入路径,默认使用斜杠,尤其是Windows下要注意用法。

(2)获取文件对象

获取文件对象的意义是基于数据文件产生对象,后续所有关于该数据文件的操作都基于该对象产生。

语法:

fileobject = open(name[,mode][,buffering])

参数:

  • name:要读取的文件名称,即上一个环节定义的file_name,必填
  • mode:打开文件的模式,选填,在实际应用中,r、r+、w、w+、a、a+是使用最多的模式。
  • buffering:文件所需的缓冲区大小,选填;0表示无缓冲,1表示线路缓冲。

返回:通过open函数会创建一个文件对象(fileobject)。示例:

file_name = 'text.txt'
file_object=open(file_name)

file_object=open('text.txt')

(3)读取文件内容

Python基于文件对象的读取分为3种方法,以读取text.txt为例:

这是第一行
这是第二行
这是第三行

关于read()方法:

1、读取整个文件,将文件内容放到一个字符串变量中

2、如果文件大于可用内存,不可能使用这种处理

执行代码:

file_name = 'text.txt'
file_object=open(file_name,encoding='utf-8')
text1 = file_object.read()
text1

结果

'这是第一行\n这是第二行\n这是第三行'

关于readline()方法:

1、readline()每次读取一行,比readlines()慢得多

2、readline()返回的是一个字符串对象,保存当前行的内容

执行代码:

file_name = 'text.txt'
file_object=open(file_name,encoding='utf-8')
text2 = file_object.readline()
text2

结果

'这是第一行\n'

关于readlines()方法:

1、一次性读取整个文件。

2、自动将文件内容分析成一个行的列表。

执行代码:

file_name = 'text.txt'
file_object=open(file_name,encoding='utf-8')
text3 = file_object.readlines()
text3

结果

['这是第一行\n', '这是第二行\n', '这是第三行']

在实际应用中,read方法和readlines方法比较常用,而且二者都能读取全部文件中的数据。

二者的区别只是返回的数据类型不同,前者返回字符串,适用于所有行都是完整句子的文本文件,例如大段文字信息;

后者返回列表,适用于每行是一个单独的数据记录,例如日志信息。不同的读取方法会直接影响后续基于内容的处理应用;readline由于每次只读取一行数据,因此通常需要配合seek、next等指针操作才能完整遍历读取所有数据记录。

(4)关闭文件内容

每次使用完数据对象之后,需要关闭数据对象。方法是

file_object.close()

理论上,Python可以读取任意格式的文件,但在这里先讲以读取格式化的文本数据文件为主,其中包括txt、csv、tsv等格式的文件,以及有固定分隔符分隔并以通用数据编码和字符集编码(例如utf8、ASCII、GB2312等)存放的无扩展名格式的数据文件。

另外,Python文件操作中的指针类似于Word操作中的光标,指针所处的位置就是光标的位置,它决定了Python的读写从哪里开始。默认情况下,当通过open函数打开文件时,文件的指针处于第一个对象的位置。因此,在上述通过readline读取文件内容时,获取的是第一行数据。仍然是上面示例中的数据文件,我们通过如下代码演示基于不同指针位置读取的内容:

fn=open('text.txt',encoding='utf-8')#获得文件对象
print(fn.tell())#输出指针位置
line1=fn.readline()#获得文件第一行数据 
print(line1)#输出第一行数据
print(fn.tell())#输出指针位置
line2=fn.readline()#获得文件第二行数据
print(line2)#输出第二行数据
print(fn.tell())#输出指针位置 
line3=fn.readline()#获得文件第三行数据
print(line3)#输出第三行数据
fn.close()#关闭文件对象

结果:

0
这是第一行
16
这是第二行
32
这是第三行

1.2 使用Numpy的loadtxt、load、fromfile读取数据

Numpy读取数据的方法包括loadtxt、load和fromfile等3种

(1)numpy的loadtxt()方法

numpy.loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
参数 作用
fname 被读取的文件名(文件的相对地址或者绝对地址)
dtype 指定读取后数据的数据类型
comments 跳过文件中指定参数开头的行(即不读取)
delimiter 指定读取文件中数据的分割符
converters 对读取的数据进行预处理
skiprows 选择跳过的行数
usecols 指定需要读取的列
unpack 选择是否将数据进行向量输出
encoding 对读取的文件进行预编码

执行代码:

import numpy as np
txt_array = np.loadtxt('text.txt',dtype=str,comments='#',encoding='utf-8')
print(txt_array)

结果

['这是第一行' '这是第二行' '这是第三行']

(2)numpy的load()方法

numpy.load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, encoding='ASCII')[source])
参数 作用
file 要读取的文件,字符串或pathlib.Path。类文件对象必须支持 seek()和read()方法。pickle文件要求类文件对象也支持该readline()方法。
mmap_mode 内存映射模式,值域为None、'r+'、'r'、'w+'、'c',选填。
allow_pickle 布尔型,选填,决定是否允许加载存储在npy文件中的pickled对象数组,默认值为True。
fix_imports 布尔型,选填,仅在Python3上加载Python2生成的pickle文件时才有用,其中包括包含对象数组的npy / npz文件。如果fix_imports为True,则pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。
encoding 字符串,决定读取Python2字符串时使用何种编码,选填。

执行代码:

import numpy as np#导入nump库
write_data=np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])#定义要存储的数据 np.save('load_data',write_data)#保存为npy数据文件
np.save('load_data',write_data)#保存为npy数据文件
read_data=np.load('load_data.npy')#读取npy文件
print(read_data)#load()无法直接读取txt文件,只能读取.npy或者.npz的文件。

结果

[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]

(3)numpy的fromfile()方法

numpy.fromfile(file, dtype=float, count=-1, sep='')
参数 作用
file 要读取的文件,字符串或pathlib.Path。
dtype 数据类型
count 整数型,读取数据的数量,-1意味着读取所有数据。
sep 字符串,如果file是一个文本文件,那么该值就是数据间的分隔符。如果为空("")则意味着file是一个二进制文件,多个空格将按照一个空格处理。

执行代码:

import numpy as np
txt_array3 = np.loadtxt('text.txt',dtype=str,comments='#',encoding='utf-8')
print(txt_array3)
tofile_name = 'binary'#定义导出二进制文件名
txt_array3.tofile(tofile_name)#导出二进制文件
fromfile_data = np.fromfile(tofile_name,dtype='float32')#读取二进制文件print(fromfile_data)#打印数据

结果

['这是第一行' '这是第二行' '这是第三行']

1.3 使用Pandas的read_csv、read_fwf、read_table读取数据

(1)Pandas的read_csv()方法

pandas.read_csv(filepath_or_buffer: Union[str, pathlib.Path, IO[~AnyStr]], sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)
参数 作用
file 要读取的文件,字符串或pathlib.Path。
dtype 数据类型
count 整数型,读取数据的数量,-1意味着读取所有数据。
sep 字符串,如果file是一个文本文件,那么该值就是数据间的分隔符。如果为空("")则意味着file是一个二进制文件,多个空格将按照一个空格处理。

text.csv文档原始数据:

       1            	2
这是第一行第一列	这是第一行第二列
这是第二行第一列	这是第二行第二列

执行代码:

import pandas as pd
txt_array4 = pd.read_csv('text.csv',sep=',',dtype='str',encoding='gbk')
print(txt_array4)

结果

         1                 2
0  这是第一行第一列  这是第一行第二列
1  这是第二行第一列  这是第二行第二列

(2)Pandas的read_fwf()方法

pandas.read_fwf(filepath_or_buffer, colspecs='infer', widths=None, **kwds)
参数 作用
filepath_or_buffer 要读取的文件,字符串或pathlib.Path。
widths 由整数组成的列表,选填,如果间隔是连续的,可以使用的字段宽度列表而不是“colspecs”。

执行代码:

import pandas as pd
txt_array4 = pd.read_fwf('text.csv',sep=',',dtype='str',encoding='gbk')
print(txt_array4)

结果

         1,2
0  这是第一行第一列,这是第一行第二列
1  这是第二行第一列,这是第二行第二列

(3)Pandas的read_table()方法

pandas.read_table(filepath_or_buffer, sep='\t', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, skipfooter=0, skip_footer=0, doublequote=True, delim_whitespace=False, as_recarray=None, compact_ints=None, use_unsigned=None, low_memory=True, buffer_lines=None, memory_map=False, float_precision=None)[source]

参数:对于read_table而言,参数与read_csv完全相同。其实read_csv本来就是read_table中分隔符是逗号的一个特例,表现在语法中是read_csv的sep=','(默认)。因此,具体参数请查阅read_csv的参数部分。

read_csv() 读取以‘,’分割的文件到DataFrame

read_table()读取以‘/t’分割的文件到DataFrame

分割符既有空格又有制表符(‘/t’),sep参数用‘/s+’,可以匹配任何空格。

参数 作用
filepath_or_buffer 要读取的文件,字符串或pathlib.Path。
widths 由整数组成的列表,选填,如果间隔是连续的,可以使用的字段宽度列表而不是“colspecs”。

执行代码:

import pandas as pd
txt_array4 = pd.read_table('text.csv',sep='/s+',dtype='str',encoding='gbk')
print(txt_array4)

结果

         1,2
0  这是第一行第一列,这是第一行第二列
1  这是第二行第一列,这是第二行第二列

1.4 如何选择最佳读取数据的方法

  • 对于纯文本格式或非格式化、非结构化的数据,通常用于自然语言处理、非结构化文本解析、应用正则表达式等后续应用场景下,Python默认的三种方法更为适合。

  • 对于结构化的、纯数值型的数据,并且主要用于矩阵计算、数据建模的,使用Numpy的loadtxt方法更为方便,例如本书中使用的sklearn 本身就依赖于Numpy。

  • 对于二进制的数据处理,使用Numpy的load和fromfile方法更为合适。

  • 对于结构化的、探索性的数据统计和分析场景,使用Pandas方法进行读取效果更佳,因为其提供了类似于R的数据框,可以实现“仿SQL”式的操作方式,对数据进行任意翻转、切片(块等)、关联等都 非常方便。

  • 对于结构化的、数值型和文本型组合的数据统计分析场景,使用Pandas更为合适,因为每个数据框中几乎可以装载并处理任意格式的数 据。

二、从EXCEL文件读取运营数据

现有的Excel分为两种格式:xls(Excel 97-2003)和xlsx(Excel 2007及以上)。

Python处理Excel文件主要是第三方模块库xlrd、xlwt、pyexcel-xls、xluntils和pyExcel-erator,以及win32com和openpyxl模块,此外Pandas中也带有可以读取Excel文件的模块(read_excel)。

我们主要说主流的read_excel()

pandas.read_excel(io,sheet_name = 0,header = 0,names = None,index_col = None,usecols = None,squeeze = False,dtype = None, ...)
参数 作用
io 字符串,文件的路径对象。
sheet_name None、string、int、字符串列表或整数列表,默认为0。字符串用于工作表名称,整数用于零索引工作表位置,字符串列表或整数列表用于请求多个工作表,为None时获取所有工作表。
header 指定作为列名的行,默认0,即取第一行的值为列名。数据为列名行以下的数据;若数据不含列名,则设定 header = None。
names 默认为None,要使用的列名列表,如不包含标题行,应显示传递header=None。
index_col 指定列为索引列,默认None列(0索引)用作DataFrame的行标签。
usecols int或list,默认为None。
squeeze boolean,默认为False,如果解析的数据只包含一列,则返回一个Series。
dtype 列的类型名称或字典,默认为None。数据或列的数据类型。例如{'a':np.float64,'b':np.int32}使用对象保存存储在Excel中的数据而不解释dtype。如果指定了转换器,则它们将应用于dtype转换的INSTEAD。
skiprows 省略指定行数的数据,从第一行开始。
skipfooter 省略指定行数的数据,从尾部数的行开始。

执行代码:

import pandas as pd
txt_array4 = pd.read_excel('text.xlsx',sep='\s+',encoding='gbk')
print(txt_array4)

结果

      1                   2
0  这是第一行第一列  这是第一行第二列
1  这是第二行第一列  这是第二行第二列

三、从关系型数据库MySQL读取运营数据

3.1 第一步,下载Navicat,连接mysql

3.2 第二步,将Excel数据导入数据库

选择要导入的表,右键选择“导入向导”,再选择格式类型“EXCEL”。

3.3 第三步,用python的pymysql包连接mysql数据库

pymysql语法教程链接:www.runoob.com/python3/pyt…

import pymysql
# 打开数据库连接(IP地址,用户名,密码,数据库名称)
db = pymysql.connect("localhost","testuser","test123","TESTDB" )
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
# 使用 execute()  方法执行 SQL 查询 
cursor.execute("SELECT VERSION()")
# 使用 fetchone() 方法获取单条数据.
data = cursor.fetchone()
print ("Database version : %s " % data)
# 关闭数据库连接
db.close()

结果

Database version : 5.5.57-log 

3.4 第四步,操作mysql数据

SQL语句教程:www.w3school.com.cn/sql/index.a…

正则表达式教程:www.runoob.com/regexp/rege…

# SQL 查询语句
sql = "SELECT `订单产品数据`.`订单状态`,COUNT(*) FROM `订单产品数据` GROUP BY `订单产品数据`.`订单状态`"
try:
   # 执行SQL语句
   cursor.execute(sql)
   # 获取所有记录列表
   results = cursor.fetchall()
   print (results)
except:
   print ("报错")

结果:

(('交易取消', 33), ('交易完成', 16), ('待发货', 17), ('待收货', 218), ('拍下商品', 20), ('退货完成', 6))

四、从非关系型数据库MongoDB读取运营数据

PyMongo教程:www.runoob.com/python3/pyt…

4.1 安装MongoDB

MongoDB教程:www.runoob.com/mongodb/mon…

4.2 测试是否正常启动

import pymongo
myclient = pymongo.MongoClient('mongodb://localhost:27017/')
dblist = myclient.list_database_names()
if "runoobdb" in dblist:
  print("数据库已存在!")

结果

数据库已存在!

4.3 创建集合,插入多个文档

mydb = myclient["runoobdb"]
mycol = mydb["sites"]
 
mylist = [
  { "name": "Taobao", "alexa": "100", "url": "https://www.taobao.com" },
  { "name": "QQ", "alexa": "101", "url": "https://www.qq.com" },
  { "name": "Facebook", "alexa": "10", "url": "https://www.facebook.com" },
  { "name": "知乎", "alexa": "103", "url": "https://www.zhihu.com" },
  { "name": "Github", "alexa": "109", "url": "https://www.github.com" }
]
 
x = mycol.insert_many(mylist)
 
# 输出插入的所有文档对应的 _id 值
print(x.inserted_ids)

结果

[ObjectId('5b236aa9c315325f5236bbb6'), ObjectId('5b236aa9c315325f5236bbb7'), ObjectId('5b236aa9c315325f5236bbb8'), ObjectId('5b236aa9c315325f5236bbb9'), ObjectId('5b236aa9c315325f5236bbba')]

4.4 查询集合中所有数据

mydb = myclient["runoobdb"]
mycol = mydb["sites"]
 
for x2 in mycol.find():
  print(x2)

结果

{'_id': ObjectId('5d4390faa89575889f30d11e'), 'name': 'RUNOOB', 'alexa': '10000', 'url': 'https://www.runoob.com'}
{'_id': ObjectId('5d439138a89575889f30d11f'), 'name': 'Taobao', 'alexa': '100', 'url': 'https://www.taobao.com'}
{'_id': ObjectId('5d439138a89575889f30d120'), 'name': 'QQ', 'alexa': '101', 'url': 'https://www.qq.com'}
{'_id': ObjectId('5d439138a89575889f30d121'), 'name': 'Facebook', 'alexa': '10', 'url': 'https://www.facebook.com'}
{'_id': ObjectId('5d439138a89575889f30d122'), 'name': '知乎', 'alexa': '103', 'url': 'https://www.zhihu.com'}
{'_id': ObjectId('5d439138a89575889f30d123'), 'name': 'Github', 'alexa': '109', 'url': 'https://www.github.com'}

在企业实际应用中,非关系型数据库往往基于“大数据”的场景产生,伴随着海量、实时、多类型等特征。这些数据库通过舍弃了关系型数据库的某些特征和约束,然后在特定方面进行增强,因此才能满足特定应用需求。非关系型数据库由于约束性、规范性、一致性和数据准确性低于关系性数据库,因此常用于实时海量数据读写、非结构化和半结构化信息读写、海量集群扩展、特殊场景应用等。所以在金融、保险、财务、银行等领域内,这种应用比较少;而互联网、移动应用等新兴产 业和行业领域则应用较多。

五、从API获取运营数据

为了更好地让所有读者都能了解从API获取数据的具体过程,本节使用百度免费API作为实际数据来源。百度API提供了众多地图类功 能,如基本地图、位置搜索、周边搜索、公交驾车导航、定位服务、地理编码及逆地理编码等。本节使用的是百度Web服务API中的Geocoding API。

Geocoding API用于提供从地址到经纬度坐标或者从经纬度坐标到地址的转换服务,用户可以发送请求且接收JSON、XML的返回数。 该应用可用于对运营数据中的地址相关信息进行解析,从而获得经纬度信息,这些信息可用于进一步基于地理位置进行解析、展示和分析等。

要获得该API,需要拥有百度相关账户和AK信息。

第一步 获得百度账户,没有账户的读者可在 passport.baidu.com/v2/?reg 处免费注册获取。

第二步 注册成为百度开放平台开发者,读者可进入 lbsyun.baidu.com/apicon-sole… 完成相关注册。 该过程非常简单,遵循引导整个过程在5分钟内即可完成。

第三步 注册完成之后,会有一个名为“【百度地图开放平台】开发者激活邮件”的验证链接发送到指定(注册时邮箱)邮箱,点击链接即可完成验证。

第四步 点击“申请秘钥”进入创建应用界面,在该应用创建中,我 们主要使用Geocoding API v2,其他应用服务根据实际需求勾选。IP白名单区域,如果不做限制,请设置为“0.0.0.0/0”。设置完成后,点击提 交。

第五步 获得AK秘钥。完成上述步骤之后,会默认跳转到应用列表界面,界面中的“访问应用(AK)”便是该应用的秘钥。

5.1 获取并解析XML数据

我们先通过Python请求该API来获得JSON格式的数据。本示例的目标是通过给百度API发送一条地理位置数据,返回其经纬度信息。 本节会用到Python第三方库requests,读者需要先通过pip install requests进行安装。完整代码如下:

import requests # 导入库 
add = '广州市天河区正佳广场' # 定义地址 
ak = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' # 创建访问应用时获得的AK 
url = 'http://api.map.baidu.com/geocoder/v2/?address=%s&output=xml&ak=%s' # 请求URL 
res = requests.get(url % (add, ak)) # 获得返回请求 
add_info = res.text # 返回文本信息 
print (add_info) # 打印输出

结果

<?xml version="1.0" encoding="utf-8"?>
<GeocoderSearchResponse>
	<status>0</status>
	<result>
		<location>
			<lng>113.333581818</lng>
			<lat>23.1383236194</lat>
		</location>
		<precise>1</precise>
		<confidence>80</confidence>
		<comprehension>100</comprehension>
		<level>购物</level>
	</result>
</GeocoderSearchResponse>

接着我们通过引入一个XML格式化处理库来从中提取经纬度信息。

# 设置字符编码为utf-8 
import importlib
importlib.reload(sys)
import xml.etree.ElementTree as Etree # 导入XML中的ElementTree方法 
root = Etree.fromstring(add_info) # 获得XML的根节点 
lng = root[1][0][0].text # 获得lng数据 
lat = root[1][0][1].text # 获得lat数据 
print ('lng: %s' % lng) # 格式化打印输出 
print ('lat: %s' % lat) # 格式化打印输出

结果

lng: 113.333581818
lat: 23.1383236194

5.2 获取并解析JSON数据

import requests # 导入库 
add = '广州市天河区正佳广场' # 定义地址 
ak = 'DdOyOKo0VZBgdDFQnyhINKYDGkzBkuQr' # 创建访问应用时获得的AK 
url = 'http://api.map.baidu.com/geocoder/v2/?address=%s&output=json&ak=%s' # 请求URL 
res = requests.get(url % (add, ak)) # 获得返回请求 
add_info = res.text # 返回文本信息 
print (add_info) # 打印输出

结果

{"status":0,"result":{"location":{"lng":113.33358181846966,"lat":23.138323619365097},"precise":1,"confidence":80,"comprehension":100,"level":"购物"}}

该结果可以通过JSON进行格式化处理

import json # 导入库 
add_json = json.loads(add_info) # 加载JSON字符串对象 
lat_lng = add_json['result']['location'] # 获得经纬度信息 
print (lat_lng) # 打印输出

结果

{'lng': 113.33358181846965, 'lat': 23.138323619365096}

有关百度API的更多信息,具体查阅

lbsyun.baidu.com/index.php?t…

在API应用中,中文的编码处理因细节太多而常常让人头疼。因此,如果可以则应尽量减少直接在API的数据中出现中文字符。在实际企业应用中,会出现多种API形式,但无论哪种形式,其基本实现思路 都是一致的:导入库→定义请求变量→发送请求→获得返回数据→格式化并获得目标数据,因此需要掌握JSON和XML的数据与其他数据的转换方法。

六、读取非结构化网页、文本、图像、视频、语音

6.1 读取非结构化网页

举个简单的例子

import requests  # 导入库
url = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=python&oq=python'  # 定义要抓取的网页地址
res = requests.get(url)  # 获得返回请求
html = res.text  # 返回文本信息
print(html)  # 打印输出网页源代码

想进阶的朋友看Scrapy爬取网页教程:www.imooc.com/learn/1017

6.2 读取非结构化文本

非结构化的文本数据指的是文本数据中没有结构化的格式,需要定制化解析才能获取数据,并且每条记录的字段也可能存在差异,这意味 着传统的结构化读取方式很难工作。非结构化的日志就是一个典型示例,服务器的日志可由运维工程师自行定义,因此不同公司的日志格式有所不同;另外在网站日志中还可能包含通过页面“埋码”的方式而采集来的用户行为数据,这些都会使日志面临非结构化的解析问题。

file = 'file_log'
fn = open(file, 'r')  # 打开要读取的日志文件对象
content = fn.readlines()  # 以列表形式读取日志数据
print(content[:2])
fn.close()  # 关闭文件对象

其实日志文件只是普通文本文件中的一种类型而已,其他的非结构化数据文件都可以以类似的方法读取,即使文件没有任何扩展名。 对于非结构化的文本处理,通常更多地侧重于特定场景,通用性较差,原因就在于非结构化的形式本身变化多样。自然语言理解、文本处 理和挖掘、用户日志和机器日志解析等都是该领域中的主要工作。

6.3 读取图像数据

Python读取图像通常使用PIL和OpenCV两个库,相对而言,笔者使用后者的情况更多。

OpenCV教程:juejin.cn/post/684490…

import cv2
# 1、文件的读取 2、封装格式解析 3、数据解码 4、数据加载
img = cv2.imread('canton.jpg',1)
cv2.imshow('image',img)
# jpg png 1、文件头 2、文件数据
cv2.waitKey (0)
# waitKey(0),以毫秒为单位延迟。0是指“永远”的特殊值

6.4 读取视频数据

Python读取视频最常用的库也是OpenCV。

import cv2  # 导入库

cap = cv2.VideoCapture("test.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(int(1000 / frame_fps))  # 每次帧播放延迟一定时间,同时等待输入指令
    if k == 27:  # 如果等待期间检测到按键ESC
        break  # 退出循环

# 操作结束释放所有对象
cv2.destroyAllWindows()  # 关闭所有窗口
cap.release()  # 释放视频文件对象

6.5 读取语音数据

对于语音文件的读取,可以使用Python的audioop、aifc、wav等库实现。但针对语音处理这一细分领域,当前市场上已经具备非常成熟的 解决方案,例如科大讯飞、百度语音等,大多数情况下,我们会通过调用其API实现语音分析处理,或者作为分析处理前的预处理。

以百度语音API服务应用为例,说明如何通过请求百度语音的API,将语音数据转换为文字信息。

申请百度语音API教程:jingyan.baidu.com/article/f3e…

# 导入库
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).decode('utf-8')  # 将语音内容转换为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)  # 打印输出语音识别的文字