requests请求状态保持-登录github为例
2018-06-20 本文已影响222人
北游_
模拟登录-状态保持
---- 以登录 github 为例
1 .页面分析:
-
登录页 ( https://github.com/login ) 网页源代码能找到 form 表单的提交方式是 post 请求,登录账号并且打开 Chrome 浏览器的调试工具 ( F12 - Network - all ) 查看提交请求,能到以下信息
-
提交数据为:
commit: Sign in utf8: ✓ authenticity_token: UCGHpjglqtJ70hl/3ygpPUPVGLukUm0ACcYJ47BGb4pyyz6s+V5GHQSYQp419+EYcyUfJx3j/cGJziQonKIeAw== login: email password: passwd
其中 login 和 password 的参数值为用户的邮箱和密码,每个人不一样。
分析 authenticity_token 这个参数值是没有规律的,但是细心点会发现,在登录页的网页源代码中的 form 标签中有一个 type 为 "hidden" 并且 name 参数 为 "authenticity_token" 的 <input> 子标签,其 value 参数值就是提交数据中的值。
-
2.流程说明
- 使用 requests.Session() 方法创建一个 Session 对象,这样可以做到模拟同一个会话而不用担心 Cookies 的问题。
- get 请求登录页,xpath 解析出 "authenticity_token" 的值。为避免反爬,请加上请求头 headers。
- 构建 post 请求,提交数据数据为上述的那些,请自行验证其正确性。为避免反爬,请加上请求头 headers。
- 登录成功后会自动重定向到首页,此时已经做到了session 的状态保持。
- 请求个人主页解析自己的 用户名 和 邮箱。(这一步只是测试。)
3.代码示例
-
demo版(面向流程)只是为了跑通流程,之后会改为面向对象版本。
import requests from lxml import etree # 登录页get请求URL base_url = 'https://github.com/login' # 登录post提交URL login_url = 'https://github.com/session' # github个人主页 profile_url = 'https://github.com/settings/profile' # 登录页headers headers = { 'Referer':'https://github.com/', 'Host':'github.com', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36', } # post 提交数据 post_data = { 'commit':'Sign in', 'utf8':'✓', 'login':'email@mail.com', 'password':'password', } # 保持会话式请求 s = requests.Session() # 请求登录页获取 token res_login = s.get(url=base_url, headers=headers) if res_login.status_code == requests.codes.ok: index_html = res_login.text index_html_obj = etree.HTML(index_html) # 获取 authenticity_token,在post提交时会作为一个键值对传入 token = index_html_obj.xpath('//div[@id="login"]/form/input[@name="authenticity_token"]/@value')[0] post_data['authenticity_token'] = token # 登录提交 res_index = s.post(url=login_url, headers=headers, data=post_data) if res_index.status_code == requests.codes.ok: print("登录成功,开始请求个人主页") # 进入个人中心 res_profile = s.get(url=profile_url, headers=headers) if res_profile.status_code == requests.codes.ok: print("请求个人主页成功,开始解析数据") profile_html = res_profile.text profile_obj = etree.HTML(profile_html) username = profile_obj.xpath('//div[@class="column two-thirds"]/dl[contains(@class,"form-group")]/dd/input[@id="user_profile_name"]/@value')[0] print("用户名:", username) email = profile_obj.xpath('//div[@class="column two-thirds"]/dl[2]/dd/select/option[2]/text()')[0] print("邮箱:", email) else: print("请求个人主页失败") else: print("登录失败")
-
面向对象版本
import requests from lxml import etree class GithubLogin(object): def __init__(self): # 登录页get请求URL self.base_url = 'https://github.com/login' # 登录post提交URL self.login_url = 'https://github.com/session' # github个人主页 self.profile_url = 'https://github.com/settings/profile' # 登录页headers self.headers = { 'Referer': 'https://github.com/', 'Host': 'github.com', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36', } self.session = requests.Session() # 获取登录页的 authenticity_token 值 def token(self): res = self.session.get(url=self.base_url, headers=self.headers) if res.status_code == requests.codes.ok: res_obj = etree.HTML(res.text) token_value = res_obj.xpath('//div[@id="login"]/form/input[@name="authenticity_token"]/@value')[0] return token_value def login(self, email, passwd): post_data = { 'commit': 'Sign in', 'utf8': '✓', 'login': email, 'password': '753159wt', 'authenticity_token': self.token() } # 登录 post 提交表单 res_index = self.session.post(url=self.login_url, headers=self.headers, data=post_data) if res_index.status_code == requests.codes.ok: self.repository(res_index.text) # 请求个人中心页面 res_profile = self.session.get(url=self.profile_url, headers=self.headers) if res_profile.status_code == requests.codes.ok: self.getProfile(res_profile.text) def repository(self, text): res_obj = etree.HTML(text) repo_list = res_obj.xpath('//div[@class="Box-body"]/ul/li//a/@href') for repo in repo_list: print(repo) def getProfile(self, text): res_obj = etree.HTML(text) username = res_obj.xpath('//div[@class="column two-thirds"]/dl[contains(@class,"form-group")]/dd/input[@id="user_profile_name"]/@value')[0] print("用户名:", username) email = res_obj.xpath('//div[@class="column two-thirds"]/dl[2]/dd/select/option[2]/text()')[0] print("邮箱:", email) if __name__ == '__main__': alice_login = GithubLogin() alice_login.login('email@mail.com', 'password')