如何用 Python 和 API 收集与分析网络数据?

本文以一款阿里云市场历史天气查询产品为例,为你逐步介绍如何用 Python 调用 API 收集、分析与可视化数据。但愿你触类旁通,轻松应对从此的 API 数据收集与分析任务。html

雷同

上周的研究生课,学生分组展现实践环节第二次做业,主题是利用 API 获取、分析与可视化数据。python

你们作的内容,确实五花八门。git

例如这个组,调查对象是动画片《小猪佩奇》(英文名 “Peppa Pig”,又译做《粉红猪小妹》)。这部片子听说最近很火。github

猜猜看,下面这一组调查对象是什么?编程

没错,是《权力的游戏》(Game of Thrones)。一部很好看的美剧。json

主题丰富多彩,作得有声有色。api

做为老师,我在下面,应该很开心吧?浏览器

不,我简直啼笑皆非。bash

14个组中,有一多半都和他们同样,作的是维基百科页面访问量分析。微信

为何会这样呢?

由于我在布置做业的时候,很贴心地给了一个样例,是我以前写的一篇教程《如何用R和API免费获取Web数据?》。

因而,他们就都用 R 语言,来分析维基百科页面访问量了。

这些同窗是否是太懒惰了?

听了他们的讲述,我发觉,其中很多同窗,是很是想作些新东西的。

他们找了国内若干个云市场,去找 API 产品。

其中要价太高的 API ,被他们自动过滤了。

可即适合练手的低价或免费 API ,也很多。

问题是,他们花了很长时间,也没能搞定

考虑到做业展现日程迫近,他们只好按照个人教程,去用 R 分析维基百科了。

因而,多组做业,都雷同。

讲到这里,他们一副很差意思的表情。

我却发觉,这里蕴藏着一个问题。

几乎全部国内云市场的 API 产品,都有丰富的文档。很多还干脆给出了各类编程语言对应调用代码。

既然示例代码都有了,为何你还作不出来呢?

下课后,我让有疑问的同窗留下,我带着他们实际测试了一款 API 产品,尝试找到让他们遭遇困境的缘由。

市场

咱们尝试的,是他们找到的阿里云市场的一款 API 产品,提供天气数据。

它来自于易源数据,连接在这里

这是一款收费 API ,100次调用的价格为1分钱。

做为做业练习,100次调用已经足够了。

这价格,他们表示能够接受。

我本身走了一遍流程。

点击“当即购买”按钮。

你会被引领到付费页面。若是你没有登陆,能够根据提示用淘宝帐号登陆。

支付1分钱之后,你会看到以下的成功提示。

以后,系统会提示给你一些很是重要的信息。

注意上图中标红的字段。

这是你的AppCode,是后面你调用 API 接口获取数据,最为重要的身份认证手段,请点击“复制”按钮把它存储下来。

点击上图中的商品名称连接,回到产品介绍的页面。

这个产品的 API 接口,提供多种数据获取功能。

学生们尝试利用的,是其中“利用id或地名查询历史天气”一项。

请注意这张图里,有几样重要信息:

  • 调用地址:这是咱们访问 API 的基本信息。就好像你要去见朋友,总得知道见面的地址在哪里;
  • 请求方式:本例中的 GET ,是利用 HTTP 协议请求传递数据的主要形式之一;
  • 请求参数:这里你要提供两个信息给 API 接口,一是“地区名称”或者“地区id”(二选一),二是月份数据。需注意格式和可供选择的时间范围。

咱们往下翻页,会看到请求示例。

默认的请求示例,是最简单的 curl 。

若是你的操做系统里面已经安装了 curl (没有安装的话,能够点击这个连接,寻找对应的操做系统版本下载安装),尝试把上图中 curl 开头的那一行代码拷贝下来,复制到文本编辑器里面。

就像这样:

