Python中如何使用tornado实现异步请求模拟登录?
之前写 python 的模拟客户端登录,都是使用 python 的 requests 库。因为这个库有 requests.session(),写模拟登录非常方便。
但现在我的一个 tornado 异步服务,有一个模拟登录的需求。我需要用异步,所以只能用: tornado.httpclient.AsyncHTTPClient()之类的异步方式,不能用 requests 库。
那么我应该如何用 tornado 的异步库来实现模拟登录的 session ?
Python中如何使用tornado实现异步请求模拟登录?
7 回复
看一下 trequests 吧,别人已经做好轮子了……
自己写的话,没记错的话,连 Cookie 都要自己解析……
import tornado.ioloop
import tornado.httpclient
import tornado.gen
from urllib.parse import urlencode
class AsyncLoginSimulator:
def __init__(self):
# 创建异步HTTP客户端
self.http_client = tornado.httpclient.AsyncHTTPClient()
self.login_url = "https://example.com/login" # 替换为实际登录地址
self.session_cookie = None
@tornado.gen.coroutine
def simulate_login(self, username, password):
# 1. 首先获取登录页面(如果需要CSRF token等)
try:
# 获取初始页面,提取必要的token
response = yield self.http_client.fetch(
self.login_url,
method="GET",
validate_cert=False # 仅测试用,生产环境应使用证书验证
)
# 这里假设从页面中提取了CSRF token
# 实际项目中需要用BeautifulSoup或正则表达式提取
csrf_token = self._extract_csrf_token(response.body)
# 2. 构造登录表单数据
login_data = {
'username': username,
'password': password,
'csrf_token': csrf_token, # 如果有的话
# 其他可能的表单字段
}
# 3. 发送登录POST请求
login_response = yield self.http_client.fetch(
tornado.httpclient.HTTPRequest(
url=self.login_url,
method="POST",
body=urlencode(login_data),
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
follow_redirects=False, # 手动处理重定向
validate_cert=False
)
)
# 4. 检查登录是否成功
if login_response.code == 200 or login_response.code == 302:
# 保存session cookie
if 'Set-Cookie' in login_response.headers:
self.session_cookie = login_response.headers['Set-Cookie']
# 如果是302重定向,跟随重定向获取登录后的页面
if login_response.code == 302:
redirect_url = login_response.headers.get('Location')
if redirect_url:
final_response = yield self.http_client.fetch(
redirect_url,
headers={'Cookie': self.session_cookie} if self.session_cookie else None
)
return self._check_login_success(final_response.body)
return self._check_login_success(login_response.body)
else:
return False
except tornado.httpclient.HTTPError as e:
print(f"HTTP错误: {e}")
return False
except Exception as e:
print(f"其他错误: {e}")
return False
def _extract_csrf_token(self, html_body):
"""
从HTML中提取CSRF token
实际实现需要根据目标网站的具体HTML结构来写
"""
# 这里只是示例,实际需要用解析库如BeautifulSoup
# 假设token在 <input type="hidden" name="csrf_token" value="xxx">
import re
match = re.search(r'name="csrf_token"\s+value="([^"]+)"', html_body.decode('utf-8', errors='ignore'))
return match.group(1) if match else ""
def _check_login_success(self, response_body):
"""
检查登录是否成功的逻辑
根据网站返回的内容判断
"""
body_str = response_body.decode('utf-8', errors='ignore')
# 示例:检查是否包含登录成功的标识
if "登录成功" in body_str or "Welcome" in body_str:
return True
return False
# 使用示例
@tornado.gen.coroutine
def main():
simulator = AsyncLoginSimulator()
# 异步执行登录
login_result = yield simulator.simulate_login("your_username", "your_password")
if login_result:
print("登录成功!")
print(f"Session Cookie: {simulator.session_cookie}")
else:
print("登录失败")
if __name__ == "__main__":
# 启动IOLoop
tornado.ioloop.IOLoop.current().run_sync(main)
核心要点:
- 使用
AsyncHTTPClient进行异步HTTP请求 - 先GET登录页面获取必要的token(如CSRF)
- 构造表单数据发送POST请求
- 处理重定向和保存session
- 通过
@tornado.gen.coroutine装饰器实现协程
注意: 实际使用时需要根据目标网站的具体登录机制调整,特别是token提取和登录成功判断逻辑。
总结: 用AsyncHTTPClient配合协程装饰器就能搞定异步登录。
我咋没搜到这个东西。
请用 Google ……
https://github.com/1stvamp/trequests
可能有点老了,可以根据这个思路 fork 一个。
requests 的 session 无非就是帮你实现了方便的 cookie 管理,让你下次访问该网站的时候自动在 header 里面加上了它的 cookie , tornado 的每个请求都是异步的,所以感觉可以把每次请求获取到的 cookie 存到缓存(比如 redis )里面,每次进行下一步的请求时就可以先从缓存里面读 cookie 然后更新 header 。
aiohttp 也是异步的


