第 13 章 应用编程接口
应用编程接口(application programming interface,API)听起来是一个很酷炫的概念,但事实上并不是。API 是在 Web 上共享数据的一种标准方式。许多网站通过 API 端点来共享数据。本书列出了很多可用的 API,但是下面是一些很有用或有趣的 API。
Twitter(https://dev.twitter.com/overview/api)
US Census(http://www.census.gov/data/developers/datasets.html)
World Bank(http://data.worldbank.org/node/9)
San Francisco Open Data(https://data.sfgov.org/)
这些都是返回数据的 API 示例。你向 API 发出请求,随后 API 返回数据。API 同样可以作为和其他应用交互的一种方式。例如,我们可以使用 Twitter API 来获得 Twitter 的数据,构建另外一个和 Twitter 交互的应用(例如,一个使用 API 发布推文的应用)。Google API 列表(https://developers.google.com/apis-explorer/#p/)是另外一个示例,大多数 API 允许你同公司服务进行交互。使用 LinkedIn API,你可以获取数据,发布更新到 LinkedIn,而不需要通过访问 Web 界面。因为 API 可以做很多不同的事情,所以它应该被认为是一种服务。就我们的目的而言,这个服务提供数据。
在这一章中,你会请求 API 数据并且保存到电脑。API 通常会返回 JSON、XML 或 CSV 文件,这意味着在数据保存到本地计算机之后,你需要应用在本书前几章学到的知识解析这些数据。本章使用的 API 是 Twitter API。
我们出于下面几个原因选择 Twitter API 作为样例。首先,Twiiter 是一个众所周知的平台。其次,Twitter 拥有大量的数据(推文),人们对分析这些数据有很大的兴趣。最后, Twitter API 允许我们探索许多 API 的概念,这正是本章讨论的话题。
Twitter 数据不仅是非正式的信息收集工具,类似于 One Million Tweet Map(http:// onemilliontweetmap.com/),同时也是更正式的学术研究工具,例如用于预测流感趋势(http://ieeexplore.ieee.org/document/5928903/?reload=true&tp=&arnumber=5928903&url=http:%2F%2Fieeexplore.ieee.org%2Fxpls%2Fabs_all.jsp%3Farnumber%3D5928903),以及捕获实时事件的发生,例如地震(http://dl.acm.org/citation.cfm?id=1772777)。
13.1 API特性
API 可以像数据响应请求一样简单,但是很难找到只有这个功能的 API 了。大多数的 API 还有其他有用的特性。这些特性包括多种不同的 API 请求方法(REST 或流式请求)、数据时间戳、频率限制、数据分级,以及 API 访问对象(key 和 token)。让我们通过 Twitter API 的上下文看一下这些特性。
13.1.1 REST API与流式API
Twitter API 有两种形式:REST API 和流式 API。大多数的 API 是 REST 形式的,但是一些实时服务通常会提供流式 API。REST 的全称为 Representational State Transfer(表述性状态转移),被设计用来构建稳定的 API 架构。可以使用 requests
库(见第 11 章)来获取 REST API 的数据。通过 requests
库,你可以发出 GET
和 POST
Web 请求——这是 REST API 用来返回对应数据所使用的方法。在 Twitter 这个实例中,REST API 允许你查询推文,发布推文,做 Twitter 允许通过网站做的绝大多数事情。
通过 REST API,你经常可以(但并不总是可以)在浏览器中通过请求 API 链接预览查询。如果在浏览器中加载了 URL,结果看起来像是文本块,你可以在浏览器中安装一个格式化预览插件。例如,Chrome 有 JSON 文件的预览插件,通过一种更好阅读的方式预览 JSON 内容。
流式 API 作为一种实时服务运行,监听对相关数据的请求。碰到流式 API 时,你会想要使用一个构建好的库帮助管理数据的拉取。想详细了解多 Twitter 流式 API 是如何工作的,可以查看 Twitter 网站上的概述(https://dev.twitter.com/streaming/overview)。
13.1.2 频率限制
API 通常都有频率限制,限制用户在一段时间内能够请求的数据数量。频率限制由 API 提供者出于多种不同的原因使用。除了频率控制,你可能还会碰到对数据访问有限制的 API,特别是数据与商业利益相关时。出于基础设施和客户服务的考虑,API 提供者会想要控制请求的数量,这样服务器和架构可以控制数据传输数量。如果允许每个人在 100% 的时间使用 100% 的数据,这可能会导致 API 服务的崩溃。
如果遇到需要支付额外费用来取得特殊访问权限的 API,你需要确定是否有能力支付,以及数据对研究有多大的价值。如果碰到有频率限制的 API,你需要确定是否数据的一个子集就足够了。如果 API 有频率限制,可能会花费相当长的时间来收集一个有代表性的样例,所以一定要评估你想要投入在这之上的努力程度。
API 通常会对所有的用户有频率控制,因为这样更易于管理。Twitter 的 API 曾经也使用这种方式;然而,随着流式 API 的出现,用法发生了改变。Twitter 的流式 API 提供了数据的常量流,而 REST API 限制了每 15 分钟你可以发出请求的数量。为了帮助开发者理解频率限制,Twitter 发布了一张图表(https://dev.twitter.com/rest/public/rate-limits)。
在练习中,我们会使用名叫获取搜索 推文(GET searchtweets)的 API。这个接口返回包含特定搜索语素的推文。如果你查看文档(https://dev.twitter.com/rest/reference/get/search/tweets),会发现 API 返回 JSON 格式的数据,频率限制在每 15 分钟 180 次或 450 次,取决于你是以用户还是应用的身份请求 API。
保存来自 API 资源的数据文件时,你可以保存很多文件,或者将数据写入一个文件。正如在第 6 章学到的,你也可以保存推文数据到数据库。无论你用什么方式来保存数据,确保定期保存数据,不丢失任何已经请求的数据。
在第 3 章,我们处理了一个 JSON 文件。如果在每 15 分钟之间最大化 API 使用频率,可以收集 180 个 JSON 文件。如果你碰到了频率限制问题,需要优化对 Twitter 或者其他 API 的请求,请阅读 Twitter 的“API 频率限制”(https://dev.twitter.com/rest/public/rate-limiting)这篇文章中的“避免碰到频率限制的一些建议”这一节。
13.1.3 分级数据卷
迄今为止,我们已经讨论了通过其 API 可免费获取的 Twitter 数据。但是或许你想要知道怎样能够得到所有的数据?在 Twitter 这个实例中,你可能听说过三种数据访问级别: firehose、gardenhose 和 Spritzer。Spritzer 是免费的 API。表 13-1 描述了这些级别之间的不同。
表13-1:Twitter feed类型
feed 类型 | 覆盖 | 可用性 | 花费 |
---|---|---|---|
firehose | 所有推文 | 通过合作伙伴可用——DataSift(http://datasift.com/)或 Gnip(https://gnip.com/) |
$$$
|
gardenhose | 10% 的推文 | 新的访问不再可用 | 不可用 |
Spritzer | 1% 或不到 1% 的推文 | 通过公共 API 可用 | 免费 |
看到这些选项你可能会想:“我需要 Firehose,因为我想要所有的数据!”但是在你尝试取得访问权限之前,需要知道下面这些事情。
firehose 是一个很大的数据。当处理海量数据时,你需要规模化数据处理。仅仅开始查询 firehose 提供的数据集,也会需要很多的工程师和服务器。
firehose 需要付费——一年几十万美元。这不包括你需要消耗的基础设施的花费(即服务器空间和数据库耗费)。使用 firehose 通常不是一个人可以独自做的事情——通常,由一个大型的公司或者机构支撑这些花销。
大部分你真正需要的,可以从 Spritzer 得到。
我们会使用 Spritzer,这是 Twitter 的免费公开 API,通过它可以在频率限制下取得推文。为了访问这个 API,我们会使用 API key 和 token。
13.1.4 API key和token
API key 和 token 是用来鉴别应用和用户的方式。Twitter API key 和 token 可能会让你迷惑。这里有四个你需要了解的概念。
- API key
标识应用。
- API secret
类似于应用的密码。
- token
标识用户。
- token secret
类似于用户的密码。
这几部分的组合给予我们访问 Twitter API 数据的权限。然而并不是所有的 API 都拥有这两层标识和密钥。Twitter 是一个很好的“最佳案例”(即更加安全的)示例。在一些情况下,API 会没有 key 或者只有一个 key。
创建一个Twitter API key和访问token
继续童工雇用的研究,收集 Twitter 上关于童工雇用的讨论。创建一个 Twitter API 的 key 很简单,但是需要以下几步。
(1) 如果你没有 Twitter 账户,先注册(https://twitter.com/signup)。
(2) 登录 apps.twitter.com。
(3) 点击“创建新应用”(Create New App)按钮。
(4) 给你的应用一个名称和描述。例如,名称设置为“童工讨论”,描述设置为“拉取 Twitter 上关于童工的讨论”。
(5) 给你的应用添加一个网站——这个网站托管着应用。指引这样写道:“如果你还没有一个 URL,可以先在此放置一个占位符,但是记得之后修改它。”我们并没有这样一个网站,所以把 Twitter 的 URL 放在这一栏中。确保你的 URL 中包含了 https,例如:https://twitter.com。
(6) 同意开发者协议,点击“创建 Twitter 应用”(Create Twitter Application)。
在创建了应用之后,你会被带到应用管理页。如果你找不到这个页面,可以通过回到应用起始页(https://apps.twitter.com/)找到它。
现在,你需要创建一个 token。
(1) 点击“Keys 和访问 Tokens”(Keys and Access Tokens)键。(这里你可以重置 key,同样可以创建一个访问 token。)
(2) 滚动到页面底部,点击“创建我的访问 token”(Create my access token)按钮。一旦你完成了这些,这个页面会通过在顶部更新来刷新。如果再一次滚动到页面底部,你会看到访问 token。
现在你应该有了一个消费者(API)key 和一个 token。下面是我们的 key 和 token。
消费者 key:
5Hqg6JTZ0cC89hUThySd5yZcL
消费者 secret:
Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c
访问 token:
3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w
访问 token secret:
nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C
不要跟任何人分享你的 key 或 token !如果你和朋友分享了 key,他们可以在电子层面上代表你。如果他们滥用这个系统,你可能会失去访问权限,并为他们的行为负责。
为什么发布自己的应用?其中一个原因是我们可以生成更多个。在生成新的 key 和 token 的过程中,已经禁用了本书包含的 key 和 token——如果意外地暴露了 key 或者 token,这也是你应该做的事情。如果你需要创建一个新的 key,去“Keys 和访问 Tokens”(Keys and Access Tokens)栏目,点击“重新生成”(Regenerate)按钮。这会为你重新生成一个新的 API key 和 token。
现在有了一个 key,让我们访问 API !
13.2 一次简单的Twitter REST API数据拉取
有了一系列的 key 值,现在可以开始访问 Twitter 的 API 数据了。在这一节中,我们会编写一个简单的脚本,使用一个搜索查询,从 API 拉取数据。这一节中的脚本基于一个由 Twitter 提供的、作为示例的 Python 代码片段(https://dev.twitter.com/oauth/overview/single-user#python)。这份代码使用了 Python OAuth2,OAuth2 是在使用 API 时为了安全地识别和连接而使用的协议。
当下最好的认证方式是使用 OAuth2。一些 API 可能仍旧在使用 OAuth1。OAuth1 与 OAuth2 在功能上有所不同,并且是一个已经废弃的协议。如果需要使用 OAuth1,你可以使用 Requests-OAuthlib(https://requests-oauthlib.readthedocs.org/en/latest/),同
requests
一起拉取数据。当通过 API 认证时,确保识别哪一个协议正在被使用。如果使用了错误的协议,在尝试连接时,你会收到错误信息。
首先,需要安装 Python OAuth2:
pip install oauth2
打开一个新文件,导入 oauth2
,并且为你的 key 变量赋值:
import oauth2
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
然后添加函数来创建 OAuth 连接:
def oauth_req(url, key, secret, http_method="GET", post_body="",
http_headers=None):
consumer = oauth2.Consumer(key=API_KEY, secret=API_SECRET) ➊
token = oauth2.Token(key=key, secret=secret) ➋
client = oauth2.Client(consumer, token) ➌
resp, content = client.request(url, method=http_method, ➍
body=post_body, headers=http_headers)
return content ➎
❶ 创建一个 oauth2
对象的消费者。消费者是 key 的所有者。这行代码给消费者提供 key,这样消费者可以顺利地通过 API 识别。
❷ 将 token 赋值给 oauth2
对象。
❸ 创建客户端,包含消费者和 token。
❹ 使用函数参数 url
,通过 OAuth2 客户端执行请求。
❺ 返回从连接接收到的内容。
现在有了一个函数,允许我们连接到 Twitter API。然而,我们需要定义 URL,并且调用函数。搜索 API 文档(https://dev.twitter.com/rest/public/search)告诉我们更多有关想要使用的请求的信息。使用 Web 接口,可以看到,如果搜索#childlabor,最终得到的 URL 是:https://twitter.com/search?q=%23childlabor。文档建议重新格式化 URL,所以最终的 URL 如下:https://api.twitter.com/1.1/search/tweets.json?q=%23childlabor。
之后,可以把这个 URL 作为一个变量,并使用之前定义的变量调用函数:
url = 'https://api.twitter.com/1.1/search/tweets.json?q=%23childlabor'
data = oauth_req(url, TOKEN_KEY, TOKEN_SECRET)
print(data) ➊
❶ 在最后添加打印语句,这样可以看见输出。
运行脚本时,你应该看到数据打印成一个很长的 JSON 对象。你可能记得 JSON 对象看起来和 Python 字典类似,但是如果使用 print(type(data))
重新运行脚本,你会发现内容是一个字符串。现在我们可以做以下两件事情中的一件:转化数据为一个字典并开始解析它,或者保存字符串到一个文件,之后再解析。为了继续在脚本中解析数据,在脚本顶部添加 import json
。之后,在尾部,使用 json
加载字符串,并且输出它。
data = json.loads(data)
print(type(data))
变量 data
现在会返回一个 Python 字典。如果你想要将数据写入一个文件并且在之后解析它,替换为下面的代码:
with open('tweet_data.json', 'wb') as data_file:
data_file.write(data)
最后的脚本应该看起来像下面这样:
import oauth2
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
def oauth_req(url, key, secret, http_method="GET", post_body="",
http_headers=None):
consumer = oauth2.Consumer(key=API_KEY, secret=API_SECRET)
token = oauth2.Token(key=key, secret=secret)
client = oauth2.Client(consumer, token)
resp, content = client.request(url, method=http_method,
body=post_body, headers=http_headers)
return content
url = 'https://api.twitter.com/1.1/search/tweets.json?q=%23popeindc'
data = oauth_req(url, TOKEN_KEY, TOKEN_SECRET)
with open("data/hashchildlabor.json", "w") as data_file:
data_file.write(data)
从这里开始,你可以查看 3.2 节,来解析数据。
13.3 使用Twitter REST API进行高级数据收集
从 Twitter 拉取单个数据文件并不是非常有用,因为这只返回大约 15 条推文。我们希望执行一连串的查询,这样可以收集尽可能多的关于这一话题的推文。我们会使用另外一个库来做这项工作——Tweepy。Tweepy 可以管理一系列的请求,包括 Twitter 的 OAuth。首先安装 tweepy
:
pip install tweepy
在脚本的最开始,导入 tweepy
,并且再一次设置你的 key:
import tweepy
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
之后将你的 API key 和 API secret 传入 tweepy
的 OAuthHandler
对象,这个对象会管理上一个实际提到的 OAuth 协议。之后设置你的访问 token。
auth = tweepy.OAuthHandler(API_KEY, API_SECRET) ➊
auth.set_access_token(TOKEN_KEY, TOKEN_SECRET) ➋
❶ 创建一个对象,通过 tweepy
来管理 API 认证。
❷ 设置访问 token。
之后,将刚刚创建的认证对象传递给 tweepy.API
:
api = tweepy.API(auth)
tweepy.API
对象可以接受不同的参数,这给了你请求数据时控制 tweepy
行为的能力。你可以通过传递参数(像 retry_count=3, retry_delay=5
)直接添加重试和延迟。另一个有用的选项是 wait_on_rate_limit
,这个选项会直到频率限制解除后再去做下一次请求。 tweepy
文档(http://docs.tweepy.org/en/latest/api.html)中有这些选项的细节和更多信息。
我们想要使用 tweepy.Cursor
创建一个和 Twitter API 的连接。然后将 API 方法(这里是 api.search
,http://docs.tweepy.org/en/latest/api.html#API.search)和与其相关的参数传递给指针(cursor)。
query = '#childlabor' ➊
cursor = tweepy.Cursor(api.search, q=query, lang="en") ➋
❶ 创建 query
变量。
❷ 使用 query
创建 cursor
,并且限制其只检索英语。
尽管
Cursor
并不是很直观,但是这是一个在数据库连接中很常用的编程名词。虽然 API 不是数据库,但类名称Cursor
可能受 API 类似数据库使用方式的影响而命名。你可以在维基百科(https://en.wikipedia.org/wiki/Cursor_(databases))上阅读更多关于指针的内容。
根据 tweepy
的文档(http://tweepy.readthedocs.org/en/latest/api.html),cursor
可以返回一个在单个对象级别或单页对象级别上的迭代器。你同样可以定义限制(http://tweepy.readthedocs.io/en/latest/cursor_tutorial.html#limits),来确定 cursor
抓取的页面数或对象数。如果查看 print(dir(cursor))
,你会看到这里有 3 个方法:['items', 'iterator', 'pages']
。一页返回一串对象,即在你的查询下独立的推文。根据需要,我们会使用页面。
让我们遍历这些页面,并且保存数据。在此之前,需要做以下两件事。
(1) 添加 import json
到脚本的顶端。
(2) 在脚本的相同目录下,创建一个名叫 data 的文件夹。为此,在命令行中运行 mkdir data
。
一旦你完成了这两件事情,运行下面的代码来遍历和保存推文:
for page in cursor.pages(): ➊
tweets = [] ➋
for item in page: ➌
tweets.append(item._json) ➍
with open('data/hashchildlabor.json', 'wb') as outfile: ➎
❶ 对于每一个 cursor.pages()
返回的页面……
❷ 创建一个空列表来保存推文。
❸ 对于页面中的每一个对象(或推文)……
❹ 抽取 JSON 推文数据,保存到推文列表中。
❺ 打开一个名为 hashchildlabor.json 的文件,保存这些推文。
你会注意到,没有保存太多的推文到文件。每个页面只有 15 个推文,所以我们需要找出一个方法来得到更多的数据。有以下一些选项。
打开一个文件,并且永远不关闭它,或者打开一个文件,在末尾追加信息。这会创建一个非常大的文件。
将每一页保存到自己的文件中(你可以使用时间戳来保证每个文件有不同的文件名)。
在你的数据库中创建一个新的表来保存数据。
创建一个文件是危险的,因为进程在任何时候都可能失败,破坏数据。除非你只是在进行很小规模的数据拉取(例如,1000 条推文),或进行开发测试,否则你应该使用其他选择。
每次都有很多种方法可以将数据保存到新文件中,最普遍的一种方式是使用日期和时间戳(https://docs.python.org/2/library/datetime.html)创建一个文件,或者只是递增一个数字,将其添加到文件名的末尾。
我们会继续添加推文到简单的数据库。为此,使用下面的函数。
def store_tweet(item):
db = dataset.connect('sqlite:///data_wrangling.db')
table = db['tweets'] ➊
item_json = item._json.copy()
for k, v in item_json.items():
if isinstance(v, dict): ➋
item_json[k] = str(v)
table.insert(item_json) ➌
❶ 创建或访问一个新表,名为 tweets
。
❷ 检查推文中是否含有字典对象。由于 SQLite 并不支持保存 Python 字典,我们需要将其转换为字符串。
❸ 插入合法的 JSON 对象。
我们还需要添加 dataset
到 import
部分的代码中。在之前保存页面的地方,需要添加这个函数的使用。确保遍历每一条推文。最后的脚本应该看起来像下面一样。
import json
import tweepy
import dataset
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
def store_tweet(item):
db = dataset.connect('sqlite:///data_wrangling.db')
table = db['tweets']
item_json = item._json.copy()
for k, v in item_json.items():
if isinstance(v, dict):
item_json[k] = str(v)
table.insert(item_json)
auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
auth.set_access_token(TOKEN_KEY, TOKEN_SECRET)
api = tweepy.API(auth)
query = '#childlabor'
cursor = tweepy.Cursor(api.search, q=query, lang="en")
for page in cursor.pages():
for item in page:
store_tweet(item)
13.4 使用Twitter流式API进行高级数据收集
本章前文中提到过,有两种类型的 Twitter API 可以使用:REST API 和流式 API。
流式 API 同 REST API 相比有什么差别呢?下面进行了简单的概括。
数据是实时的,而 REST API 只返回已经发布一段时间的推文。
流式 API 缺乏普遍性,但是在未来,随着更多实时数据的生成和曝光,其可用性会变得越来越高。
因为最新的数据很有趣,所以很多人对这部分数据很感兴趣,这意味着你可以在网络上找到很多资源和帮助。
让我们创建一个脚本来收集来自流式 API 的数据。这个脚本会使用在这一章覆盖到的所有知识。首先编写最基础的部分——输入值和 key 值。
from tweepy.streaming import StreamListener ➊
from tweepy import OAuthHandler, Stream ➋
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
❶ 导入 StreamListener
,这会创建一个流式会话,并且监听信息。
❷ 导入之前使用过的 OAuthHandler
,以及 Stream
,后者是真正处理 Twitter 的流信息的类。
这个脚本中的 import
语句和上一个脚本中的有少许不同。这两种方式都是合法的,只是个人偏好问题。下面是这两种方式的一个快速比较。
方式 1
import tweepy
...
auth = tweepy.OAuthHandler(API_KEY, API_SECRET)
方式 2
from tweepy import OAuthHandler
...
auth = OAuthHandler(API_KEY, API_SECRET)
通常情况下,脚本中没有频繁使用库时使用第一种方式。在你有一长串代码,想要更清晰一些的时候,也适合使用第一种方式。然而,当库使用得非常多时,要将其都打印出来会变得令人厌烦;同样,如果这个库是脚本的基础,从这个库导入的模块或类对人们来说应该很明显。
现在,要创建导入的 StreamListener
类的子类(在第 12 章学习的概念),以覆写其中的 on_data
方法。为此,在新的类 Listener
中重新定义了这个函数。当有数据时,我们想要在终端中看到它们,所以添加 print
语句到函数中。
class Listener(StreamListener): ➊
def on_data(self, data): ➋
print data ➌
return True ➍
❶ 创建 StreamListener
的子类。
❷ 定义 on_data
方法。
❸ 输出推文。
❹ 返回 True
。StreamListener
有 on_data
方法,同样返回 True
。因为我们创建了子类并重新定义了这个函数,所以必须在子类方法中重复返回这个值。
接下来,添加你的认证处理逻辑:
auth = OAuthHandler(API_KEY, API_SECRET)
auth.set_access_token(TOKEN_KEY, TOKEN_SECRET)
最后,将 Listener
和 auth
传入到 Stream
中,开始使用搜索词过滤。在这个案例中,我们查看 child labor(童工),因为它相对于 #childlabor 更加普遍。
stream = Stream(auth, Listener()) ➊
stream.filter(track=['child labor']) ➋
❶ 将 auth
和 Listener
作为参数传递,创建一个流。
❷ 过滤流,只返回有 child 和 labor 存在的条目。
最后的脚本如下:
from tweepy.streaming import StreamListener
from tweepy import OAuthHandler, Stream
API_KEY = '5Hqg6JTZ0cC89hUThySd5yZcL'
API_SECRET = 'Ncp1oi5tUPbZF19Vdp8Jp8pNHBBfPdXGFtXqoKd6Cqn87xRj0c'
TOKEN_KEY = '3272304896-ZTGUZZ6QsYKtZqXAVMLaJzR8qjrPW22iiu9ko4w'
TOKEN_SECRET = 'nsNY13aPGWdm2QcgOl0qwqs5bwLBZ1iUVS2OE34QsuR4C'
class Listener(StreamListener):
def on_data(self, data):
print data
return True
auth = OAuthHandler(API_KEY, API_SECRET)
auth.set_access_token(TOKEN_KEY, TOKEN_SECRET)
stream = Stream(auth, Listener())
stream.filter(track=['child labor'])
下面,你需要添加代码,通过 on_data
方法,像本章之前那样将推文保存到数据库、文件或其他的存储工具。
13.5 小结
能够同应用编程接口进行交互是数据处理中很重要的一部分。在这一章中,我们学习了一些 API 基础知识(见表 13-2 中的总结),并且处理了来自 Twitter API 的数据。
表13-2:API概念
概念 | 功能 |
---|---|
REST API(与流式 API 相比) | 返回数据,并且暴露静态的节点 |
流式 API(与 REST API 相比) | 返回查询相关的实时数据 |
OAuth 和 OAuth2 | 给定一系列 key 值和 token 的认证 |
分级数据卷 | 数据频率限制 / 可用性的不同级别;一些需要付费 |
key 和 token | 标识用户和应用的唯一 ID 和密钥 |
我们已经复用了许多已经知道的 Python 概念,并且在这一章中学习了一些新的 Python 概念。首先是 tweepy
的使用,一个处理同 Twitter API 交互的库。你还学习了有关认证和 OAuth 协议的知识。
作为同 API 交互的拓展,第 14 章会介绍你不在场时运行 API 脚本的知识。