curl -i -k --get --include 'https://ali-weather.showapi.com/weatherhistory?area=%E4%B8%BD%E6%B1%9F&areaid=101291401&month=201601'  -H 'Authorization:APPCODE 你本身的AppCode'
复制代码

而后,必定要把其中的“你本身的AppCode”这个字符串,替换为你真实的 AppCode 。

把替换好的语句复制粘贴到终端窗口里面运行。

运行结果,以下图所示:

看见窗口下方包含中文的数据了吗?

利用 API 获取数据,就是这么简单。

既然终端执行一条命令就能够,那咱们干吗还要编程呢?

好问题!

由于咱们须要的数据,可能不是一次调用就能所有得到。

你须要重复屡次调用 API ,并且还得不断变化参数,积累得到数据。

每次如果都这样手动执行命令,效率就过低了。

API 的提供方,会为用户提供详细的文档与说明,甚至还包括样例。

上图中,除了刚才咱们使用的 curl ,还包括如下语言访问 API 接口的样例说明:

  • Java
  • C#
  • PHP
  • Python
  • Object C

咱们以 Python 做为例子,点开标签页看看。

你只须要把样例代码所有拷贝下来,用文本编辑器保存为“.py”为扩展名的 Python 脚本文件,例如 demo.py 。

再次提醒,别忘了,把其中“你本身的AppCode”这个字符串,替换为你真实的 AppCode,而后保存。

在终端下,执行:

python demo.py
复制代码

若是你用的是 2.7 版本的 Python ,就当即能够正确得到结果了。

为何许多学生作不出来结果呢?

我让他们实际跑了一下,发现确实有的学生粗枝大叶,忘了替换本身的 AppCode 。

可是大部分同窗,因为安装最新版本的 Anaconda (Python 3.6版),都遇到了下面的问题:

你可能会认为这是由于没有正确安装 urllib2 模块,因而执行

pip install urllib2
复制代码

你可能会看到下面的报错提示:

你也许尝试去掉版本号,只安装 urllib,即:

pip install urllib
复制代码

可是结果依然不美妙:

有些 Python 开发者看到这里,可能会嘲笑咱们:Python 3版本里面,urllib 被拆分了啊!地球人都知道,你应该……

请保持一颗同理心。

想一想一个普通用户,凭什么要了解不一样版本 Python 之间的语句差别?凭什么要对这种版本转换的解决方式内心有数?

在他们看来,官方网站提供的样例,就应该是能够运行的。报了错,又不能经过本身的软件包安装“三板斧”来解决,就会慌乱和焦虑。

更进一步,他们也不太了解 JSON 格式。

虽然,JSON已经是一种很是清晰的、人机皆可通读的数据存储方式了。

他们想了解的,是怎么把问题迁移到本身可以解决的范围内。

例如说,可否把 JSON 转换成 Excel 形式的数据框?

若是能够,他们就能够调用熟悉的 Excel 命令,来进行数据筛选、分析与绘图了。

他们还会想,假如 Python 自己,能一站式完成数据读取、整理、分析和可视化全流程,那天然更好。

可是,样例,样例在哪里呢?

在我《Python编程遇问题,文科生怎么办?》一文中,我曾经提到过,这种样例,对于普通用户的重要性。

没有“葫芦”,他们又如何“照葫芦画瓢”呢?

既然这个例子中,官方文档没有提供如此详细的代码和讲解样例,那我就来为你绘制个“葫芦”吧。

下面,我给你逐步展现,如何在 Python 3 下,调用该 API 接口,读取、分析数据,和绘制图形。

环境

首先咱们来看看代码运行环境。

前面提到过,若是样例代码的运行环境,和你本地的运行环境不一,计时代码自己没问题,也没法正常执行

因此,我为你构建一个云端代码运行环境。(若是你对这个代码运行环境的构建过程感兴趣,欢迎阅读个人《如何用iPad运行Python代码?》一文。)

