第13章 Web服务

我没有对Twitter上瘾。我只在有空的时候刷推特,比如,吃饭的时候、休息的时候、这个时候、那个时候、所有时候。

——佚名,早于2010年5月

本章内容:

简介;

Yahoo!金融股票报价服务器;

Twitter的微博。

本章将简要介绍如何使用当今可接触到的一些Web服务,如较老的Yahoo!金融股票报价服务器以及较新的Twitter。

13.1 简介

网络上有许多Web服务和应用,分别提供不同的功能。大部分较大的公司,如Yahoo!、Google、Twitter 和 Amazon,都会为这些服务提供应用编程接口(API)。过去,API仅仅用来在使用服务时访问数据。但今日的API有所不同,不但有更加丰富的功能,而且通过这些API可以将服务整合到个人网站和页面中,这种方式通常称为“mash-up”。

这是个非常有趣的领域,后面会进一步探讨其他一些技术(REST、XML、JSON、RSS、Atom等)。现在先回头看看一个已经存在很久但仍然很有用的API,即Yahoo!提供的股票报价服务器,参见http://finance.yahoo.com。

13.2 Yahoo!金融股票报价服务器

如果访问Yahoo! Finance网站,选择任意一只股票的报价,会在页面下方,报价数据下面的“Toolbox”中发现一个标为“Download Data”的URL链接。用户通过这个链接下载.csv文件,以导入Microsoft Excel或Intuit Quicken中。如果访问的是GOOG的股票,则URL类似下面这样。

http://quote.yahoo.com/d/quotes.csv?s=GOOG&f=sl1d1t1c1ohgv&e=.csv

如果浏览器的MIME设置是正确的,浏览器会启动在系统中配置过用来处理CSV数据的软件,它们通常是类似Excel或LibreOffice Calc这样的电子表格应用。这主要是因为链接中的最后一个变量(键值对)是“e=.csv”。服务器实际不使用这个变量,而它总是返回CSV格式的数据。

如果使用urllib2.urlopen(),会返回的一个CSV字符串,其中含有股票代号。

>>> from urllib2 import urlopen

>>> url = 'http://quote.yahoo.com/d/quotes.csv?s=goog&f=sl1d1c1p2'

>>> u = urlopen(url, 'r')

>>> for row in u:

…  print row

"GOOG",600.14,"10/28/2011",+1.47,"+0.25%"

>>> u.close()

接着需要手动解析这个字符串(去除末尾空格,以及根据逗号分割符切分)。除了自行解析数据字符串之外,也可以使用csv模块(Python 2.3新增),该模块可以切分字符串并去除空格。通过csv,可以使用下面的代码替换掉前面示例中的for循环,其他内容不变。

>>> import csv

>>> for row in csv.reader(u):

…print row

['GOOG', '600.14', '10/28/2011', '+1.47', '+0.25%']

通过分析由URL字符串传递给服务器的参数字段f,以及阅读Yahoo!针对该服务的在线帮助,可以发现符号(sl1d1c1p2)分别对应股票代号、收盘价、日期、变化量、变化百分比。

更多信息可以阅读 Yahoo! Finance 帮助页面,只须在该页面搜索“download data”或“download spreadsheet format”即可。进一步分析API会发现更多选项,如上一次收盘价、52周内的最高和最低价等。表13-1总结了这些选项,以及返回的格式(这是15年前真实的Yahoo!股价,不要感到惊讶)。

表13-1 Yahoo!股票报价服务器参数 tweepy-example.py - 图1 ① 字段名称的第一个字符是字母,第二个字符(如果存在)是数字。

② 有些返回值含有额外的引号,尽管这些值都是作为服务器返回的单个CSV字符串的一部分。

服务器根据用户指定的顺序显示字段名称。将这些字段连接起来,组成单个字段参数f,作为请求URL的一部分。就像在表13-1脚注②中提到的,有些返回的组件分别用引号括起来。这取决于解析器提取数据的方式。观察前面例子中手动解析与使用csv模块分别得到的结果子字符串。如果无法获得相应的值,报价服务器会返回“N/A”,如下面的代码所示。

例如,如果使用f=sl1d1c1p2向服务器发起一个字段请求,会得到下面这样的字符串(这是我在2000年运行的查询结果)。

"YHOO",166.203125,"2/23/2000",+12.390625,"+8.06%"

而对于不再公开交易的股票,会得到下面这样的内容(注意,即使是N/A也会用引号括起来):

"PBLS.OB",0.00,"N/A",N/A,"N/A"

