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)

核心要点:

  1. 使用AsyncHTTPClient进行异步HTTP请求
  2. 先GET登录页面获取必要的token(如CSRF)
  3. 构造表单数据发送POST请求
  4. 处理重定向和保存session
  5. 通过@tornado.gen.coroutine装饰器实现协程

注意: 实际使用时需要根据目标网站的具体登录机制调整,特别是token提取和登录成功判断逻辑。

总结: 用AsyncHTTPClient配合协程装饰器就能搞定异步登录。

我咋没搜到这个东西。

请用 Google ……
https://github.com/1stvamp/trequests
可能有点老了,可以根据这个思路 fork 一个。

requests 的 session 无非就是帮你实现了方便的 cookie 管理,让你下次访问该网站的时候自动在 header 里面加上了它的 cookie , tornado 的每个请求都是异步的,所以感觉可以把每次请求获取到的 cookie 存到缓存(比如 redis )里面,每次进行下一步的请求时就可以先从缓存里面读 cookie 然后更新 header 。

aiohttp 也是异步的

aiohttp 是 python3.X 的。。。

回到顶部