2.2 使用Python获取运营数据
使用Python获取数据,目前主要的应用方法集中在文本文件、Excel文件、关系型和非关系型数据库、API、网页等方面。本节就来介绍具体获取方法。
2.2.1 从文本文件读取运营数据
1.使用read、readline、readlines读取数据
Python可以读取任何格式的文本数据,使用Python读取文本数据的基本步骤如下。
(1)定义数据文件
定义数据文件即定义要读取的文件,该步骤不是必需的,可以跟“获取文件对象”整合。但为了后续操作的便捷性、全局数据对象的可维护性以及减少代码冗余,建议读者养成习惯,将数据文件预先赋值给一个对象。
定义文本数据文件的方法是:
file_name = [文件名称]
示例:
file_name = 'd:/python_data/data/text.txt'
文件名称中可以只写文件名,此时默认Python读取当前工作目录下的文件;也可以加入路径,默认使用斜杠,尤其是Windows下要注意用法。
(2)获取文件对象
获取文件对象的意义是基于数据文件产生对象,后续所有关于该数据文件的操作都基于该对象产生。
语法:
file object = open(name [, mode][, buffering])
参数如下。
name:要读取的文件名称,即上一个环节定义的file_name,必填。
mode:打开文件的模式,选填。在实际应用中,r、r+、w、w+、a、a+是使用最多的模式。完整文件打开模式如表2-1所示。
表2-1 Python文件打开模式
buffering:文件所需的缓冲区大小,选填;0表示无缓冲,1表示线路缓冲。
返回:
通过open函数会创建一个文件对象(file object)。
示例:
file_name = 'text.txt' file_object = open(file_name)
在“定义数据文件”部分提到,可以将前两个环节结合起来,定义的语法是:
file_object = open('text.txt')
(3)读取文件内容
Python基于文件对象的读取分为3种方法,如表2-2所示。
表2-2 Python读取文件内容的方法
示例,在“附件-chapter2”文件夹中有一个名为text.txt的数据文件,其中包含2个文本行,数据内容如图2-2所示。
图2-2 示例数据源文件内容
通过read方法读取该数据文件得到的数据结果如下:
'line1: This is line1\nline2: This is line2'
通过readline方法读取该数据文件得到的数据结果如下:
'line1: This is line1\n'
通过readlines方法读取该数据文件得到的数据结果如下:
['line1: This is line1\n', 'line2: This is line2
在实际应用中,read方法和readlines方法比较常用,而且二者都能读取全部文件中的数据。二者的区别只是返回的数据类型不同,前者返回字符串,适用于所有行都是完整句子的文本文件,例如大段文字信息;后者返回列表,适用于每行是一个单独的数据记录的文件,例如日志信息。不同的读取方法会直接影响后续基于内容的处理应用。由于readline每次只读取一行数据,因此通常需要配合seek、next等指针操作,才能完整遍历读取所有数据记录。
相关知识点:指针
Python文件操作中的指针类似于Word操作中的“光标”,指针所处的位置就是“光标”的位置,它决定了Python的读写从哪里开始。默认情况下,当通过open函数打开文件时,文件的指针处于第1个对象的位置。因此,在上述通过readline读取文件内容时,获取的是第1行的数据。仍然是上面示例中的数据文件,我们通过如下代码演示基于不同指针位置读取的内容。
fn = open('text.txt') # 获得文件对象 print(fn.tell()) # 输出指针位置 line1 = fn.readline() # 获得文件第1行数据 print(line1) # 输出第1行数据 print(fn.tell()) # 输出指针位置 line2 = fn.readline() # 获得文件第2行数据 print(line2) # 输出第2行数据 print(fn.tell()) # 输出指针位置 fn.close() # 关闭文件对象
执行上述代码后,返回如下信息:
0 line1: This is line1 22 line2: This is line2 42
从返回结果看,当打开文件时,文件指针的位置处于文件开头,输出为0;当读取完第1行之后,文件指针位置处于第1行行末,位置是第22个字符后面(也就是’\n’后面,'\n'是换行符);当读取完第2行(最后一行)之后,文件指针位置处于第2行行末,位置是第42个字符后面(注意:由于是最后一行,没有换行符’\n')。
(4)关闭文件对象
每次使用完数据对象之后,需要关闭数据对象。方法是file_object.close()。这种应用方法略显冗余,这里介绍基于with的文件打开方法,该方式可以自动做上下文管理,而无须单独做close操作。
例如,上面的文件读取方式用with可以写成:
with open('text.txt') as fn: content = fn.read()
如果同时要对多个文件对象操作,那么可以连续写open方法。例如,同时对file1.txt和file2.txt做读入可以这样写:
with open('file1.txt') as fn1, open('file2.txt') as fn2: content1 = fn1.read() content2 = fn2.read()
理论上,Python可以读取任意格式的文件,但在这里通常以读取格式化的文本数据文件为主,其中包括有扩展名的txt、csv、tsv等格式的文件,以及由固定分隔符分隔并以通用数据编码和字符集编码(例如utf8、ASCII、GB2312等)存放的无扩展名格式的数据文件。在2.3节中我们会介绍使用Python读取非结构化的数据的方法。
2.使用Numpy的loadtxt、load、fromfile读取数据
Numpy读取数据的方法包括loadtxt、load和fromfile 3种,概要描述如表2-3所示。
表2-3 Numpy读取文件的方法
(1)使用loadtxt方法读取数据文件
Numpy可以读取txt格式的数据文件,数据通常都是一维或二维的。
语法:
loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None,converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
参数如下。
❑ fname:文件或字符串,必填,这里指定要读取的文件名称或字符串,支持压缩的数据文件,包括gz和bz格式。
❑ dtype:数据类型,选填,默认为float(64位双精度浮点数)。Numpy常用类型如表2-4所示。
表2-4 Numpy数据类型
❑ comments:字符串或字符串组成的列表,是表示注释字符集开始的标志,选填,默认为#。
❑ delimiter:字符串,用来分隔多个列的分隔符,例如逗号、TAB符,选填,默认值为空格。
❑ converters:字典,用来将特定列的数据转换为字典中对应的函数的浮点型数据,例如将空值转换为0,选填,默认为空。
❑ skiprows:跳过特定行数据,用来跳过特定前N条记录,例如跳过前1行(可能是标题或注释),选填,默认为0。
❑ usecols:元组,用来指定要读取数据的列,第1列为0,以此类推,例如(1,3,5),选填,默认为空。
❑ unpack:布尔型,用来指定是否转置数组,如果为真则转置,选填,默认为False。
❑ ndmin:整数型,用来指定返回的数组至少包含特定维度的数组,值域为0/1/2,选填,默认为0。
返回:
从文件中读取的数组。
示例:
在“附件-chapter2”文件夹中有一个名为numpy_data.txt的数据文件,数据为3行5列的矩阵,数据内容如图2-3所示。该示例通过loadtxt方法读取其中的数据。
图2-3 示例numpy数据源文件内容
import numpy as np # 导入Numpy库 file_name = 'numpy_data.txt' # 定义数据文件 data = np.loadtxt(file_name, dtype='float32', delimiter=' ') # 获取数据 print(data) # 打印数据
上述代码输出的结果如下:
[[ 0. 1. 2. 3. 4.] [ 5. 6. 7. 8. 9.] [ 10. 11. 12. 13. 14.]]
(2)使用load方法读取数据文件
使用Numpy的load方法可以读取Numpy专用的二进制数据文件,从npy、npz或pickled文件加载数组或pickled对象,该文件通常基于Numpy的save或savez等方法产生。
语法:
load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, encoding='ASCII')
参数如下。
❑ file:类文件对象或字符串格式,要读取的文件或字符串,必填。类文件对象需要支持seek()和read()方法。
❑ mmap_mode:内存映射模式,值域为:None、'r+'、'r'、'w+'、'c',选填。
❑ allow_pickle:布尔型,决定是否允许加载存储在npy文件中的pickled对象数组,选填,默认值为True。
❑ fix_imports:布尔型,如果为True, pickle将尝试将旧的Python 2名称映射到Python 3中并使用的新名称,仅在Python 2生成的pickled文件加载Python 3时才有用,选填,默认值为True。
❑ encoding:字符串,决定读取Python 2字符串时使用何种编码,仅对Python 3读取Python 2产生的pickled文件时有用,选填。
返回:
从数据文件中读取的数组、元组、字典等。
示例:
我们将在这个示例中先定义一份数据,然后保存为.npy格式的数据文件(该文件也在“附件-chapter2”中,名为load_data.npy),接着使用Numpy的load方法读取并打印输出。代码如下:
import numpy as np # 导入Numpy库 write_data = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])# 定义要存储的数据 np.save('load_data', write_data) # 保存为npy数据文件 read_data = np.load('load_data.npy') #读取npy文件 print(read_data) # 输出读取的数据
上述代码输出的结果如下:
[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]]
(3)使用fromfile方法读取数据文件
使用Numpy的fromfile方法可以读取简单的文本文件数据以及二进制数据。通常情况下,该方法读取的数据来源于Numpy的tofile方法,即通过Numpy的tofile方法将特定数据保存为文件(默认为二进制数据文件,无论文件扩展名如何定义),然后通过fromfile方法读取该二进制文件。
语法:
fromfile(file, dtype=float, count=-1, sep='')
参数如下。
❑ file:文件或字符串。
❑ dtype:数据类型,具体参照表2-3。注意数据类型要与文件存储的类型一致。
❑ count:整数型,读取数据的数量,-1意味着读取所有数据。
❑ sep:字符串,如果file是一个文本文件,那么该值就是数据间的分隔符。如果为空("")则意味着file是一个二进制文件,多个空格将按照一个空格处理。
返回:
从文件中读取的数据。
示例:
我们仍然以“附件-chapter2”文件夹中numpy_data.txt数据文件为例,首先通过tofile方法创建1个二进制文件,然后对该文件进行读取。
import numpy as np # 导入Numpy库 file_name = 'numpy_data.txt' # 定义数据文件 data = np.loadtxt(file_name, dtype='float32', delimiter=' ') #获取数据 tofile_name = 'binary' # 定义导出二进制文件名 data.tofile(tofile_name) # 导出二进制文件 fromfile_data = np.fromfile(tofile_name, dtype='float32') # 读取二进制文件 print(fromfile_data) # 打印数据
上述代码输出的结果如下:
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.]
注意
请务必确保读入文件跟存储文件时的数据类型一致,否则将导致数据错误。有兴趣的读者可以在使用fromfile导入数据时,不指定float32格式,看一下输出结果。另外,由于使用tofile方法保存的数据会丢失数据形状信息,因此导入时无法重现原始数据矩阵。
3.使用Pandas的read_csv、read_fwf、read_table读取数据
相对于Python默认函数以及Numpy读取文件的方法,Pandas读取数据的方法更加丰富。Pandas读取文本文件数据的常用方法如表2-5所示。
表2-5 Pandas读取数据的常用方法
(1)使用read_cvs方法读取数据
通过read_csv方法可以读取csv格式的数据文件。
语法:
read_csv(filepath_or_buffer, sep=', ', delimiter=None, header='infer', names=None,index_col=None, usecols=None, **kwds)
参数(read_csv的参数众多,仅介绍最常用的几个如下。
❑ filepath_or_buffer:字符串,要读取的文件对象,必填。
❑ sep:字符串,分隔符号,选填,默认值为英文逗号’, '。特殊情况下,如果数据分隔符号含有多个,例如多列之间通过“|+|”(3个符号)分隔的,那么分隔符sep的值可以设置为“\|\+\|”,这是Python正则表达式语法。
❑ names:类数组,列名,选填,默认值为空。
❑ engine:解析引擎,默认情况下设置为“python”,这样设置的好处是功能更全面;而如果设置为“c”则解析速度更快,在大文件解析时更好用。但是,并不是所有情况下都可以设置为“c”,例如在上面的sep解析规则中,如果设置为“\|\+\|”则无法指定解析引擎为“c”。
❑ skiprows:类字典或整数型,要跳过的行或行数,选填,默认为空。
❑ nrows:整数型,要读取的前记录总数,选填,默认为空,常用来在大型数据集下做初步探索之用。
❑ na_values:NA值的表现字符串,系统中已经默认支持将空格(‘-')、#N/A、#N/A N/A、#NA、-1.#IND、-1.#QNAND、1.#QNAN、N/A、NA、NULL、NaN、nan识别为NA值,如果数据中有其他NA值的表现形式,可以在这里指定。例如,设置na_values=[' ', 'None'],将字符串空格和None识别为NA值。
提示
当数据中含有较多的不规则的缺失值时,设置该字段可以有效识别缺失值字段,这对于后期的缺失值判断、填充、放弃等策略执行至关重要。
❑ thousands:字符串,千位符符号,选填,默认为空。
❑ decimal:字符串,小数点符号,选填,默认为点(.),在特定情况下应用。例如,欧洲的千位符和小数点与中国地区相反,欧洲的“4.321,1”对应中国的“4,321.1”。
❑ encoding:文件编码,默认情况下是“utf-8”,但需要注意的是,从原始数据库中导出的数据可能有各种编码,例如gb2312、latin1等,因此这里要设置为与原始数据一致的编码格式。
提示
在查看文件格式时,可直接使用Notepad(M级左右推荐)或UltraEdit(G级左右推荐)打开文件,在文件的右下角有当前文件的编码格式。当然,如果读者希望统一使用utf-8这一种编码,那么只要将文件另存为utf-8格式即可。
返回:
DataFrame或TextParser
示例:
我们以“附件-chapter2”文件夹中的csv_data.csv数据文件为例,直接读取文件并打印输出。数据内容如图2-4所示。
图2-4 数据文件内容
import pandas as pd # 导入Pandas库 csv_data = pd.read_csv('csv_data.csv', names=['col1', 'col2', 'col3', 'col4','col5']) # 读取csv数据 print(csv_data) # 打印输出数据
上述代码输出的结果如下:
col1 col2 col3 col4 col5 0 0 1 2 3 4 1 5 6 7 8 9 2 10 11 12 13 14
(2)使用read_fwf方法读取数据
通过read_fwf方法可以读取表格或固定宽度格式的文本行到数据框。
语法:
read_fwf(filepath_or_buffer, colspecs='infer', widths=None, **kwds)
read_fwf与read_csv一样都具有非常多的参数(只是在语法中前者通过**kwds省略了,查询完整语法请使用help(pd.read_fwf)),并且大多数参数的用法相同。除了read_csv中的常用参数外,以下介绍一个read_fwf特有且常用的参数。
❑ widths:由整数组成的列表,选填,如果间隔是连续的,可以使用字段宽度列表而不是“colspecs”。
返回:
DataFrame或TextParser。
示例:
我们以“附件-chapter2”文件夹中的fwf_data数据文件为例,直接读取文件并打印输出。数据内容如图2-5所示。
图2-5 数据文件内容
import pandas as pd # 导入Pandas库 fwf_data = pd.read_fwf('fwf_data', widths=[5, 5, 5, 5], names=['col1', 'col2', 'col3', 'col4']) # 读取csv数据 print(fwf_data) # 打印输出数据
上述代码输出的结果如下:
col1 col2 col3 col4 0 a2331 a9013 a3211 a9981 1 b4432 b3199 b9766 b2212 2 c3294 c1099 c7631 c4302
(3)使用read_table方法读取数据
通过read_table方法可以读取通用分隔符分隔的数据文件到数据框。
语法:
read_table(filepath_or_buffer, sep='\t', delimiter=None, header='infer',names=None, index_col=None, usecols=None, **kwds)
对于read_table而言,参数与read_csv完全相同。其实read_csv本来就是read_table中分隔符是逗号的一个特例,表现在语法中是read_csv的sep=', '(默认)。因此,具体参数请查阅read_csv的参数部分。
返回:
DataFrame或TextParser。
我们以“附件-chapter2”文件夹中的table_data.txt数据文件为例,直接读取文件并打印输出。数据内容如图2-6所示。
图2-6 数据文件内容
import pandas as pd # 导入Pandas库 table_data = pd.read_table('table_data.txt', sep='; ', names=['col1', 'col2', 'col3','col4', 'col5']) # 读取csv数据 print(table_data) # 打印输出数据
上述代码输出的结果如下:
col1 col2 col3 col4 col5 0 0 1 2 3 4 1 5 6 7 8 9 2 10 11 12 13 14
数据分隔(或分列)常用思路分为两种:一种是基于固定宽度,一种是基于分隔符号。在表2-5所示的3种方法中,常用的是第2种和第3种,即read_fwf和read_table方法。
除了上述用于读取文本文件的方法外,Pandas还提供了非常丰富的用于其他场景的数据读取方法,限于篇幅,在此不做更多介绍,仅提供读取方法列表供有兴趣的读者参考,以及做知识延伸。具体如表2-6所示。
表2-6 Pandas其他数据读取方法
4.如何选择最佳读取数据的方法
关于“最佳”方法其实没有固定定义,因此所谓的最佳方法往往与以下具体因素有关。
❑ 数据源情况:数据源中不同的字段类型首先会制约读取方法的选择,文本、数值、二进制数据都有各自的适应方法约束。
❑ 数据处理目标:读取数据往往是第1步,后续会涉及数据探索、预处理、统计分析等复杂过程,这些复杂过程需要用到哪些方法在一定程度上都会受数据源的读取影响,影响最多的包括格式转换、类型转换、异常值处理、分类汇总等。
❑ 模型数据要求:不同的模型对于数据格式的要求是不同的,应用到实际中不同的工具对于数据的表示方法也有所差异。
❑“手感”最好的方法:很多时候,最佳方法往往是对哪个或哪些方法最熟悉,这些所谓的“手感”最好的方法便是最佳方法。
当然,即使使用了不是“最佳”的数据读取方法也不必过于担心,因为Python强大的功能提供了众多可以相互进行转换的方法。从Python存储数据的基本对象类型来看,无非是字符串、列表、字典、元组、数组、矩阵等(当然,不同的库对于这些对象的定义名称可能有所不同,但基本含义相同),不同对象的类型转换都非常容易。但本着少走弯路的原则,在这里笔者还是针对不同的场景提供了较为适合的数据读取方法。
❑ 对于纯文本格式或非格式化、非结构化的数据,通常用于自然语言处理、非结构化文本解析、应用正则表达式等后续应用场景下,Python默认的3种方法更为适合。
❑ 对于结构化的、纯数值型的数据,并且主要用于矩阵计算、数据建模的,使用Numpy的loadtxt方法更为方便,例如本书中使用的sklearn本身就依赖于Numpy。
❑ 对于二进制的数据处理,使用Numpy的load和fromfile方法更为合适。
❑ 对于结构化的、探索性的数据统计和分析场景,使用Pandas方法进行读取效果更佳,因为其提供了类似于R的数据框,可以实现“仿SQL”式的操作方式,对数据进行任意翻转、切片(块等)、关联等都非常方便。
❑ 对于结构化的、数值型和文本型组合的数据统计分析场景,使用Pandas更为合适,因为每个数据框中几乎可以装载并处理任意格式的数据。
2.2.2 从Excel获取运营数据
现有的Excel分为两种格式:xls(Excel 97-2003)和xlsx(Excel 2007及以上)。
Python处理Excel文件主要是第三方模块库xlrd、xlwt、pyexcel-xls、xluntils和pyExcel-erator等,此外Pandas中也带有可以读取Excel文件的模块(read_excel)。
基于扩展知识的目的,我们使用xlrd模块读取Excel数据。
首先安装该库,本书推荐的Anaconda中已经默认安装了xlrd和xlwt模块,用于Excel的读写操作。如果读者系统环境中没有,可以在Jupyter输入命令!pip install xlrd安装。
然后我们以“附件-chapter2”文件夹中的demo.xlsx数据文件为例,介绍该库的具体应用。数据概览如图2-7所示。
图2-7 数据文件内容
import xlrd # 导入库 # 打开文件 xlsx = xlrd.open_workbook('demo.xlsx') # 查看所有sheet列表 print('All sheets: %s' % xlsx.sheet_names())
上述代码中,我们先读取一个Excel文件,输出文件的sheet名称列表。由于里面只有一张sheet,一次只有一个值。结果为:All sheets: ['Sheet1']。
查看sheet1的数据概况:
sheet1 = xlsx.sheets()[0] # 获得第1张sheet,索引从0开始 sheet1_name = sheet1.name # 获得名称 sheet1_cols = sheet1.ncols # 获得列数 sheet1_nrows = sheet1.nrows # 获得行数 print('Sheet1 Name: %s\nSheet1 cols: %s\nSheet1 rows: %s' % (sheet1_name, sheet1_cols, sheet1_nrows))
我们分别获取了第1张sheet(虽然里面只有一张,但在多sheet情况下可通过索引循环输出)的名称、列数量和行数据。结果如下:
Sheet1 Name: sheet1 Sheet1 cols: 4 Sheet1 rows: 10
查看sheet1的特定切片数据:
sheet1_nrows4 = sheet1.row_values(4) # 获得第4行数据 sheet1_cols2 = sheet1.col_values(2) # 获得第2列数据 cell23 = sheet1.row(2)[3].value # 查看第3行第4列数据 print('Row 4: %s\nCol 2: %s\nCell 1: %s\n' % (sheet1_nrows4, sheet1_cols2, cell23))
通过查看特定行、列或行列组合的索引来输出,结果如下:
Row 4: ['431381197408191515', ’有效’, 42725.0, ’深圳市’] Col 2: ['Create_Time', 42725.0, 42725.0, 42725.0, 42725.0, 42725.0, 42725.0,42725.0, 42725.0, 42725.0] Cell 1: 深圳市
查看sheet1的数据明细:
for i in range(sheet1_nrows): # 逐行打印sheet1数据print(sheet1.row_values(i))
逐条输出结果,部分结果如下(为了节约篇幅,中间的数据内容以…代替):
['ID_number', 'Status', 'Create_Time', 'Business_City'] ['431381198109106573', ’有效’, 42725.0, ’深圳市’] ['431381198809122734', ’有效’, 42725.0, ’深圳市’] … ['431381198901176911', ’有效’, 42725.0, ’深圳市’] ['43138119870827275X', ’有效’, 42725.0, ’深圳市’]
上述操作只是将数据从Excel中读取出来,将读取的数据转换为数组便可以进行矩阵计算。由于矩阵计算大多是基于数值型数据实现的,因此上述数据将无法适用于大多数科学计算场景,这点需要注意。
总结:在企业实际场景中,由于Excel本身的限制和适用,其无法存储和计算过大(例如千万级的数据记录)的数据量,并且Excel本身也不是为了海量数据的应用而产生的,因此,Excel可以作为日常基本数据处理、补充数据来源或者汇总级别的数据进行读取,同时也可以作为数据结果展示的载体,这种应用下对于大量数值表格的应用效果非常好。
2.2.3 从关系型数据库MySQL读取运营数据
在1.2.4节中我们介绍了安装MySQL和Navicat的方法和关键步骤。这里我们介绍如何利用Python从MySQL中读取数据。
在“附件-chapter2”文件夹中有一个名为order.xlsx的数据文件,我们先把文件导入MySQL数据库,然后再基于数据库进行相关操作。
第一步,新建一个数据库用于存放要导入的目标数据。
1)打开Navicat,左侧导航栏中有我们已经建立好的数据库链接,在第1章中我们已经建立好了本地连接,名为“local”。
2)双击该数据库连接,会展示出所有当前连接(对应的用户权限)下可用的数据库,如图2-8所示。
图2-8 local数据库
3)为了保持不同数据的独立性,我们新建一个数据库,单独存放特定主题的数据。在“local”名称上右击,在弹出的菜单中选择,然后设置各项并单击“确定”按钮,如图2-9所示。完成之后在左侧的“local”链接下会新增一个刚才新建的数据库“python_data”。
图2-9 新建数据库设置
第二步,将Excel数据导入数据库。
双击刚才新建的名为“python_data”的数据库名称,激活数据库连接。此时右侧功能栏中的部分功能已经可用。单击“导入向导”,开始导出Excel数据,如图2-10所示。
图2-10 创建导入向导
1)选择数据文件格式为Excel 2007文件。
2)选择数据源文件,如图2-11所示。
图2-11 设置导入数据源
3)定义附加选项。由于数据文件中第1行是表头,因此数据从第2行开始。日期分隔符与数据文件一致,需要设置为“-”,其他都为默认值,如图2-12所示。
图2-12 导入附加选项
4)设置目标数据表名。源表为“Sheet1”,目标表为“order”。
5)设置字段类型、长度、约束等信息。其中主要的设置是将order_data类型设置为date(日期型),长度为0(不做限制); order_tme类型设置为time(时间型),长度为0(不做限制);total_amount类型设置为float(浮点型),长度默认为255,如图2-13所示。
图2-13 设置字段类型等信息
提示
实际上,我们的数据很可能用不了那么多的“存储空间”,因此在设置时存在数据空间冗余。不过没关系,这里我们仅仅做入门引导之用。真正涉及数据库表的模型设计有很多学问,这里的设置不会影响我们做数据统计分析之用。
6)设置导入模式。由于我们是新创建表,因此设置为:“添加记录到目标表”。
7)启动导入任务。单击“开始”按钮即可。
等待系统导入数据。导入成功后,会在窗口中显示一些信息,最终的信息中包含“success-fully”,如图2-14所示。单击“关闭”按钮即可。
图2-14 导入成功提示信息
至此我们已经成功导入数据,在数据库python_data下新增了一个名为“order”的数据表。我们要初步验证导入的数据是否与原始数据一致。
双击打开该表。打开表之后,会弹出信息,提示该表没有主键。但这并不影响我们使用该表,单击“确定”按钮即可,如图2-15所示。
图2-15 提示表没有主键
提示
在创建表时,我们完全可以指定主键,例如本案例中的order_id是唯一的,那么可指定该字段作为主键,更可以创建一个自增长ID作为主键。本节的主要内容是介绍如何导入外部数据到数据库,有关数据库建表还有很多话题,在此不做更多介绍。
打开order表之后,会显示表预览内容,如图2-16所示。
图2-16 数据表预览
提示
一般情况下,MySQL以及数据都是存储在C盘的。当不断写入大数据量时可能导致C盘的空间急剧减少。由于很多应用程序(也包括MySQL)会在C盘占用很多临时空间,因此当C盘突然变小时,可能导致程序无法正常运行。此时可以检查是否是MySQL不断写库而导致的。
在当前窗口,单击“文件-查询表”或直接使用快捷键Ctrl+Q,打开SQL窗口,然后输入SELECT * FROM 'order' LIMIT 5;点击“运行”或使用快捷键Ctrl+R,返回前5条结果,如图2-17所示。读者可以在此输入其他SQL,或直接浏览数据表来核对数据导入是否准确。
图2-17 运行SQL并返回结果
注意
由于表名order是数据库中的排序关键字,因此在查询表时需要写为“order”,否则会报错。
导入Excel数据主要核对的信息点如下。
❑ 数据记录数是否一致:使用SELECT COUNT(*) FROM 'order';或在导入成功提示窗口也可以看到)。
❑ 数据字段数量是否一致,导入表中的字段不能多也不能少。
❑ 查看数据内容是否一致,尤其是日期、时间等非字符串字段的数据,很多时候时间型的数据转换会出现0000-00-00,这通常是导入设置的日期分隔符问题。
❑ 数据精准度是否一致,尤其是当原始数据是浮点型,要注意对应到数据库字段是否还是浮点型(注意小数位数),问题通常出现在字段类型和位数设置上。
❑ 注意字段的最大长度,不同的数值型数据长度位数是不同,例如整数型tinyint、int,浮点型的单精度和双精度浮点等,这对于汇总级别的数据会产生极大影响(因为某些字段的汇总数据可能非常大)。
通过Python连接MySQL需要有Python库来建立连接,本节使用MySQL官方驱动连接程序,更多信息可在1.2.3节中找到。
以下是Python读取数据库数据的基本方法:
import pymysql # 导入库 config = {'host': '127.0.0.1', # 默认127.0.0.1 'user': 'root', # 用户名 'password': '123456', # 密码 'port': 3306, # 端口,默认为3306 'database': 'python_data', # 数据库名称 'charset': 'utf8' # 字符编码 } cnn = pymysql.connect(**config) # 建立MySQL连接 cursor = cnn.cursor() # 获得游标 sql = "SELECT * FROM 'order'" # SQL语句 cursor.execute(sql) # 执行SQL语句 data = cursor.fetchall() # 通过fetchall方法获得数据 for i in data[:2]: # 打印输出前2条数据 print(i) cursor.close() # 关闭游标 cnn.close() # 关闭连接
上述代码中,实现了通过Python连接MySQL查询所有的数据,并输出前2条数据的功能。执行结果如下:
('3897894579', datetime.date(2010, 3, 11), datetime.timedelta(0), 'PENDING_ORDER_CONFIRM', '1038166', 59.0) ('3897983041', datetime.date(2010, 3, 11), datetime.timedelta(0), 'REMOVED','1041656', 19.9)
在应用MySQL中,除了查询所有数据外,更多时候我们还会应用更多SQL技巧来帮助我们快速找到目标数据并做初步处理。以下是常用SQL语法。
1)只查询前N条数据而非全部数据行记录。
示例:只查询前100条数据记录。
SELECT * FROM 'order' LIMIT 100;
LIMIT为限制的数据记录数方法,语法为limit m, n,意思是从第m到m+n条数据。m可省略,默认值从0开始,如上述示例中是从0开始,取100条数据。例如,要从第11条开始取,取10条可以写为SELECT * FROM 'order' LIMIT 11, 10;。
2)只查询特定列(而非全部列)数据。
示例:只查询total_amount和order_id两列数据。
SELECT total_amount, order_id from 'order';
选择特定列只需将列名写到表达式中即可,多个列名用英文逗号分隔。另外,还可以使用“表名.字段名”的写法,例如上述表达式可以写成SELECT order.total_amount, order.order_id from 'order';,这种写法会出现在表达式中有多个表的情况下,例如多表关联查询。
3)查询特定列去重后的数据。
示例:查询针对user_id去重后的数据。
SELECT DISTINCT user_id FROM 'order';
关键词DISTINCT用于返回唯一不同的值,后面接字段名即要去重的字段。如果后面接多个字段会默认对多个字段同时进行比较,只有多个字段完全相同时才会去重。DISTINCT常用来返回去重后的特定ID,或者与COUNT配合使用,查询特定数据记录的唯一数量。
4)查询带有1个条件的数据。
示例:查询total_amount<100的所有数据。
SELECT * FROM 'order' WHERE total_amount < 100;
WHERE是条件关键字,后面接具体条件。本示例中,由于total_amount为浮点型,因此可直接与数值型比较;如果是字符串型,则比较值需要加引号用来表示一致的字段类型。
5)查询带有多个条件(同时满足)的数据。
示例:查询total_amount<100且status为REMOVED的所有数据。
SELECT * FROM 'order' WHERE total_amount < 100 and 'status' = 'REMOVED';
多个条件使用and表示且的关系,多个条件必须同时满足。MySQL中字段不区分大小写。由于status也是关键字,因此也需要使用’status'。
6)查询带有多个条件(满足任意一个)的数据。
示例:查询total_amount<100或status为REMOVED的所有数据。
SELECT * FROM 'order' WHERE total_amount < 100 or 'status' = 'REMOVED';
多个条件使用or表示或的关系,多个条件满足任意一个条件即可。
7)查询特定条件值在某个值域范围内的数据。
示例:查询status的值为REMOVED或NO_PENDING_ACTION或PENDING_ORDER_CONFIRM。
SELECT * FROM 'order' WHERE 'status' in ('REMOVED', 'NO_PENDING_ACTION', 'PENDING_ORDER_CONFIRM');
对于特定字段采用穷举法列出值域的方法,也可以使用or方法连接多个条件,但使用列表的穷举法会使得表达式更简单。
8)使用正则表达式查询具有复杂条件的数据。
示例:查询user_id以“103”开头且order_id包含“04”的所有订单数据。
SELECT * FROM 'order' WHERE user_id LIKE '103%' and order_id LIKE '%04%';
正则表达式通常用在复杂条件中,通过使用关键字LIKE来连接不同的正则语法,LIKE后面接具体的匹配模式。常用的匹配模式如下。
❑ 以特定字符开头:’字符串%',例如’ABD%’表示以ABD开头的所有匹配。
❑ 以特定字符结尾:'%字符串’,例如’% ABD’表示以ABD结尾的所有匹配。
❑ 包含特定字符:'%字符串%',例如’%ABD%’表示包含ABD的所有匹配。
正则表达式还有更多强大的语法规则,限于篇幅不再展开介绍。
9)将查询到的数据倒序排列。
示例:将total_amount金额在10~100之间的所有数据,按照订单ID倒序排序。
SELECT * FROM 'order' WHERE 10 < total_amount < 100 ORDER BY order_id DESC;
在查询表达式ORDER BY的结尾,通过使用DESC来表示倒序(逆序)排序;省略是默认使用ASC正序(顺序)排序。
10)查询指定列中不包含空值的所有数据。
示例:查询order_id不为空的所有数据。
SELECT * FROM 'order' WHERE order_id IS NOT NULL;
在MySQL中,IS NULL表示为空,IS NOT NULL表示非空。需要注意的是,NULL不代表空字符串或者空格,而是真正意义上的没有任何数据,类似于Python中的None。
上述案例只是展示了如何取数,更多情况下,我们会配合特定函数和方法做数据计算、整合和探索性分析。例如:
❑ 使用MySQL聚合函数求算术平均值、计数、求最大/最小值、做分类汇总等。
❑ 使用MySQL数学函数,用来求绝对值,进行对数计算、求平方根等。
❑ 使用MySQL字符串函数进行字符串分割、组合、截取、匹配、处理等。
❑ 使用MySQL的日期函数进行日期获取、转换、处理等。
❑ 使用MySQL将多个表(2个或2个以上)数据进行关联、匹配和整合。
在Python工作者看来,Python本身能胜任MySQL的很多工作,为什么还要耗费时间和精力学习如何在MySQL中完成这些数据工作呢?直接用Python读取数据然后基于Python的相关库进行数据运算岂不更好?
Python的工作强项并不是数据计算,而是其灵活、高效、简易和集成多方的工作方式、效率和效果。MySQL(以及其他关系型数据库)作为成熟的数据存储和集成解决方案,在(关系型)数据本身方面更具优势,尤其是对于数据结构定义(实体、属性、关系)、关系操作(选择、连接、聚合等)、关系完整性约束(主外键、唯一性等)等方面具有成熟且稳定的应用价值,这对于数据处理至关重要。因此,可以说MySQL在结构化数据存储和初步处理工作上比Python更专业。
还有一个更加关键的原因是,如果所有数据工作都由Python完成,那么Python的事务处理在某些情况下一定会面临资源瓶颈、工作效率等问题,届时可能会导致程序崩溃和报错,这将大大降低程序的可靠性以及结果输出的效率,对于海量数据工作更是如此。
因此,很多时候不是Python不能做,而是在合适的时机选择最合适的工具来完成才是最好的选择。
2.2.4 从非关系型数据库MongoDB读取运营数据
由于MongoDB一般都是企业级数据存储,因此这里我们使用在第1章已经安装过的SSH远程客户端SecureCRT。如果读者有自己在虚拟机或本地安装MongoDB,也可以使用,操作方法类似。
双击SecureCRT打开程序,单击顶部的快速连接按钮,新建连接,如图2-18所示。
图2-18 新建快速连接
然后根据服务器具体配置情况,配置如图2-19所示信息。其中主机名和用户名需要单独配置,其他则应根据实际情况询问IT或运维管理人员(本案例中都是默认值)。可勾选用于以后启动该程序时直接显示快捷入口。
图2-19 填写连接配置信息
单击“连接”按钮之后,会弹出密码输入窗口,输入密码,可勾选用于以后无须重复输入密码,具体视公司安全规定执行,如图2-20所示。
图2-20 输入密码
如果服务器配置信息填写正确,连接服务器成功会显示如图2-21所示信息。
图2-21 成功连接服务器
要想通过Python调用MongoDB,需要先安装PyMongoDB,本书使用的Anaconda默认没有安装该库,可在Jupyter中直接使用!pip install pymongo安装。
注意
不同的服务器环境对于可访问外网的限制有差异,有的服务器可以访问外网,而有的服务器却不能。我们在第1章中的大多数安装方法,默认都是通过pip请求外部网络资源实现的,对于无法直接从服务器连接外网的,请参照1.2.3节中的方法,先将安装包和依赖包下载到本机,然后拷贝到服务器上,再通过setup(从源码安装)或pip(从whl文件安装)命令安装。
相关知识点:如何区分第三方库是通过pip还是conda命令安装的
在第1章笔者曾经提到,在安装第三方库时习惯于使用pip install安装,而查看现有库信息列表时习惯于使用conda list。在使用conda list查看所有库列表信息时,除了库名、版本外还有一列安装源信息。通过该列可以看出其中带有pip字样的是通过pip命名安装的,而py*字样的是Anaconda默认安装的,如图2-22所示。
图2-22 不同方式安装第三方库信息差异
注意
通过setup命令从源码安装的库,使用conda list命令是无法看到的。但通过pip3 list命令却可以看到。例如笔者通过setup安装的prettytable (0.7.2)库只能通过pip3 list看到,而conda list命令则不展示该信息。
使用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-23所示信息。
图2-23 MongoDB服务启动后的浏览器提示信息
提示
MongoDB也提供了Windows版本的程序,有兴趣的读者,可登录https://www.mon-godb.com/download-center#community下载程序并进行本地部署安装。
要在服务器上进入Python环境,直接在终端窗口输入命令python。在Python命令行窗口中,通过如下方法调用MongoDB数据。
from pymongo import MongoClient # 导入库 client = MongoClient('10.0.0.54', 27017) # 输出实际的服务器IP地址以及端口,建立连接,并初始化环境变量 db = client.python_data # 选择python_data库 orders = db.ordersets # 选择orders集合 terms = [{"user": "tony", "id": "31020", "age": "30", "products": ["215120", "245101", "128410"], "date": "2017-04-06"}, {"user": "lucy", "id": "32210", "age": "29", "products": ["541001", "340740", "450111"], "date": "2017-04-06"}] # 定义一条数据集合用于插入 orders.insert_many(terms) # 插入数据 print(orders.find_one()) # 获取一条文档数据
在上述代码中,我们连接到MongoDB后选择了test_py库下的ordersets集合,然后插入2条数据到集合中,打印其中一条数据如下:
{'_id': ObjectId('5bf51b668b0b3f20dcc04638'), 'user': 'tony', 'id': '31020', 'age':'30', 'products': ['215120', '245101', '128410'], 'date': '2017-04-06'}
再输出所有集合数据。
for i in orders.find(): # 获取所有文档数据并展示 print(i)
以下是代码执行后打印输出的结果:
{'age': '30', 'products': ['215120', '245101', '128410'], 'user': 'tony', 'date':'2017-04-06', '_id': ObjectId('58eb1f0b2f76bf26108b4898'), 'id': '31020'} {'age': '29', 'products': ['541001', '340740', '450111'], 'user': 'lucy', 'date':'2017-04-06', '_id': ObjectId('58eb1f0b2f76bf26108b4899'), 'id': '32210'}
除了上述基本查询语句外,PyMongo也提供了类似于MySQL的条件过滤语句。
1)查询特定文档数据。
示例:只查询第2条数据。
orders.find()[1] # 查询特定索引的数据记录
通过增加索引值可以指定查询特定索引的文档数据。注意索引值从0开始,0代表第1条是数据。
2)查询特定范围内的文档数据。
示例:只查询第1~2条数据。
orders.find()[0:2] # 查询特定范围内的数据记录
通过增加索引值可以指定查询特定索引范围的文档数据(切片)。注意,索引值为空则默认从0开始,0代表第1条是数据。上述表达式可以写成orders.find()[:2]。索引结束值默认不包含,例如,上述语法中的0:2的实际索引只有0和1。
3)增加查询条件。
示例:只查询user为lucy的文档数据。
orders.find({"user": "lucy"}) # 所有数据,注意使用迭代方法查看数据 orders.find_one({"user": "lucy"})# 单条数据
作为Key-Value形式的代表应用之一,MongoDB几乎所有的用法都以Key-Vaule的形式存在。过滤条件也不例外,只需在find函数中,以Key-Value的形式设置过滤条件即可,其中Key为过滤维度,Value为对应值。
4)排序。
示例:针对user排序并输出。
orders.find({"user": "lucy"}).sort("user") # 所有数据,注意使用迭代方法查看数据
通过使用Sort方法设置排序维度。默认是正序,也可以指定为倒序排列,同时也可以指定多个字段排序规则,例如collection.find().sort([ ('field1', pymongo. ASCENDING), ('field2', pymongo.DESCENDING)])。从MongoDB 2.6开始,还提供了按照文本相关性的排序方法,例如collection.find({'score': {'$meta': 'text-Score'}}).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信息。
1)获得百度账户,没有账户的读者可在https://passport.baidu.com/v2/?reg免费注册获取。
2)注册成为百度开放平台开发者,读者可进入http://lbsyun.baidu.com/apiconsole/key?appl-ication=key完成相关注册。该过程非常简单,遵循引导即可,整个过程在5分钟以内完成,如图2-24所示。
图2-24 提交成功
3)注册完成之后,会有一封名为“百度地图开放平台”的开发者激活邮件发送验证链接到用户指定(注册时邮箱)邮箱,单击链接进行验证。
4)单击“申请秘钥”进入创建应用界面,如图2-25所示。在该应用创建中,我们主要使用Geocoding API v2,其他应用服务根据实际需求勾选,如图2-26所示。如果不做限制,IP白名单区域设置为“0.0.0.0/0”。设置完成后,单击“提交”按钮。
图2-25 完成激活
图2-26 创建应用
5)获得AK秘钥。完成上述步骤之后,会默认跳转到应用列表界面,界面中的“访问应用(AK)”中便是该应用的秘钥,如图2-27所示。
图2-27 获得AK秘钥
1.获取并解析JSON数据
我们先通过Python请求该API来获得JSON格式的数据。本示例的目标是给百度API发送一条地理位置数据,返回其经纬度信息。
本节会用到Python第三方库requests,默认通过Anaconda已经安装。如果读者系统环境中没有该库,可以先通过!pip install requests安装。完整代码如下:
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) # 打印输出
在上述代码中,先导入一个requests库,该库用来发送网络请求,支持多种发送模式,可以用来做网页内容抓取、自动化网页测试、网页内容采集等。
第2行定义了一个地址,该地址通常是运营中的地址类信息,例如:通信地址、注册地址、收货地址、联系地址等。
第3行ak是创建访问应用时获得的AK,注意百度有每天有6000次的限制,读者可填写自行申请的AK。
第4行定义了一个通过get方法发送的URL请求地址,地址中的address和ak的具体值使用占位符代替,在后面用到时具体赋值,这种方法经常用于地址、ak有变化的场景中。例如:我们通常会创建多个应用(基于每个账户有限制,以及分开治理应用的考虑),然后从数据库中读取一系列地址用于解析。此时的地址和AK都需要能动态赋值。
提示
在API请求方法中,最常用的是get和post方法。前者用于向服务器以“明文”(所有参数都在URL中体现)的形式请求数据,常用于普通的页面或服务请求,例如浏览网页、搜索关键字等都是GET方法;后者则以“暗语”(所有的数据信息都在HTTP消息中)以键值对的形式发送,在URL中是看不到具体信息的,常用于数据保密性高的场景,例如登录、注册、订单等表单的处理都是POST方法。
第5行通过get方法发送请求到上面定义的URL中,并具体赋值。
第6行将返回对象的文本信息赋值到add_info,返回对象中还包括非常多的相关属性信息,例如状态码、cookie、reason、headers、编码等,这些信息可用于判断是否正确返回、问题原因、状态等信息。
最后一行打印输出返回的文本信息。
以下是代码执行后打印输出的结果:
{"st atus":0, "result":{"location":{"lng":116.29381532521775, "lat":40.052991139523 19}, "precise":0, "confidence":40, "comprehension":100, "level":"工业园区"}}
返回结果包括以下字段。
❑ status:返回结果状态值,成功则返回0。
❑ location:经纬度坐标,其中lat是纬度值,lng是经度值。
❑ precise:位置的附加信息,决定是否精确查找。1为精确查找,即准确打点;0为不精确查找,即模糊打点。
❑ confidence:可信度,描述打点准确度。
❑ level:百度定义的地址类型。
该结果可以通过JSON进行格式化处理。
import json # 导入库 add_json = json.loads(add_info) # 加载JSON字符串对象 lat_lng = add_json['result']['location'] # 获得经纬度信息 print(lat_lng) # 打印输出
代码中,我们导入Python自带的JSON库。该库支持Python其他对象和JSON对象之间的相互转换。
先将获得的地址信息格式化为JSON字符串(字典类型),然后通过读取字典的Key来获得其Value。由于返回的地址信息中包含字典嵌套,因此这里需要依次读出第1层和第2层信息。读者可通过add_json.items()来更加直观地观察2层嵌套。
上述代码执行后返回结果如下:
{'lng': 116.29381532521775, 'lat': 40.05299113952319}
2.获取并解析XML数据
Geocoding API也提供XML格式的返回数据。下面以获得XML格式的数据为例介绍代码过程。
上述所有代码与JSON格式的代码完全相同,只在第4行定义url时,将output的返回值类型设置为xml。执行后返回结果如下:
<? xml version="1.0" encoding="utf-8"? > <GeocoderSearchResponse> <status>0</status> <result> <location> <lng>116.299337657</lng> <lat>40.0539973025</lat> </location> <precise>0</precise> <confidence>40</confidence> <level>工业园区</level> </result> </GeocoderSearchResponse>
接着我们通过引入一个XML格式化处理库来从中提取经纬度信息。关于XML文件的解析,Python默认和第三方的常用库包括xml、libxml2、lxml、xpath等,我们使用Python自带的XML进行处理。
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) # 格式化打印输出纬度值
上述代码中,前4行实现了一个功能,将代码的字符编码设置为utf-8,否则系统会默认为ASCII,对返回的带有中文字符串无法识别而报错。
代码第5行导入XML自带的ElementTree方法,该方法可以实现对XML内容的查询、新建、修改等操作,是XML中比较简单容易上手的方法(XML除了ElementTree外,还提供了DOM和SAX方法)。
代码第6行获得从API得到的XML对象并获得根节点。
代码第7、第8行分别通过嵌套读取从根节点开始向下的第3层经纬度数据。
代码最后两行格式化打印输出经纬度。
上述代码执行后返回结果如下:
lng: 116.293815325 lat: 40.0529911395
有关百度API的更多信息,具体查阅http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding。
在API应用中,中文的编码处理因细节太多而常常让人头疼。因此,如果可以则应尽量减少直接在API的数据中出现中文字符。在实际企业应用中,会出现多种API形式,但无论哪种形式,其基本实现思路都是一致的:导入库→定义请求变量→发送请求→获得返回数据→格式化并获得目标数据,因此需要掌握JSON和XML的数据与其他数据的转换方法。