还可以指定多个股票代号,输出结果中每一行显示一个公司的数据。但要注意 Yahoo! Finace帮助页面上说的:“在Yahoo!上显示的任何数据都严格禁止再次发布”,所以只能将这些数据作为个人用途。另外还要注意,这些下载得到的报价有延迟。

根据这些内容,来构建一个读取并显示一些关注的互联网公司股票报价数据的应用,如示例13-1所示。

示例13-1 Yahoo! Finance股票报价示例(stock.py)

该脚本从Yahoo! quote服务器下载并显示股票价格。

tweepy-example.py - 图2

当运行该脚本时,输出结果如下所示。

$ stock.py

Prices quoted as of: Sat Oct 29 02:06:24 2011 PDT

TICKER PRICE CHANGE %AGE


"YHOO" 16.56 -0.07 "-0.42%"

"DELL" 16.31 -0.01 "-0.06%"

"COST" 84.93 -0.29 "-0.34%"

"ADBE" 29.02 +0.68 "+2.40%"

"INTC" 24.98 -0.15 "-0.60%"

逐行解释

第1~7行

这个 Python 2 脚本使用 time.ctime()显示股票信息从 Yahoo!下载下来的时间点, urllib2.urlopen()连接到 Yahoo!的服务以获取股票数据。接下来是股票代号的导入语句,以及获取所有数据的固定URL。

第9~12行

这一小块代码显示下载股票信息的时间点,并使用 urllib2.ulropen()获取请求的数据(如果读过本书之前的版本,会注意到这里简化了输出代码,感谢之前眼尖的读者!)。

第14~18行

从Web下载下来的数据作为一个文件类型的对象打开,遍历该对象获取每一行,分隔由逗号间隔的列表,接着显示到屏幕上。

与从文本文件读取类似,这里依然保留了行末的终止符,所以需要向每个print语句的末尾添加一个逗号,来消除换行符的影响;否则,每个数据行之间会有两个空行。

最后,注意,有些返回的字段含有引号。本章末尾会有若干练习,用来改进默认的输出格式。

13.3 Twitter微博

这一节将会介绍通过 Twitter 服务构成的微博世界。它首先简要介绍社交网络,描述Twitter所扮演的角色,了解其提供的多种Python接口,最后,分别介绍一个简单和一个相对较复杂的示例。

13.3.1 社交网络

过去五年多来,社交媒体得到了长足的发展。它首先仅仅是一个简单的概念,如Web登录,或发布一些简短的消息。这种类型的服务需要用户登录账号,用户可以发布文章或其他形式的文体。可以将其想象为公共在线期刊或日记,人们可以对当前事件发布观点或批评,或任何想让别人知道的事情。

但在线意味着全世界都会知道分享的内容。用户无法只针对特定的人或组织,如朋友或家人,发布信息。因此诞生了社交网络,MySpace、Facebook、Twitter 和 Google+就是最广为人知的。通过这些系统,用户可以与他们的朋友、家人、同事,以及社交圈内的人沟通。尽管对于用户来说,这些服务大同小异。但这些社交网络依然有各自的区别。比如各自的交互方式就不同,因此,这些社交网络之间并不是完全处于竞争关系。首先介绍各个社交工具,接着深入了解Twitter。

MySpace 主要面向年轻人(初中或高中),侧重于音乐。Facebook 原先专注于大学生,但现在面向所有人群。与MySpace相比,Facebook是个更加通用的平台,可以在上面托管应用,这是让Facebook成为主流社交工具的特性之一。Twitter是微型博客服务,与传统博客相比,用户在Twitter上发布状态,通常是对某件事的观点。而Google+是这个因特网巨人最近对该领域的尝试,试图提供与其他工具相似的功能,同时也包括一些新的功能。

在这些常见的社交媒体应用中,最基本的是Twitter。用户可以使用Twitter发布短小的状态信息,称为推文。其他人可以“关注”你,即订阅你的推文。同样,你也可以关注其他感兴趣的人。

将Twitter称为微型博客服务是因为与标准博客不同,标准博客允许用户创建任何长度的博文,而每条推文最长限制为140个字符。这个长度限制主要是因为该服务原先是面向手机的,它是通过短消息服务(Short Message Service,SMS)支持的Web和文本信息,SMS只能处理160个ASCII字符。这样用户不用阅读冗长的内容,而发布者则必须在140个字符内将事情表述清楚。

13.3.2 Twitter和Python

