2.2 使用Python获取运营数据-2
“详细阐述使用Python获取运营数据的四种核心途径及实操方法。涵盖利用xlrd读取Excel文件;通过mysql.connector连接MySQL执行SQL查询;使用pymongo操作MongoDB处理非关系型数据;以及借助requests库调用外部API并解析JSON与XML数据。内容对比了不同数据源的适用场景,为企业数据化运营提供底层技术支撑。”
说明:本文是《Python 数据分析与数据化运营》中的“2.2 使用 Python 获取运营数据”中的第二部分,由于本节内容较多,这里分几个文章。
2.2.2 从 Excel 获取运营数据
现有的 Excel 分为两种格式:xls(Excel 97-2003)和 xlsx(Excel 2007 及以上)。
Python 处理 Excel 文件主要是第三方模块库 xlrd、xlwt、pyexcel-xls、xluntils 和 pyExcelerator,以及 win32com 和 openpyxl 模块,此外 Pandas 中也带有可以读取 Excel 文件的模块(read_excel)。
基于扩展知识的目的,我们使用 xlrd 模块读取 Excel 数据。首先安装该库,在系统终端命令行输入命令 pip install xlrd。然后我们以“附件-chapter2”文件夹 demo.xlsx 数据文件为例,介绍该库的具体应用。数据概览如图 2-7 所示:
图 2-7 数据文件内容
python
上述代码中,我们先读取一个 Excel 文件,再查看所有 sheet(工作簿)并输出 sheet1 相关属性信息;然后查看 sheet1 中特定数据行、列和元素的信息;最后我们用循环的方式,依次读取每个数据行并打印输出。
以下是代码执行后打印输出的结果:
code
提示 在上述打印输出的内容中,我们发现第二列、第三列、第四列与原始数据似乎不同。第二列和第四列“异常”的原因是将中文编码统一转换为 Unicode 编码,便于在不同程序间调用;第三列“异常”是由于将日期格式转换为数值格式而已。
上述操作只是将数据从 Excel 中读取出来,基于读取的数据转换为数组便可以进行矩阵计算。由于矩阵计算大多是基于数值型数据实现的,因此上述数据将无法适用于大多数科学计算场景,这点需要注意。
总结:在企业实际场景中,由于 Excel 本身的限制和适用,其无法存储和计算过大(例如千万级的数据记录)的数据量,并且 Excel 本身也不是为了海量数据的应用而产生的。因此,Excel 可以作为日常基本数据处理、补充数据来源或者汇总级别的数据进行读取,同时也可以作为数据结果展示的载体,这种应用下对于大量数值表格的应用效果非常好。
2.2.3 从关系型数据库 MySQL 读取运营数据
在第一章“1.2.4 数据库和客户端”中我们介绍了安装 MySQL 和 Navicat 的方法和关键步骤。这里我们介绍如何从利用 Python 从 MySQL 中读取数据。
在“附件-chapter2”文件夹中有一个名为 order.xlsx 的数据文件,我们先把文件导入 MySQL 数据库,然后再基于数据库进行相关操作。
第一步,新建一个数据库用于存放要导入的目标数据。
步骤 1:打开 Navicat,左侧导航栏中有我们已经建立好的数据库链接,在第一章中我们已经建立好了本地连接,名为“127.0.0.1”。
步骤 2:双击该数据库连接,会展示出所有当前连接(对应的用户权限)下可用的数据库,如图 2-8。
图 2-8 127.0.0.1 下的数据库
步骤 3:为了保持不同数据的独立性,我们新建一个数据库,单独存放特定主题的数据。在“127.0.0.1”名称上右键,在弹出的菜单中选择新建数据库,然后做如下设置并点击确定。完成之后在左侧的“127.0.0.1”链接下会新增一个刚才新建的数据库 python_data。
第二步,将 Excel 数据导入数据库。
双击刚才新建的名为 python_data 的数据库名称,激活数据库连接。此时右侧功能栏中的部分功能已经可用。点击“导入向导”,开始导出 Excel 数据。如图 2-10。
图 2-10 创建导入向导
步骤 1:选择数据文件格式:Excel 2007。
步骤 2:选择数据源文件。
图 2-11 设置导入数据源
步骤 3:定义附加选项。由于数据文件中第一行是表头,因此数据从第二行开始;日期分隔符与数据文件一致,需要设置为 -,其他都为默认值。
图 2-12 设置导入附件选项
步骤 4:设置目标数据表名为 order。
步骤 5:设置字段类型、长度、约束等信息。其中主要的设置是将 order_data 类型设置为 date(日期型),长度为 0(不做限制);order_tme 类型设置为 time(时间型),长度为 0(不做限制);total_amount 类型设置为 float(浮点型),长度默认为 255。
图 2-13 设置字段类型等约束
提示 实际上,我们的数据很可能用不了那么多的“存储空间”,因此在设置时存在数据空间冗余,不过没关系,这里我们仅仅做入门引导之用。真正涉及到数据库表的模型设计有很多学问,这里的设置不会影响我们做数据统计分析之用。
步骤 6:设置导入模式。由于我们是新创建表,因此设置为:添加。
步骤 7:启动导入任务。点击 开始 即可。
等待系统导入数据,导入成功后,会在窗口中显示如下信息,最终的信息中包含 successfully,如图 2-14。点击关闭按钮即可。
图 2-14 导入成功提示信息
至此我们已经成功导入数据,在数据库 python_data 下新增了一个名为 order 的数据表。我们要初步验证导入的数据是否与原始数据一致。双击打开该表。
打开表之后,会弹出信息提示该表没有主键。该信息不影响我们使用该表,点击确定即可。
图 2-15 提示表没有主键
提示 在创建表时,我们完全可以指定主键,例如本案例中的
order_id是唯一的,那么可指定该字段作为主键,更可以创建一个自增长 ID 作为主键。本节的主要内容是介绍如何导入外部数据到数据库,有关数据库建表还有很多话题,在此不作更多介绍。
打开 order 表之后,会显示如下表预览内容:
图 2-16 数据表概览
在当前窗口,点击“文件-查询表”或直接使用快捷键 Ctrl+Q,打开 SQL 窗口,然后输入 `SELECT * FROM `order` LIMIT 5;` 点击“运行”或使用快捷键 Ctrl+R,返回前 5 条结果,如下图 2-17。读者可以在此输入其他 SQL 或直接浏览数据表来核对数据导入是否准确。
注意 由于表名
order是数据库中的排序关键字,因此在查询表时需要写为`order`,否则会报错。
图 2-17 运行 SQL 并返回结果
导入 Excel 数据主要核对的信息点包括:
- 数据记录数是否一致:使用
`SELECT COUNT(*) FROM `order`;`或在导入成功提示窗口也可以看到。 - 数据字段数量是否一致,导入表中的字段不能多也不能少。
- 查看数据内容是否一致,尤其是日期、时间等非字符串字段的数据,很多时候时间型的数据转换会出现
0000-00-00,这通常是导入设置的日期分隔符问题。 - 数据精准度是否一致,尤其是原始数据是浮点型,对应到数据库字段是否还是浮点型(注意小数位数),问题通常出现在字段类型和位数设置。
- 注意字段的最大长度,不同的数值型数据长度位数是不同,例如整数型
tinyint、int,浮点型的单精度和双精度浮点等,这对于汇总级别的数据会产生极大影响(因为某些字段的汇总数据可能非常大)。
通过 Python 连接 MySQL 需要有 Python 库来建立连接,本节使用 MySQL 官方驱动连接程序,更多信息可在“1.2.3 Python 第三方库”中的“5.数据库连接库”中找到。以下是 Python 读取数据库数据的基本方法:
python
上述代码中,实现了通过 Python 连接 MySQL 查询所有的数据,并输出前 2 条数据的功能。执行结果如下:
code
在应用 MySQL 中,除了查询所有数据外,更多时候我们还会应用更多 SQL 技巧来帮助我们快速找到目标数据并作初步处理。以下是常用 SQL 语法。
只查询前 N 条数据而非全部数据行记录。示例:只查询前 100 条数据记录。
sql
知识点:LIMIT 为限制的数据记录数方法,语法为 limit m,n,意思是从第 m 到 m+n 条数据。m 可省略,默认值从 0 开始,如上述示例中是从 0 开始,取 100 条数据。例如,要从第 11 条开始取,取 10 条可以写为 `SELECT * FROM `order` LIMIT 11, 10;`
只查询特定列(而非全部列)数据。示例:只查询 total_amount 和 order_id 两列数据。
sql
知识点:选择特定列只需将列名写到表达式中即可,多个列名用英文逗号分隔。另外,还可以使用 表名.字段名 的写法,例如上述表达式可以写成 `SELECT order.total_amount, order.order_id from `order`;` 这种写法会出现在表达式中出现多个表的情况下,例如多表关联查询。
查询特定列去重后的数据。示例:查询针对 user_id 去重后的数据。
sql
知识点:关键词 DISTINCT 用于返回唯一不同的值,后面接字段名即要去重的字段。如果后面接多个字段会默认对多个字段同时进行比较,只有多个字段完全相同时才会去重。DISTINCT 常用来返回去重后的特定 ID,或者与 COUNT 配合使用,查询特定数据记录的唯一数量。
查询带有 1 个条件的数据。示例:查询 total_amount < 100 的所有数据。
sql
知识点:WHERE 是条件关键字,后面接具体条件。本示例中,由于 total_amount 为浮点型,因此直接可与数值型比较;如果是字符串型,则比较值需要加引号用来表示一致的字段类型。
查询带有多个条件(同时满足)的数据。示例:查询 total_amount < 100 且 status 为 REMOVED 的所有数据。
sql
知识点:多个条件使用 and 表示且的关系,多个条件必须同时满足。MySQL 中字段不区分大小写。由于 status 也是关键字,因此也需要使用 `status`。
查询带有多个条件(满足任意一个)的数据。示例:查询 total_amount < 100 或 status 为 REMOVED 的所有数据。
sql
知识点:多个条件使用 or 表示或的关系,多个条件满足任意一个条件即可。
查询特定条件值在某个值域范围内的数据。示例:查询 status 的值为 REMOVED 或 NO_PENDING_ACTION 或 PENDING_ORDER_CONFIRM。
sql
知识点:对于特定字段采用“穷举法”列出值域的方法,也可以使用 or 方法连接多个条件,但使用列表的穷举法会使得表达式更简单。
使用正则表达式查询具有复杂条件的数据。示例:查询 user_id 以 106 开头且 order_id 包含 04 的所有订单数据。
sql
知识点:正则表达式通常用在复杂条件中,通过使用关键字 LIKE 来连接不同的正则语法,LIKE 后面接具体的匹配模式,常用的匹配模式包括:
- 以 * 开头:
'字符串%',例如'ABD%'表示以 ABD 为开头的所有匹配; - 以 * 结尾:
'%字符串',例如'% ABD'表示以 ABD 为结尾的所有匹配; - 包含 *:
'%字符串%',例如'%ABD%'表示包含 ABD 的所有匹配。
关于正则表达式还有更多强大的语法规则,限于篇幅不作展开介绍。
将查询到的数据倒叙排列。示例:将 total_amount 金额在 10~100 之间的所有数据,按照订单 ID 倒叙排序。
sql
知识点:在查询表达式 ORDER BY 的结尾,通过使用 DESC 来表示倒叙(逆序)排序;省略是默认使用 ASC 正序(顺序)排序。
查询指定列中不包含空值的所有数据。示例:查询 order_id 不为空的所有数据。
sql
知识点:在 MySQL 中,IS NULL 表示为空,IS NOT NULL 表示非空。需要注意的是,NULL 不代表空字符串或者空格,而是真正意义上的没有任何数据,类似于 Python 中的 None。
上述案例只是展示了如何取数,更多情况下,我们会配合特定函数和方法做数据计算、整合和探索性分析,例如:
- 使用 MySQL 聚合函数求算术平均值、计数、求最大最小值、做分类汇总等;
- 使用 MySQL 数学函数,用来求绝对值、对数计算、平方根等;
- 使用 MySQL 字符串函数进行字符串分割、组合、截取、匹配、处理等;
- 使用 MySQL 的日期函数进行日期获取、转换、处理等;
- 使用 MySQL 将多个表(2 个或 2 个以上)数据进行关联、匹配和整合。
关于在 Python 还是 MySQL 中进行数据处理计算的争议
在 Pythoner(Python 工作者)看来,MySQL 的很多工作 Python 本身也能胜任,为什么还要耗费时间和精力学习如何在 MySQL 中完成这些数据工作,直接用 Python 读取数据然后基于 Python 的相关库进行数据运算岂不更好?
- Python 的工作强项并不是数据计算,而是其灵活、高效、简易和集成多方的工作方式、效率和效果。MySQL(以及其他关系型数据库)作为成熟的数据存储和集成解决方案,在(关系型)数据本身方面更具优势,尤其是对于数据结构定义(实体、属性、关系)、关系操作(选择、连接、聚合等)、关系完整性约束(主外键、唯一性等)等方面具有成熟且稳定的应用价值,这对于数据处理至关重要,因此可以说 MySQL 在结构化数据存储和初步处理工作上比 Python 更专业。
- 还有一个更加关键的原因是如果所有数据工作都由 Python 完成,那么 Python 的事务处理在某些情况下一定会面临资源瓶颈、工作效率等问题,届时可能会导致程序崩溃和报错,这将大大降低程序的可靠性以及结果输出的效率,对于海量数据工作尤为如此。
因此,很多时候不是 Python 不能做,而是在合适的时机选择最合适的工具来完成才是最好的选择。
2.2.4 从非关系型数据库 MongoDB 读取运营数据
由于 MongoDB 一般都是企业级数据存储,因此这里我们使用在第一章已经安装过的 SSH 远程客户端 SecureCRT。如果读者有自己在虚拟机或本地安装 MongoDB,也可以使用,操作方法类似。
双击 SecureCRT 打开程序,点击顶部的“快速连接”按钮,新建连接。
图 2-18 新建快速连接
然后根据服务器具体配置情况,配置如下信息,其中主机名和用户名需要单独配置,其他的根据实际情况询问 IT 或运维管理人员(本案例中都是默认值)。可勾选用于以后启动该程序时直接显示快捷入口。
图 2-19 填写连接配置信息
点击连接之后,会弹出密码输入窗口,输入密码,可勾选“用于以后无需重复输入密码”,具体视公司安全规定执行。
图 2-20 填写密码
如果服务器配置信息填写正确,连接服务器成功会显示如下信息:
图 2-21 成功连接服务器
要想通过 Python 调用 MongoDB,需要安装 PyMongoDB,直接使用 pip install pymongo 即可实现。
注意 不同的服务器环境对于可访问外网的限制有差异,有的服务器可以访问外网,而有的服务器却不能。我们在第一章中的大多数安装方法,默认都是通过 pip 请求外部网络资源实现的,对于无法直接从服务器连接外网的,请参照“1.2.3 Python 第三方库”中的方法,先将安装包和依赖包下载到本机,然后再拷贝到服务器上,再通过
setup和pip命令安装。
使用 Python 连接 MongoDB 之前,需要服务器上的 MongoDB 处于启动状态。查看是否成功启动的方法是找一个可以直接连接或访问服务器的浏览器,直接输入 IP:端口,如果出现“It looks like you are trying to access MongoDB over HTTP on the native driver port.”字样的提示则说明已经正常启动和运行。
例如:笔者的服务器上已经启动了该服务,在浏览器中输入 http://10.66.202.134:27017/ 后提示如下信息:
图 2-22 MongoDB 服务启动后的浏览器返回信息
提示 MongoDB 也提供了 Windows 版本的程序,有兴趣的读者,可登陆 https://www.mongodb.com/download-center#community 下载程序并进行本地部署安装。
要在服务器上进入 Python 环境,直接在终端窗口输入命令 python。在 Python 命令行窗口中,通过如下方法调用 MongoDB 数据。
python
上述代码中,我们连接到 MongoDB 后选择了 test_py 库下的 ordersets 集合,然后插入 2 条数据到集合中,再从集合中查看单独一条以及所有集合数据。
以下是代码执行后打印输出的结果:
code
除了上述基本查询语句外,PyMongo 也提供了类似于 MySQL 一样的条件过滤。
查询特定文档数据。示例,只查询第 2 条数据。
python
知识点:通过增加索引值可以指定查询特定索引的文档数据。注意索引值从 0 开始,0 代表第一条是数据。
查询特定范围内的文档数据。示例,只查询第 1-2 条数据。
python
知识点:通过增加索引值可以指定查询特定索引范围的文档数据(切片)。注意索引值为空则默认从 0 开始,0 代表第一条是数据。上述表达式可以写成 orders.find()[:2]。索引结束值默认不包含,例如上述语法中的 0:2 的实际索引只有 0 和 1。
增加查询条件。示例:只查询 user 为 lucy 的文档数据。
python
知识点:作为 Key-Value 形式的代表应用之一,MongoDB 几乎所有的用法都以 K-V 的形式存在。过滤条件也不例外,只需在 find 函数中,以 Key-Value 的形式设置过滤条件即可,其中 Key 为过滤维度,Value 为对应值。
排序。示例:针对 user 排序输出。
python
知识点:通过使用 Sort 方法设置排序维度。默认是正序,也可以指定为倒叙排列,同时也可以指定多个字段排序规则,例如 collection.find().sort([('field1', pymongo.ASCENDING), ('field2', pymongo.DESCENDING)])。从 MongoDB 2.6 开始,还提供了按照文本相关性的排序方法,例如 collection.find({'score': {'$meta':'textScore'}}).sort([('score', {'$meta': 'textScore'})])。
除了上述基本查询和过滤条件外,PyMongo 也提供了用于做数据统计、分析和探索的基本方法,更多信息,具体查阅 http://api.mongodb.com/python/current/
总结:在企业实际应用中,非关系型数据库往往基于“大数据”的场景产生,伴随着海量、实时、多类型等特征而来。这些数据库通过舍弃了关系型数据库的某些特征和约束,然后在特定方面进行增强,因此才能满足特定应用需求。非关系型数据库由于约束性、规范性、一致性和数据准确性低于关系性数据库,因此常用于实时海量数据读写、非结构化和半结构化信息读写、海量集群扩展、特殊场景应用等。所以在金融、保险、财务、银行等领域内,这种应用比较少;而互联网、移动应用等新兴产业和行业领域则应用较多。
2.2.5 从 API 获取运营数据
为了更好的让所有读者都能了解从 API 获取数据的具体过程,本节使用百度免费 API 作为实际数据来源。百度 API 提供了众多地图类功能,可用于基本地图、位置搜索、周边搜索、公交驾车导航、定位服务、地理编码及逆地理编码等。本节使用的是百度 Web 服务 API 中的 Geocoding API。
Geocoding API 用于提供从地址到经纬度坐标或者从经纬度坐标到地址的转换服务,用户可以发送请求且接收 JSON、XML 的返回数据。该应用可用于对运营数据中的地址相关信息进行解析,从而获得有关经纬度信息,这些信息可用于进一步的基于地理位置的解析、展示和分析等应用。要获得该 API,读者需要拥有百度相关账户和 AK 信息。
第一步 获得百度账户,没有账户的读者可在 https://passport.baidu.com/v2/?reg 免费注册获取。
第二步 注册成为百度开放平台开发者,读者可进入 http://lbsyun.baidu.com/apiconsole/key?application=key 完成相关注册。该过程非常简单,遵循引导整个过程在 5 分钟以内即可完成。
图 2-23 提交成功
第三步 注册完成之后,会有一封名为“【百度地图开放平台】开发者激活邮件”发送验证链接到指定(注册时邮箱)邮箱,点击链接进行验证。
图 2-24 激活验证链接
第四步 点击“申请秘钥”进入创建应用界面,在该应用创建中,我们主要使用 Geocoding API v2,其他应用服务根据实际需求勾选。IP 白名单区域,如果不做限制,请设置为 0.0.0.0/0。设置完成后,点击提交。
图 2-25 创建应用
第五步 获得 AK 秘钥。完成上述步骤之后,会默认跳转到应用列表界面,界面中的“访问应用(AK)”便是该应用的秘钥。
图 2-26 获得 AK 秘钥
1. 获取并解析 json 数据
我们先通过 Python 请求该 API 来获得 json 格式的数据。本示例的目标是通过给百度 API 发送一条地理位置数据,返回其经纬度信息。
本节会用到 Python 第三方库 requests,读者需要先通过 pip install requests 进行安装。完整代码如下:
python
- 在上述代码中,我们先导入一个
requests库,该库用来发送网络请求,支持多种发送模式,可以用来做网页内容抓取、自动化网页测试、网页内容采集等。 - 第二行我们定义了一个地址,该地址通常是运营中的地址类信息,例如:通讯地址、注册地址、收货地址、联系地址等。
- 第三行
ak是创建访问应用时获得的 AK,注意百度有每天 6000 次的限制,读者可填写自行申请的 AK。 - 第四行定义了一个通过
get方法发送的 URL 请求地址,地址中的address和ak的具体值使用占位符代替,在后面用到时具体赋值,这种方法经常用到地址、ak 有变化的场景中。例如:我们通常会创建多个应用(基于每个账户有限制,以及分开治理应用的考虑),然后从数据库中读取一系列地址用于解析,此时的地址和 AK 都需要能动态赋值。
提示 在 API 请求方法中,最常用的是
get和post方法。前者用于向服务器以“明文”(所有参数都在 URL 中体现)的形式请求数据,常用于普通的页面或服务请求,例如浏览网页、搜索关键字等都是GET方法;后者则以“暗语”(所有的数据信息都在 HTTP 消息中)以键值对的形式发送,在 URL 中是看不到具体信息的,常用于数据保密性高的场景,例如登录、注册、订单等表单的处理都是POST方法。
- 第五行通过
get方法发送请求到上面定义的 URL 中,并具体赋值。 - 第六行将返回对象的文本信息赋值到
add_info,返回对象中还包括非常多的相关属性信息,例如状态码、cookie、reason、headers、编码等,这些信息可用于判断是否正确返回、问题原因、状态等信息。 - 最后一行打印输出返回的文本信息。以下是代码执行后打印输出的结果:
json
返回结果包括以下字段:
status:返回结果状态值, 成功返回 0。location:经纬度坐标,其中lat是纬度值,lng是经度值。precise:位置的附加信息,是否精确查找。1 为精确查找,即准确打点;0 为不精确,即模糊打点。confidence:可信度,描述打点准确度。level:百度定义的地址类型。
该结果可以通过 JSON 进行格式化处理。
python
代码中,我们导入 Python 自带的 json 库。该库支持 Python 其他对象和 Json 对象之间的相互转换。
先将获得的地址信息格式化为 json 字符串(字典类型),然后通过读取字典的 Key 来获得其 Value,由于返回的地址信息中包含字典嵌套,因此这里需要依次读出第一层和第二层信息。读者可通过 add_json.items() 来更加直观的观察 2 层嵌套。
上述代码执行后,返回的结果(字典类型)可进行进一步处理:
json
2. 获取并解析 xml 数据
Geocoding API 也提供 XML 格式的返回数据,下面以获得 XML 格式的数据为例介绍代码过程。
python
上述所有代码与 json 格式的代码完全相同,只在第四行定义 url 时,将 output 的返回值类型设置为 xml,执行后返回结果如下:
xml
接着我们通过引入一个 xml 格式化处理库来从中提取经纬度信息。关于 xml 文件的解析,Python 默认和第三方的常用库包括 xml、libxml2、lxml、xpath 等,我们使用 Python 自带的 xml 进行处理。
python
上述代码中,前 4 行实现了一个功能,将代码的字符编码设置为 utf-8,否则系统会默认为 ASCII,对返回的带有中文字符串无法识别而报错。
代码第五行导入 XML 自带的 ElementTree 方法,该方法可以实现对 XML 内容的查询、新建、修改等操作,是 XML 中比较简单容易上手的方法(XML 除了 ElementTree 外,还提供了 DOM 和 SAX 方法)。
代码第六行获得从 API 得到的 XML 对象并获得根节点。 代码第七、八行分别通过嵌套读取从根节点开始向下的第 3 层经纬度数据。 代码最后两行格式化打印输出。
上述代码执行后返回结果如下:
code
有关百度 API 的更多信息,具体查阅 http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
总结:在 API 应用中,中文的编码处理常常是非常头疼的细节。因此,如果可以尽量少的直接在 API 的数据中出现中文字符。在实际企业应用中,会出现多种 API 形式,但无论哪种形式,其基本实现思路都是一致的:导入库→定义请求变量→发送请求→获得返回数据→格式化并获得目标数据,因此需要掌握 Json 和 xml 的数据与其他数据的转换方法。


