请点击这个连接t.cn/R3us4Ao),直接进入我们的实验环境。

不须要在本地计算机安装任何软件包。只要有一个现代化浏览器(包括Google Chrome, Firefox, Safari和Microsoft Edge等)就能够了。所有的依赖软件,我都已经为你准备好了。

打开连接以后,你会看见这个页面。

这个界面来自 Jupyter Lab。

图中左侧分栏,是工做目录下的所有文件。

右侧打开的,是我们要使用的ipynb文件。

根据个人讲解,请你逐条执行,并仔细观察运行结果。

本例中,咱们主要会用到如下两个新的软件包。

首先是号称“给人用”(for humans)的HTTP工具包requests。

这款工具,不只符合人类的认知与使用习惯,并且对 Python 3 更加友好。做者 Kenneth Reitz 甚至在敦促全部的 Python 2 用户,赶忙转移到 Python 3 版本。

The use of Python 3 is highly preferred over Python 2. Consider upgrading your applications and infrastructure if you find yourself still using Python 2 in production today. If you are using Python 3, congratulations — you are indeed a person of excellent taste. —Kenneth Reitz

咱们将用到的一款绘图工具,叫作 plotnine

它实际上本不是 Python 平台上的绘图工具,而是从 R 平台的 ggplot2 移植过来的。

要知道,此时 Python 平台上,已经有了 matplotlib, seaborn, bokeh, plotly 等一系列优秀的绘图软件包。

那为何还要费时费力地,移植 ggplot2 过来呢?

由于 ggplot2 的做者,是大名鼎鼎的 R 语言大师级人物 Hadley Wickham 

他创造 ggplot2,并不是为 R 提供另外一种绘图工具,而是提供另外一种绘图方式

ggplot2 彻底遵照而且实现了 Leland Wilkinson 提出的“绘图语法”(Grammar of Graphics),图像的绘制,从本来的部件拆分,变成了层级拆分。

这样一来,数据可视化变得史无前例地简单易学,且功能强大。

我会在后文的“代码”部分,用详细的叙述,为你展现如何使用这两个软件包。

我建议你先彻底按照教程跑一遍,运行出结果。

若是一切正常,再将其中的数据,替换为你本身感兴趣的内容

以后,尝试打开一个空白 ipynb 文件,根据教程和文档,本身敲代码,而且尝试作调整。

这样会有助于你理解工做流程和工具使用方法。

下面咱们来看代码。

代码

首先,读入HTTP工具包requests。

import requests
复制代码

第二句里面,有“Your AppCode here”字样,请把它替换为你本身的AppCode,不然下面运行会报错。

appcode = 'Your AppCode here'
复制代码

咱们尝试获取丽江5月份的天气信息。

在API信息页面上,有城市和代码对应的表格。

位置比较隐蔽,在公司简介的上方。

