Trip: 给 Requests 加上协程,一百份网络请求一份时间
Trip 是一个协程的网络库,如 Requests 一般简单的操作,程序不再被网络阻塞。
兼容 Python 2.7+ 的所有版本,主流三大操作系统。
基于两大依赖包:TRIP: Tornado & Requests In Pair
。
感谢 Tornado 与 Requests 让想法可以快速变成现实,坦诚的说,这个项目我只做了一些简单的工作。
其实上半年就写好了这个项目,结果文档拖到了今天才大致写了一些,不得不感谢一下同类项目对我的督促。
让协程变的简单
这是一个让协程变的简单的项目,你只需要这样:
import trip
@trip.coroutine
def main():
r = yield trip.get('https://httpbin.org/get', auth=('user', 'pass'))
print(r.content)
trip.run(main)
一百份请求一份时间
基于 Tornado 的协程让网络阻塞不再成为问题:(这里演示兼容用法)
import time, functools
import requests, trip
def timeit(fn):
start_time = time.time()
fn()
return time.time() - start_time
url = 'http://httpbin.org/get'
times = 10 # 100 changed for inland network delay
def fetch():
r = [requests.get(url) for i in range(times)]
return r
@trip.coroutine
def async_fetch():
r = yield [trip.get(url) for i in range(times)]
raise trip.Return(r)
print('Non-trip cost: %ss' % timeit(fetch))
print('Trip cost: %ss' % timeit(functools.partial(trip.run, async_fetch)))
# Result:
# Non-trip cost: 17.90799999237s
# Trip cost: 0.172300004959s
由于协程的特性,所有的等待时间重合在了一起。
你不需要每个请求开一个线程,主线程中一切也可以井然有序的进行。
可以想象如果你在写一个爬虫,这将节省多少时间!
让协程服务人类
基于 Requests 的操作方式让协程 HTTP 从未如此简单:(这里使用 Python3 演示 async/await )
>>> async def main():
... global r
... r = await trip.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
...
>>> trip.run(main)
>>> r.status_code
200
>>> r.headers['content-type']
'application/json'
>>> r.encoding
None
>>> r.text
u'{"authenticated": true,...'
>>> r.json()
{u'authenticated': True, u'user': u'user'}
只要你有一些 Requests 基础就可以轻松使用 Trip,协程不再遥不可及。
重现了几乎所有 Requests 的操作,最大限度的减少了你的学习成本。
以一个爬虫为例
为了不打扰正常网站的运行,这里以httpbin.org
作为目标网站。 设置 Cookies 模拟登陆,get 请求模拟爬取内容。
那么普通 Requests 是这样的:
import requests
url = 'http://httpbin.org'
s = requests.Session()
def fetch(times=10):
s.get('%s/cookies/set?name=value' % url)
r = [s.get('%s/get' % url) for i in range(times)]
print r
fetch()
使用 Trip 以后就会变成这样:
import trip
url = 'http://httpbin.org'
s = trip.Session()
@trip.coroutine
def fetch(times=10):
yield s.get('%s/cookies/set?name=value' % url)
r = yield [s.get('%s/get' % url) for i in range(times)]
print r
trip.run(fetch)
几乎不需要修改代码,爬虫就获得了协程的特性!
最后
爬虫耗时太久优化困难吗? 各种协程网络框架难以使用吗? 大型爬虫框架臃肿无法灵活定制吗?
试试 Trip,你不会后悔的!
----------------------- 以下是精选回复-----------------------
答:厉害
答:赞
答:mark
答:跟 grequests 比如何呢
答:跟 aiohttp 相比有什么优势?
答:酷
答:我是不是唯一一个想起 gevent 的 ?
答:居然最后没有广告链接。
答:据说 aiohttp 对 http 的解析拖慢了它的速度,不知道这个怎么样?
答:想起之前的一个帖子 /t/401575
答:给用户提个醒,resp.text 以及 resp.json 相关,如果 Content-Type 没有 charset,比如一个裸的 application/json,会导致 chardet 执行,chardet 执行速度比较慢(其实可以说很慢,比如一个接口一个 roundtrip 不到 1ms,跑个 chardet 都要 4-5 毫秒,就不可接受了),因此会降低整体性能(当然这个问题在 requests 里面也存在)。
答:还是 gevent 来得爽,真正的无侵入支持协程
答:666 !
答:看到兼容 3.7 还以为 3.7 出了
答:太给力了!给作者点个赞
答:great
答:看起来学习成本很低啊;刚好在找 aiohttp 的低成本解决方案,aiohttp 学习成本太高了
答:先 star 一下,有空看看源码学习一下。
----
简单看了一下,trip 基于 Tornado 的封装。所以充斥的大量 Tronado 类似的语法。
Tronado 最为人诟病之一就是语法比较恶心, 不够 pythonic...
我觉得可以把这些恶心的语法封装成 API 的形式,比如 raise Return() 这种。
答:我去,大兄弟。。我就说看源码怎么那么熟悉呢。。基本都是 requests 的 copy 啊。基本就把 send 方法改成了 Tornado 版本的啦
答:= = 报错,requests 版本兼容有问题。。。
>>> import trip
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/site-packages/trip/__init__.py", line 12, in <module>
from .api import (
File "/usr/local/lib/python2.7/site-packages/trip/api.py", line 10, in <module>
from . import sessions
File "/usr/local/lib/python2.7/site-packages/trip/sessions.py", line 21, in <module>
from requests.sessions import (
ImportError: cannot import name preferred_clock
答:大概看了一眼,实际上是把 requests 里的参数取出来再用 tornado 的 http 进行请求?
答:上周也开源了一个 Curio + Requests: Async HTTP for Humans https://www.v2ex.com/t/401739
哈哈
答:实际写爬虫的时候,同一个 ip,这样的速度,是会被封锁的,使用代理的话,一般代理商能提供的 ip 切换速度是有限的,基本跟不上这种速度。或许大量静态代理能用得上这种协程。不知道我理解的对不对。
答:我司两个后台在评论里面
0条评论