破解 Twitter Search API 的请求限制

分类:笔记 标签:API, Google App Engine, Twitter, hack

You have been rate limited. Enhance your calm.

在Google App Engine上使用过Twitter Search API 的人可能会经常遇到这个头疼的问题,就是API的请求限额经常被刷爆。

出现这个问题有两个原因:首先要从urlfetch的实现原理来看。因为GAE是个云平台,它将资源整合分配。每次通过urlfetch发出一个请求时,首先GAE会在IP地址池里取得一个IP,然后用这个IP访问网络。而IP地址池中的IP都是给所有应用共享的,你也用,我也用,大家都用。另外一个原因,就是Twitter Search API的请求策略是按照 每IP*小时(基于IP的请求限制) 计算,而不是REST API的按照 每用户*小时(基于认证的请求限制)计算。由于GAE发出请求的IP是所有应用共享的,所以给这些IP的请求限额会必然会被海量的应用连续不断的请求刷爆。

有人提出过给search api加入认证(authenticate)就可以实现 每(用户*小时) 的请求策略。但经过实践证明这样做是不行的。

这个问题困扰了我很久,搜索各种资料都没找到什么有用的结果。后来发现了一个一直没有注意到的现象,那就是twitter官网的新界面搜索功能特别好用,而且只要修改了hosts,就可以用https在墙内使用。可Search API所用的域名search.twitter.com没有https支持,而且我在hosts中也没有设置任何search.twitter.com这个域名的IP。那这个搜索结果是怎么传过来的呢? 如果twitter官网使用的是 search.twitter.com 这个域名作为搜索api的地址,那肯定search.twitter.com也支持https,但事实上是不行的。显然,twitter官网肯定使用了别twitter.com域名来搜索!

接下来就简单了,用Firefox/chrome打开https://twitter.com,观察网络活动。于是抓到了一个名叫 pheonix_search 的隐藏API。大概是这样的:


一、API地址
https://twitter.com/phoenix_search.phoenix


二、参数
q - 必须,要搜索的关键字。
since_id - 可选,返回结果的id应全都大于since_id。
page - 可选,这是一个很奇怪的参数,twitter用它来获取搜索结果的下一页。它本身又包含了很多其他参数。
include_entities - 可选,是否包含推文的“实体”。
contributor_details - 未知,在Httpfox中观察它的值一直是:true
domain - 未知,在Httpfox中观察它的值一直是:https://twitter.com
format - 未知,在Httpfox中观察它的值一直是:phoenix

详解page参数:
page是个很奇怪的参数,它本身又包含了很多其他参数(大致)。
   page - 这个不是上边说的page而是真正的页码。
   max_id - 返回结果应全都小于max_id
   rpp - 每页返回的推文个数
   q - 请求关键字
举例(注意这里page参数必须是urlencode过的):
page=%3Fpage%3D2%26max_id%3D44034426279165952%26rpp%3D20%26q%3Dtwitdao
解码后:
?page=2&max_id=44034426279165952&rpp=20&q=twitdao


三、返回数据
json格式,
{
	"statuses":[...], //推文实体数组
	"next_page":false, //下一页,也就是翻页时的page参数
	"error":null //出错信息
}


四、用法
假设要搜索 "twitdao" ,
第一次请求:
https://twitter.com/phoenix_search.phoenix?q=twitdao&format=phoenix
刷新(最新符合关键字的推文):
https://twitter.com/phoenix_search.phoenix?q=twitdao&since_id=43865302966075392&format=phoenix
翻页(更早符合关键字的推文):
https://twitter.com/phoenix_search.phoenix?q=twitdao&page=%3Fpage%3D2%26max_id%3D44034426279165952%26rpp%3D20%26q%3Dtwitdao&format=phoenix

实例代码:
http://code.google.com/p/twitdao/source/browse/trunk/twitter.py?spec=svn62&r=61#238


五、一些特性
1、可以通过加入认证提升Rate Limit
这也是本文主要的目的,就是破解 Twitter Search API 的请求限制。经过一番测试,在pheonix_search的请求中加入OAuth header后,果然可以从“基于IP的请求限制”转化成“基于认证的请求限制”!
2、返回真正的推文实体列表
pheonix_search API 的另外一个优点就是它返回的推文实体是完整的,与home_timline方法返回的推文实体相同。而普通Search API返回的推文实体并不是完整的,并且有些id数据可能会不正确。
Twitter Search API文档中的警告:
Warning: The user ids in the Search API are different from those in the REST API (about the two APIs). This defect is being tracked by Issue 214. This means that the to_user_id and from_user_id field vary from the actualy user id on Twitter.com. Applications will have to perform a screen name-based lookup with the users/show method to get the correct user id if necessary.


六、测试办法
如何知道一个API是“基于IP的请求限制”还是“基于认证的请求限制”呢?每次请求 twitter api 的时候都会返回几个有关请求限制(Rate Limit)的http首部,主要有:
X-RateLimit-Limit - 每小时限制请求数
X-RateLimit-Remaining - 剩余的请求数
X-RateLimit-Reset - 请求限制重置时刻

假设所有请求都用同一个IP。

1、首先,对api发出请求,假设返回:
X-RateLimit-Limit: 150
X-RateLimit-Remaining: 149
X-RateLimit-Reset: 1299344165

2、然后,换一个用户,再次对该api发出请求,
--若返回:
X-RateLimit-Limit: 150
X-RateLimit-Remaining: 148 (仍然在减少)
X-RateLimit-Reset: 1299344165 (注意这里不能变,如果变了要重新开始)
继续更换用户并发出请求,如果X-RateLimit-Remaining持续减少,并且X-RateLimit-Reset一直未变。
则该api请求限制是“基于IP的请求限制”。
--若返回:
X-RateLimit-Limit: 150
X-RateLimit-Remaining: 149 (重新开始计数)
X-RateLimit-Reset: 1299399168 (变了!)
继续更换用户并发出请求,如果X-RateLimit-Remaining按照的减少是基于用户的,并且每个用户都有自己独有的X-RateLimit-Reset。
则该api请求限制是“基于认证的请求限制”。


参考:
  1. https://dev.twitter.com/pages/rate-limiting
  2. https://groups.google.com/d/msg/google-appengine/okY7XSO3EFQ/37AvPss4K88J
  3. http://codeleaks.net/2010/08/19/%E8%AF%B4%E8%AF%B4-twitter-for-iphone-%E7%9A%84-n-%E5%AE%97-%E2%80%9C%E7%BD%AA%E2%80%9D/
  4. http://dev.twitter.com/pages/tweet_entities
0 0
你可能还会对下列文章感兴趣:

1条评论(不来一发么?) 顺序排列 倒序排列

    想说点什么呢?

    您需要登录您的Google账号才能进行评论。