Twitter API 库中有若干 Python 库。在 Twitter 的开发者文档中有介绍(https://dev.twitter.com/docs/twitter-libraries#python)。这些库之间既有相同点,又有各自的特点,所以建议读者自己分别试用一下,找到最适合自己的库。这里不做过多的限制,本章将会使用到 Twython 和Tweepy。这两个库分别位于http://github.com/ryanmcgrath/twython和http://tweepy.github.com。

与大多数Python包相同,可以选择easy_intall或pip分别安装,也可以用一款工具同时安装这两个库。如果对库的源码感兴趣,可以在GitHub上了解对应的代码库。另外,可以直接从GitHub上下载最新的.tgz或.zip格式的文件,然后调用经典的setup.py install命令安装。

$ sudo python setup.py install

Password:

running install

running bdist_egg

running egg_info

creating twython.egg-info

Finished processing dependencies for twython==1.4.4

类似 Twython 这样的库需要通过一些额外的方式与 Twitter交互。其依赖于 httplib2、oauth2和simplejson。(最后一个在Python 2.5之前作为外部json库,从Python 2.6开始成为标准库。)

起步

为了能开始上手,这里用一个简单的示例介绍如何使用Tweepy库在Twitter上进行搜索。

tweepy-example.py

import tweepy

results = tweepy.api.search(q='twython3k')

for tweet in results:

print '  User: @%s' % tweet.from_user

print '  Date: %s' % tweet.created_at

print '  Tweet: %s' % tweet.text

如果执行这个Python 2脚本(在本书编写时,Tweepy还不支持Python 3)进行查询,读者会注意到这个搜索的关键字是专门选定的,只能找到很少的搜索结果。也就是说,无论使用Python 3版本的Twython库,还是这个Tweepy版,Twitter只会返回几条推文(在本书编写时)。

$ python twython-example.py

User: @wescpy

Date: Tue, 04 Oct 2011 21:09:41 +0000

Tweet: Testing posting to Twitter using Twython3k (another story of life on the bleeding edge)

User: @wescpy

Date: Tue, 04 Oct 2011 17:18:38 +0000

Tweet: @ryanmcgrath cool…thx! i also have a "real" twython3k bug i need to file…will do it officially on github.just giving you a heads-up!

User: @wescpy

Date: Tue, 04 Oct 2011 08:01:09 +0000

Tweet: @ryanmcgrath Hey ryan, good work on Twython thus far!

Can you pls drop twitter_endpoints.py into twython3k? It's out-of- date…thx! :-)

调用Tweepy库的search()会获得一个推文列表。代码遍历列表中的推文并显示其中感兴趣的部分。Twython是一个类似的Python库,提供了Twitter API。

Twython与Tweepy类似,但也有自己的特点。Twython同时支持Python 2和3,但输出的结果不用对象,而是用纯Python字典来持有结果数据。将前面的tweepy-example.py与这里的twython-example.py脚本进行比较,后者兼容Python 2和3。

twython-example.py

from distutils.log import warn as printf

try:

import twython

except ImportError:

import twython3k as twython

TMPL = '''\

User: @%(from_user)s

Date: %(created_at)s

Tweet: %(text)s

'''

twitter = twython.Twython()

data = twitter.searchTwitter(q='twython3k') for tweet in data['results']:

printf(TMPL % tweet)

distutils.log.warn()函数是Python 2中print语句和Python 3中print函数的代理。同时读者还可以尝试导入Python 2和3中的Twython库,希望至少有一个会成功。

Twython.searchTwitter()的输出结果是一个字典,该对象在字典的“results”键中,每个对象都是一个字典列表,表示一条推文。因为结果是个字典,这样就可以简化显示,还可以更方便地调用(付出的代价是需要使用字符串模板来展开字典中含有的键值)。

这里还有其他改动,如不使用纯单行输出,将所有字符串放到一个大的字符串模板中,然后将输出的字典传递给字符串模板。这样做的原因是在实际应用中经常会使用某种形式的模板(无论是字符串模板还是Web模板)。

这里输出的结果与Tweepy版本相同,所以这里就不重复了。

13.3.3 稍微长一点的API组合应用示例

这些简单短小的示例可以快速地让读者上手。但在现实当中会遇到不同的场景,因此可能需要使用或集成多种类似的 API。下面通过一个稍微长一点的示例来练习。这里将编写一个兼容库,通过同时使用Tweepy和Twython来支持一些基本的Twitter命令。这个练习会帮助读者学习这两个库,并更加熟悉Twitter的API。

验证

在继续这个练习之前,读者需要一个Twitter账号。如果没有,访问http:// twitter.com并注册一个。一般需要用户名和密码进行验证(更现代的方式包括生物方式的验证,如指纹或视网膜扫描)。这些凭证仅用于身份验证,数据访问则是另外一回事。

授权

验证并不意味着可以访问数据(任何人的数据都不行),还需要正确的授权。在通过Twitter或第三方授权后才能访问自己或其他人的数据,如允许外部应用下载 Twitter 消息或通过Twitter账号发布状态来更新Twitter账号。

为了通过Twitter获取授权凭证,需要创建一个应用。可以在http://dev.twitter.com中完成这个任务。至少拥有一个应用,然后再单击需要授权的应用。URL类似于https://dev.twitter.com/apps/APP-ID/show,这里可以看到访问Twitter数据所需的OAuth设置,它包括4个重要的部分:consumer key、consumer secret、access token和access token secret,它们都用来访问Twitter上的数据。

获取这4块有价值的数据后,将其放置在一个安全的地方,也就是说,不能放在源码中!在这个例子中,将这些数据另存到一个名为tweet_auth.py模块的4个全局变量里。在最终的应用中会导入这个模块。实际应用中,要么发布编译过的字节码.pyc(不是纯文本),要么通过数据库或网络上的其他位置访问这些数据,最好是加密过的。现在所有内容都设置完毕,在描述代码前先介绍应用本身。

一个混合的Twitter API应用

这个应用执行4个操作:首先它输出在Twitter上搜索的结果;接着,它获取并输出当前应用更详细的信息;然后,它获取并输出当前用户发布消息的时间线;最后,它为当前用户发布一条推文。这4个操作都执行两次:一次使用Tweepy库,另一次使用Twython库。为了完成这个任务,需要支持4个Twitter API命令,如表13-2所示。

表13-2 混合Twitter API应用的4个命令 tweepy-example.py - 图3

这款应用同时使用了Twython和Tweepy。最后,代码会在Python 2和Python 3中运行。也就是说,代码中有这4个命令,并实例化两个库,接着含有支持每个命令的代码。准备好了吗?查看示例13-2中的twapi.py。

示例13-2 Twitter API组合库示例(twapi.py)

这里演示使用Twython和Tweepy库与Twitter交互。

tweepy-example.py - 图4

tweepy-example.py - 图5

tweepy-example.py - 图6

tweepy-example.py - 图7

tweepy-example.py - 图8

在介绍这个脚本之前,先运行并查看其输出。要确保首先创建一个tweet_auth.py文件,其中含有以下这些变量(以及Twitter应用中正确的对应值)。

tweet_auth.py

consumer_key = 'SOME_CONSUMER_KEY'

consumer_secret = 'SOME_CONSUMER_SECRET'

access_token = 'SOME_ACCESS_TOKEN'

access_token_secret = 'SOME_ACCESS_TOKEN_SECRET'

现在可以开始了。当然,这是在编写本书时执行程序得到的输出结果,读者得到的肯定会与此不同。下面是执行时的状态(“…”表示省略了一些输出内容以缩短篇幅)。

$ twapi.py

* SEARCH

TWYTHON


@ryanmcgrath

Status: #twython is now version 1.4.4; should fix some utf-8 decoding issues, twython3k should be caught up, etc: http://t.co/s6fTVh0P /cc@wescpy

Posted at: Thu, 06 Oct 2011 20:25:17 +0000


@wescpy

Status: Testing posting to Twitter using Twython3k (another story of life on the bleeding edge)

Posted at: Tue, 04 Oct 2011 21:09:41 +0000


@wescpy

Status: @ryanmcgrath cool…thx! i also have a "real"

twython3k bug i need to file…will do it officially on github.just giving you a heads-up!

Posted at: Tue, 04 Oct 2011 17:18:38 +0000


@wescpy

tweepy-example.py - 图9

Status: I'm wondering: will future Apple products visually be designed as well & have as much impact on the market? What do you think?

Posted at: Thu Oct 06 00:02:16 +0000 2011



TWEEPY


Status: .@imusicmash That's great that you're enjoying corepython.com!

Note: there will be lots of cookies at #SVCC: yfrog.com/kh1azqznj

Posted at: 2011-10-07 22:37:37


* UPDATE STATUS

Posted at: Sat Oct 08 05:18:51 +0000 2011


Posted at: 2011-10-08 05:18:51


* RESULTS WRAPPER

..


-

Ran 2 tests in 0.000s

OK

$

从中可以看到运行了4个函数,这4个函数执行时分别使用了Tweepy库和Twython库。如果安装没有问题,在Windows上执行脚本时会获得相同的结果。因为代码也兼容Python 3,所以在Python 3中也得到类似的输出,但只能看到Twython的输出,因为Tweepy在本书编写时还不支持Python 3。现在来进一步了解代码。

逐行解释

第1~5行

这里含有一些导入语句,包括导入标准库(使用distutils.log.warn()作为print语句或函数的代理,具体取决于是Python 2还是Python 3,还有一些在Python中运行单元测试的基本属性),以及Twitter授权凭证。

还要提醒的是,在一般情况下,不鼓励使用“from module import *”(第 5行),因为标准库和第三方库中可能含有与该模块相同的变量名称,这样会有潜在的问题。在这里,完全了解tweet_auth.py并知道其中所有(4个)变量。该模块的唯一目的是隐藏用户的凭证信息。在实际生产环境中,这样一个文件要么作为编译过的字节码(.pyc)或优化过的文件(.pyo),要么来自数据库或网络调用,需要说明的是,.pyc和.pyo两者都是人类不可读的。

第7~38行

第一块实际代码只完成了一件事,即让Python解释器了解可以使用哪个Twitter客户端库,就这样。

CMD是一个字典,其中还有两个字典项,分别是Twython(twython)和Tweepy(tweepy)。在本章末尾的练习中,会添加第三个库。

对于每个库,提供方法名表示前4个方法对应的Twitter API命令。如果该值是None,这意味着方法名完全匹配。如果使用其他值(即不是None),即表示方法名与API命令不一致。

Tweepy较为简单,其方法名与命令完全匹配。因此,使用dict.fromkeys()创建字典时,所有键的值都是None。Twython就有点麻烦,因为其使用驼峰命名法,且有与规则不一致的地方。第71~80行描述了为什么使用这些名称和方法。

在第22行,将所有支持的API放到集合中。在Python中,最快速检测是否包含的方式是使用集合数据结构,同时遍历这个变量中的所有API。到目前为止,仅创建了可能的API,现在需要看实际当中可能使用哪些,把不能用的去除。

第25~33行的代码尝试导入各个库,将无法导入的API移动到另一个含有不存在的API的remove集合中。循环结束后,就知道缺少哪些API,把这些缺失的API从全体API中删除(第35行)。如果两个库都不可用,则在第36~38行抛出NotImplementedError异常。

第40~71行

Twitter类是该应用的头等对象。该类定义了初始化函数,获取api(在这里,要么是twython,要么是 tweepy),以及可选的 auth标记。该标记默认为 True,因为大部分时候需要验证和授权才能访问用户数据(Search是唯一不需要验证的函数),然后将选定的API缓存到self.api中。

这一节剩余的部分用来(第48~71行)实例化Twitter,并将该实例赋值给self.twitter。该对象是执行Twitter API命令的处理程序。

第73~81行

_get_meth()方法处理特殊情况,将每个API的调用与正确的方法名称整合到一起。注意,该方法前面有单条下划线。这种标记法表示该方法不应该由用户调用,而它是一个内部方法,由该类中的其他方法调用。

可以在该方法中直接使用self.api,但众所周知,最佳实践是将经常使用的实例属性赋值给局部变量。使用self.api需要两次查询,而“api”只需一次,从CPU时间上来看,另一次查询并不耗时很多,但如果在类型循环中或经常执行它,开销就会增大。这就是为什么在第74行赋值给局部变量。

下一行中,查询来自请求API里相应的命令,并赋值给meth_name。如果它是None,则默认行为是命令与方法名称相同。对于Tweepy,很简单,前面提到过,其方法名与命令名完全相同。接下来的几行用于处理特殊情况,来获得正确的名称。

前面提到过,Twython使用驼峰命名法,而不是通过下划线分割单词。这意味着必须先根据下划线将每个单词分开,接着将其追加到第一个单词后面(第79~80行)。最后一个行为是使用这个名字从请,求的API中获取方法对象,这是个头等对象,把它直接返回给调用者。

第83~102行

支持的4个Twitter命令由4个函数实现:search()、verify_credentials()、user_timeline()、update_status()。除了 search()之外,其他三个很简单,两个库的使用方式几乎相同。首先看后面三个,最后再深入了解search()。

验证已经通过身份验证的用户信息仅仅是 verify_credentials 命令能做的其中一件事。该命令同时能用编程方式最快地访问最新的推文。用户信息会打包成 ResultsWrapper(后面会进一步介绍),接着返回给调用者。关于使用这条命令的更多信息可以参考 Twitter 文档(http://dev.twitter.com/docs/api/1/get/account/verify_credentials)。

用户的时间线由最近发布的推文和转推组成。user_timeline这个Twitter命令默认情况下返回最近的20条,而使用count参数可以最多请求200条,不过这里没有用到,但本章末尾的一个练习中会用到。关于该函数的更多信息可以参考 http://dev.twitter.com/docs/api/1/get/statuses/user_timeline。与 verify_credentials()不同,user_timeline 封装每条单独的推文,而不是返回来自Twitter的整个结果,返回一个生成器表达式,迭代返回推文。

Twitter最基本的功能是用户可以更新自己的状态,也就是,发布推文。如果没有这个功能,就不能称之为Twitter了。从代码中可以看出,update_status接受额外的参数s,这是推文的文本。返回值是推文本身(同样被ResultsWrapper封装),通过最重要的特性(created_at字段),表示推文已经创建并已发布。下面代码中的created_at演示了这个功能。关于该函数的更多用法,参考http://dev.twitter.com/docs/api/1/post/statuses/update。

现在返回search。Twython和Tweepy两个库对这个API调用方式有所区别,所以代码要比普通情形多。Twython试图原原本本解释Twitter返回的结果,将JSON装成Python字典。这种数据结构含有多个元数据,在“results”键下还会发现一些有用的信息(需要在第86行进行查找)。

而Tweepy更加现实,直接以列表形式对象返回搜索结果,实际上,ResultsSet是列表的子类,因为开发者知道用户实际上想要什么。这样更加方便,节省了将来查找的时间。那么额外的元数据呢?那些只是返回的ResultsSet的属性而已。

第104~124行

这一块代码是通用类,可以在任何地方使用,包括在这个应用之外。该类与Twitter库没有关系,仅仅用来方便用户,为这些库返回的对象提供通用接口。

读者是否因为不一致的对象类型而感到挫败过,比如字典类型或对象类型?我的意思是对于字典对象,需要通过getitem()调用获取值,即 foo['bar'],而对于对象,需要处理对象的属性接口,即 foo.bar。能否做到不管是什么对象,可以同时使用这两个方式?这就是ResultsWrapper类的工作。

在编写本书时,我刚刚接触这些,所以可能不够完善,但其思想是将任何Python对象封装到一个对象中,将查询(通过getitem()或getattr())委托给封装对象(对于委托的内容,可以阅读 Core Python Programming 或者 Core Python Language Fundamentals 的Object-Oriented Programming)。

在初始化函数中(第106~107行)封装对象。然后使用str以字符串的形式表示对象(第 109~113 行)。大多数变化发生在getattr()中。当请求一个没有识别的属性时,getattr()检查在封装对象中是否是存在该属性(第116~117行)。如果没有,也许在字典对象中,所以检查它是否是一个“键”(第118~119行)。当然,在使用in操作符之前,需要检查该对象是否支持这种类型的检查或访问,即首先检查对象是否含有contains属性。如果所有else都失败,则告知用户处理失败(第120~122行)。

最后一行(第124行)用来应对用户试图用字典的方式访问属性,即将属性名称作为键来使用。我们希望getitem有与getattr()完全相同的行为。因此,无论封装的对象类型是什么,都能获得并返回用户需要的内容。

第126~165行

demo*()函数的名副其实:_demo_search()演示了使用所有可用 API 搜索条目“twython3k”,并显示搜索推文的结果数据。_demo_ver_creds()执行verify_credentials命令,并显示已验证用户最近的推文;_demo_user_timeline()获取最新的20条推文,显示每条推文的内容和时间戳。最后,_demo_update_status()发布新的推文,新推文介绍了所用到的API。

第167~184行

这一部分代码用于测试ResultsWrapper类。unit*_wrap()函数测试每个封装的字典(或类似字典的对象),以及含有属性接口的对象。这两个都通过属性访问,无论是通过obj['foo'],还是通过obj.foo都会返回相同的结果“bar”。最后通过TestSequenceFunctions测试类完成这种验证(第179~184行)。

第186~196行

main()函数显示正在测试哪个函数,并调用特定的demo*()函数显示其输出。最后一个调用针对unittest.main()函数,用于执行单元测试。

13.3.4 总结

通过这一节的内容,希望读者扎实地掌握了一些Web服务的接口,如Yahoo!的股票报价服务器,以及Twitter。更重要的是,认识到Yahoo的接口完全是由URL驱动的,无须授权。而Twitter提供了完全的REST API和用于访问安全数据的OAuth授权。我们能够使用Python代码发挥这些强大的功能来完成工作。

这里只介绍了两个 Web 服务,网络上还有许多其他的服务。下一章还会回顾这两个服务。

13.3.5 额外在线资源

Yahoo! Finance

http://gummy-stuff.org/Yahoo-data.htm

http://gummy-stuff.org/forex.htm

Twitter

http://dev.twitter.com/docs/twitter-libraries#python

http://github.com/ryanmcgrath/twython

http://tweepy.github.com

13.4 练习

Web服务

13-1 Web服务。使用自己的语言描述什么是Web服务。在网上找到这样一些服务,并描述其工作方式。包括服务的API以及如何访问这些数据。是否需要认证或授权?

13-2 REST和Web服务。学习 REST和XML或JSON是如何应用在现代Web服务API和应用中的。与Yahoo!报价服务器(它使用URL参数)这样的老系统相比,这三者提供了哪些额外功能?

13-3 REST和Web服务。使用Python中对REST和XML的支持构建一个应用框架,该框架允许共享并重用一些代码。这些代码包括使用如今新的Web服务和API。展示使用Yahoo!、Google、eBay、Amazon API的代码。

练习13-4~13-11涉及本章前面介绍的Yahoo!股票报价示例(stock.py)。

13-4 Web服务。更新stock.py中下载股票报价数据的内容,添加表13-1中列出的额外参数。可以直接在本章前面的stock.py基础上添加新功能。

13-5 字符串处理。读者会注意到有些返回的字段含有引号,移除这些引号。读者能想到几种移除引号的方法?

13-6 字符串处理。并不是所有股票代号长度都是4个字符。同样,并不是所有股价都在10~99.99美元之间。每日涨跌幅和百分比也是如此。对脚本进行适当的修改,让其可以应对不同长度的结果。对于所有股票输出结果依然需要是格式化的、对齐的和一致的。下面是一个示例。

C:\py>python stock.py

Prices quoted as of: Sat Oct 29 02:38:53 2011

TICKER  PRICE  CHANGE  %AGE

———  ——-  ———  ——

YHOO   16.56  -0.07  -0.42%

GOOG   600.14  +1.47  +0.25%

T     29.74  +0.60  +2.06%

AMZN   217.32  +10.54  +5.10%

BAC    7.35  +0.30  +4.26%

BRK-B   79.96 +0.065  +0.08%

13-7 文件。更新应用,将股票数据保存到文件中,而不是显示在屏幕上。附加题:修改脚本,让用户选择将股票信息显示出来还是保存到文件中。

13-8 Web服务和csv模块。原来 的stock.py文件使用普通的for循环,并手动解析数据。将其转成使用csv模块解析输入数据,类似在示例代码段中做的那样。

13-9 健壮性。Yahoo!倾向于不断修改下载的主机名。今天可能是quote.yahoo.com,明天可能会变成finace.yahoo.com。本书示例运行时的链接是“download.finance.yahoo.com”。有时主机名又会变成老的。维护一个主机列表,ping这些主机上的Web服务器,在获取股价之前先查看服务器是否可用,以此来构建一个健壮的应用。可以定期访问Yahoo!股票报价页面,从页面底部Toolbox部分的Download Data链接中抓取主机名。

13-10 扩展 API。Yahoo!报价服务器还有许多其他命令。完整的列表可以访问 http://gummy-stuff.org/Yahoo-data.htm。选择若干新的数据点,并将其集成到stock.py脚本中。

13-11 Python 3。将stock.py移植到Python 3中,重命名为stock3.py。附加题:通过某种方式让脚本同时运行在Python 2.x和3.x中,并描述用到的方法。

13-12 外汇。Yahoo!报价服务器还可以查询货币汇率。查看http:// gummy-stuff.org/forex.htm,并创建一个新的forex.py脚本,查询汇率。

13-13 股票图。Yahoo!还提供了自动生成图的方式。下面是一些示例URL,可以用于了解这个服务。

小图:

1天: http://chart.yahoo.com/t?s=GOOG

5天: http://chart.yahoo.com/v?s=GOOG

1年: http://chart.yahoo.com/c/bb/m/GOOG

大图:

1天://chart.yahoo.com/b?s=GOOG

5天: http://chart.yahoo.com/w?s=GOOG

3个月: http://chart.yahoo.com/c/3m/GOOG

6个月: http://chart.yahoo.com/c/6m/GOOG

1年: http://chart.yahoo.com/c/1y/GOOG

两年: http://chart.yahoo.com/c/2y/GOOG

5年: http://chart.yahoo.com/c/5y/GOOG

最大时间:http://chart.yahoo.com/c/my/GOOG

与练习 13-9 的健壮性类似,域名会在 chart.yahoo.com、ichart.yahoo.com 和ichar.finance.yahoo.com之间轮换,所以要使用所有这些来检查数据。创建一个应用,允许用户生成股票投资组合图。同时提供在浏览器中访问的功能,直接显示股票图页面。提示:webbrowser模块会有帮助。

13-14 历史数据。ichart.financial.yahoo.com还提供历史价格查询。使用下面这个示例的URL了解其工作方式,并创建一个应用,用于查询股票历史价格:http://chart.yahoo.com/table.csv?s=GOOG&a =06&b=12&c=2006&d=10&e=2&f=2007。

Twitter

13-15 Twitter服务。用自己的语言描述Twitter服务。介绍什么是推文,并指出推文的一些限制。

13-16 Twitter库。描述Twython和Tweepy这两个Python库的异同点。

13-17 Twitter库。了解其他可以访问Twitter API的Python库。这些库与本章用到的库有什么区别与联系?

13-18 Twitter库。如果既不喜欢Twython,也不喜欢Tweepy Python库。那么自己从头写一个与Twitter交互的安全且RESTful的库。可以从https://dev.twitter.com/docs开始。

下面的练习需要改进本章的twapi.py示例。

13-19 用户查询。添加新功能来查询用户在Twitter界面上的名称。并返回对应的ID。注意,有些用户的界面名称就是整数,所以要确保允许用户输入这些数字作为潜在的界面名称,使用ID获取用户最新的推文。

13-20 发布推文。改进搜索功能,不仅让用户搜索推文,还可以让其转发选择的推文。可以提供命令行、Web或GUI来支持这个功能。

13-21 删除推文。与练习13-20类似,让用户可以删除自己发布的推文。注意,这只是从Twitter删除推文,而推文的内容可能已经扩散到其他地方了。

13-22 关注。添加查看用户关注者(粉丝)ID以及被关注者ID的功能。

13-23 Twitter库。向twapi.py添加对不同Python/Twitter客户端库的支持。例如,可以尝试支持 python-twitter,该库参见 http://code.google.com/p/python-twitter,其他库可以在http://dev.twitter.com/docs/twitter-libraries#python中找到。

13-24 编辑个人资料。让用户可以更新自己的资料,以及上传新的头像。选做题:允许用户更新个人资料的颜色和背景图片。

13-25 计数。user_timeline()这个 Twitter 函数还支持 count 变量。默认情况下,Twitter返回用户时间线上最新的20条推文。向twapi.py添加对count和其他可选参数的支持。

13-26 直接消息。支持直接消息(Direct Message),将这些消息发送给指定用户,获取当前已发送的DM列表、已接收的DM列表,并可以删除DM。

在twapi.py示例中,能够检测并修改Twitter流,因为应用拥有所有必需的授权信息。但如果需要编写一个应用来帮助用户发送推文就是另外一回事了。在这种情况下,为了能获得access token和secret token,需要支持OAuth的完整流程。

最后几个练习需要花点时间,因为必须学习OAuth 的内容。可以先阅读这两个文档:https://dev.twitter.com/docs/auth/oauthhttps://dev.twitter.com/docs/auth/moving-from-basic-auth-to-oauth。

13-27 推文归档。创建一个Twitter归档服务。由于Twitter只保存最近的200条推文,因此很快就会丢失以前的推文。构建一个Twitter归档服务,保存已注册用户的推文。如果在网上搜索“twitter archive”或“twitter research tools”,会得到很多内容。希望通过这个练习,能够在读者中诞生下一代Twitter分析工具!

13-28 短链接、Feed轮询。为个人或工作博客创建周期扫描器(RSS或其他),当发布新博客时,自动发布一条短链接以及该博客标题的前N个单词。

13-29 其他 Web 服务。阅读关于 Google 的 Prediction API(http://code.google.com/apis/predict),尝试学习其中的“Hello World”教程。上手以后,开发一个自己的模型,来扫描不同的推文(自己或别人的都可以)。创建并训练预测模型,判断一条推文是积极的、消极的,还是中性的。当训练完成后,使用工具以相同的方式判断新的推文。为了完成这个练习,需要在 Google 的 API 控制台(http://code.google.com/apis/console)上创建一个项目,启用Google Prediction和Google Storage。如果不想创建Google账号,也可以使用其他类似的API。


[1].现在还是在用这个,没有发布新的了。——译者注

[2].没有特殊格式的非二进制文件,如XML。——译者注

[3].除非到了开发阶段,否则无需Web服务器,因此可以在后面安装。Django自带了开发服务器(刚刚已经看到),可以用于创建和测试应用。

[4].Windows系统用户可以修改PATH环境变量。首先右击“我的电脑”,接着选择“属性”。在弹出的对话框中,选择“高级”标签,最后单击“环境变量”按钮。

[5].术语硬件包括物理设备(磁盘和内存)、电源设备、冷却设备、网络设备。

[6].http://media.amazonwebservices.com/AWS_Overview.pdf。

[7].现在跳槽到Dropbox了。——译者注

[8].现已完全迁移至Python 2.7。——译者注

[9].http://labs.google.com/papers/bigtable.html。

[10].http://research.google.com/pubs/pub36971.htm。