我把这个 Excel 文档的网址放在了这里(http://t.cn/R3T7e39),你能够直接点击下载。

下载该 Excel 文件后打开,根据表格查询,咱们知道“101291401”是丽江的城市代码。

咱们将其写入areaid变量。

日期咱们选择本文写做的月份,即2018年5月。

areaid = "101291401"
month = "201805"
复制代码

下面咱们就设置一下 API 接口调用相关的信息。

根据API信息页面上的提示,咱们的要访问的网址为:https://ali-weather.showapi.com/weatherhistory,须要输入的两个参数,就是刚才已经设置的areaidmonth

另外,咱们须要验证身份,证实本身已经付费了。

点击上图中蓝色的“API 简单身份认证调用方法(APPCODE)”,你会看到如下示例页面。

看来咱们须要在HTTP数据头(header)中,加入 AppCode。

咱们依次把这些信息都写好。

url = 'https://ali-weather.showapi.com/weatherhistory'
payload = {'areaid': areaid, 'month': month}
headers = {'Authorization': 'APPCODE {}'.format(appcode)}
复制代码

下面,咱们就该用 requests 包来工做了。

requests 的语法很是简洁,只须要指定4样内容:

  • 调用方法为“GET”
  • 访问地址 url
  • url中须要附带的参数,即 payload (包含 areaidmonth的取值)
  • HTTP数据头(header)信息,即 AppCode
r = requests.get(url, params=payload, headers=headers)
复制代码

执行后,好像……什么也没有发生啊!

咱们来查看一下:

r
复制代码

Python 告诉咱们:

<Response [200]>
复制代码

返回码“200”的含义为访问成功。

回顾一下,《如何用R和API免费获取Web数据?》一文中,咱们提到过:

以2开头的状态编码是最好的结果,意味着一切顺利;若是状态值的开头是数字4或者5,那就有问题了,你须要排查错误。

既然调用成功,咱们看看 API 接口返回的具体数据内容吧。

调用返回值的 content 属性:

r.content
复制代码

这一屏幕,密密麻麻的。

其中许多字符,甚至都不能正常显示。这可怎么好?

不要紧,从 API 信息页上,咱们得知返回的数据,是 JSON 格式。

那就好办了,咱们调用 Python 自带的 json 包。

import json
复制代码

用 json 包的字符串处理功能(loads)解析返回内容,结果存入 content_json

content_json = json.loads(r.content)
复制代码

看看 content_json 结果:

content_json
复制代码

能够看到,返回的信息很完整。并且刚刚没法正常显示的中文,此时也都显现了庐山真面目。

下一步很关键。

咱们把真正关心的数据提取出来。

咱们不须要返回结果中的错误码等内容。

咱们要的,是包含每一每天气信息的列表。

观察发现,这一部分的数据,存储在 'list' 中,而 'list' ,又存储在 'showapi_res_body' 里面

因此,为选定列表,咱们须要指定其中的路径:

content_json['showapi_res_body']['list']
复制代码

冗余信息都被去掉了,只剩下咱们想要的列表。

可是对着一个列表操做,不够方便与灵活。

咱们但愿将列表转换为数据框。这样分析和可视化就简单多了。

大不了,咱们还能够把数据框直接导出为 Excel 文件,扔到熟悉的 Excel 环境里面,去绘制图形。

读入 Python 数据框工具 pandas 。

import pandas as pd
复制代码

咱们让 Pandas 将刚刚保留下来的列表,转换为数据框,存入 df 。

df = pd.DataFrame(content_json['showapi_res_body']['list'])
复制代码

看看内容:

df
复制代码

此时,数据显示格式很是工整,各项信息一目了然。

写到这里,你基本上搞懂了,如何读取某个城市、某个月份的数据,而且整理到 Pandas 数据框中。

可是,咱们要作分析,显然不能局限在单一月份与单一城市。

每次加入一组数据,若是都得从头这样作一遍,会很辛苦。并且语句多了,执行起来,不免顾此失彼,出现错误。

因此,咱们须要把刚刚的代码语句整合起来,将其模块化,造成函数。

这样,咱们只须要在调用函数的时候,传入不一样的参数,例如不一样的城市名、月份等信息,就能得到想要的结果了。

综合上述语句,咱们定义一个传入城市和月份信息,得到数据框的完整函数。

def get_df(areaid, areaname_dict, month, appcode):

    url = 'https://ali-weather.showapi.com/weatherhistory'
    payload = {'areaid': areaid, 'month': month}
    headers = {'Authorization': 'APPCODE {}'.format(appcode)}

    r = requests.get(url, params=payload, headers=headers)

    content_json = json.loads(r.content)

    df = pd.DataFrame(content_json['showapi_res_body']['list'])
    df['areaname'] = areaname_dict[areaid]

    return df
复制代码

注意除了刚才用到的语句外,咱们为函数增长了一个输入参数,即areaname_dict

它是一个字典,每一项分别包括城市代码,和对应的城市名称。

根据咱们输入的城市代码,函数就能够自动在结果数据框中添加一个列,注明对应的是哪一个城市。

当咱们获取多个城市的数据时,某一行的数听说的是哪一个城市,就能够一目了然。

反之,若是只给你看城市代码,你很快就会眼花缭乱,不知所云了。

可是,只有上面这一个函数,仍是不够高效。

毕竟咱们可能须要查询若干月、若干城市的信息。若是每次都调用上面的函数,也够累的。

因此,咱们下面再编写一个函数,帮咱们自动处理这些脏活儿累活儿。

def get_dfs(areaname_dict, months, appcode):
    dfs = []
    for areaid in areaname_dict:
        dfs_times = []
        for month in months:
            temp_df = get_df(areaid, areaname_dict, month, appcode)
            dfs_times.append(temp_df)
        area_df = pd.concat(dfs_times)
        dfs.append(area_df)
    return dfs
复制代码

说明一下,这个函数接受的输入,包括城市代码-名称字典、一系列的月份,以及咱们的 AppCode。

它的处理方式,很简单,就是个双重循环。

外层循环负责遍历全部要求查询的城市,内层循环遍历所有指定的时间范围。

它返回的内容,是一个列表。

列表中的每一项,都分别是某个城市一段时间(可能包含若干个月)的天气信息数据框。

咱们先用单一城市、单一月份来试试看。

仍是2018年5月的丽江。

areaname_dict = {"101291401":"丽江"}
months = ["201805"]
复制代码

咱们将上述信息,传入 get_dfs 函数。

dfs = get_dfs(areaname_dict, months, appcode)
复制代码

看看结果:

dfs
复制代码

返回的是一个列表。

由于列表里面只有一个城市,因此咱们只让它返回第一项便可。

dfs[0]
复制代码

此次显示的,就是数据框了:

测试经过,下面咱们趁热打铁,把天津、上海、丽江2018年初至今全部数据都读取出来。

先设定城市:

areaname_dict = {"101030100":"天津", "101020100":"上海", "101291401":"丽江"}
复制代码

再设定时间范围:

months = ["201801", "201802", "201803", "201804", "201805"]
复制代码

我们再次执行 get_dfs 函数。

dfs = get_dfs(areaname_dict, months, appcode)
复制代码

看看此次的结果:

dfs
复制代码

结果仍是一个列表。

列表中的每一项,对应某个城市2018年年初到5月份本文写做时,这一段时间范围天气数据。

假设咱们要综合分析几个城市的天气信息,那么就能够把这几个数据框整合在一块儿。

用到的方法,是 Pandas 内置的 concat 函数。

它接收一个数据框列表,把其中每个个数据框沿着纵轴(默认)链接在一块儿。

df = pd.concat(dfs)
复制代码

看看此时的总数据框效果:

df
复制代码

这是开头部分:

这是结尾部分:

3个城市,4个多月的数据都正确读取和整合了。

下面咱们尝试作分析。

首先,咱们得搞清楚数据框中的每一项,都是什么格式:

df.dtypes
复制代码
aqi                object
aqiInfo            object
aqiLevel           object
max_temperature    object
min_temperature    object
time               object
weather            object
wind_direction     object
wind_power         object
areaname           object
dtype: object
复制代码

全部的列,全都是按照 object 处理的。

什么叫 object

在这个语境里,你能够将它理解为字符串类型。

可是,我们不能把它们都当成字符串来处理啊。

例如日期,应该按照日期类型来看待,不然怎么作时间序列可视化?

AQI的取值,若是看做字符串,那怎么比较大小呢?

因此咱们须要转换一下数据类型。

先转换日期列:

df.time = pd.to_datetime(df.time)
复制代码

再转换 AQI 数值列:

df.aqi = pd.to_numeric(df.aqi)
复制代码

看看此时 df 的数据类型:

df.dtypes
复制代码
aqi                         int64
aqiInfo                    object
aqiLevel                   object
max_temperature            object
min_temperature            object
time               datetime64[ns]
weather                    object
wind_direction             object
wind_power                 object
areaname                   object
dtype: object
复制代码

此次就对了,日期和 AQI 都分别变成了咱们须要的类型。其余数据,暂时保持原样。

有的是由于原本就该是字符串,例如城市名称。

另外一些,是由于咱们暂时不会用到。

下面咱们绘制一个简单的时间序列对比图形。

读入绘图工具包 plotnine 。

注意咱们同时读入了 date_breaks,用来指定图形绘制时,时间标注的间隔。

import matplotlib.pyplot as plt
%matplotlib inline
from plotnine import *
from mizani.breaks import date_breaks
复制代码

正式绘图:

(ggplot(df, aes(x='time', y='aqi', color='factor(areaname)')) + geom_line() +
 scale_x_datetime(breaks=date_breaks('2 weeks')) +
 xlab('日期') +
 theme_matplotlib() +
 theme(axis_text_x=element_text(rotation=45, hjust=1)) +
 theme(text=element_text(family='WenQuanYi Micro Hei'))
 )
复制代码

咱们指定横轴为时间序列,纵轴为 AQI,用不一样颜色的线来区分城市。

绘制时间的时候,以“2周”做为间隔周期,标注时间上的数据统计量信息。

咱们修改横轴的标记为中文的“日期”。

由于时间显示起来比较长,若是按照默认样式,会堆叠在一块儿,很差看,因此咱们让它旋转45度角,这样避免重叠,一目了然。

为了让图中的中文正常显示,咱们须要指定中文字体,这里咱们选择的是开源的“文泉驿微米黑”。

数据可视化结果,以下图所示。

png

怎么样,这张对比图,绘制得还像模像样吧?

从图中,你能够分析出什么结果呢?

反正我看完这张图,很想去丽江

小结

读过本教程,但愿你已经掌握了如下知识:

  • 如何在 API 云市场上,根据提示选购本身感兴趣的产品;
  • 如何获取你的身份验证信息 AppCode ;
  • 如何用最简单的命令行 curl 方式,直接调用 API 接口,得到结果数据;
  • 如何使用 Python 3 和更人性化的 HTTP 工具包 requests 调用 API 得到数据;
  • 如何用 JSON 工具包解析处理得到的字符串数据;
  • 如何用 Pandas 转换 JSON 列表为数据框;
  • 如何将测试经过后的简单 Python 语句打包成函数,以反复调用,提升效率;
  • 如何用 plotnine (ggplot2的克隆)绘制时间序列折线图,对比不一样城市 AQI 历史走势;
  • 如何在云环境中运行本样例,而且照葫芦画瓢,自行修改。

但愿这份样例代码,能够帮你创建信心,尝试本身去搜集与尝试 API 数据获取,为本身的科研工做添砖加瓦。

若是你但愿在本地,而非云端运行本样例,请使用这个连接t.cn/R3usDi9)下载本文用到的所有源代码和运行环境配置文件(Pipenv)压缩包。

若是你知道如何使用github,也欢迎用这个连接t.cn/R3usEti)访问对应的github repo,进行clone或者fork等操做。

固然,要是能给个人repo加一颗星,就更好了。

讨论

你以前尝试过用 Python 和 API 获取数据吗?你使用了哪些更好用的软件包进行数据获取、处理、分析与可视化呢?你还使用过哪些其余的数据产品市场?欢迎留言,把你的经验和思考分享给你们,咱们一块儿交流讨论。

喜欢请点赞。还能够微信关注和置顶个人公众号“玉树芝兰”(nkwangshuyi)

若是你对数据科学感兴趣,不妨阅读个人系列教程索引贴《如何高效入门数据科学?》,里面还有更多的有趣问题及解法。

相关文章
相关标签/搜索