requests模块高级应用---模拟登录
- 模拟登录目的:
爬取某些用户的用户信息。
- 需求说明:
对古诗词网进行模拟登录。
- 编码流程:
- 爬取首页数据,获取验证码信息并保存
- 通过超级鹰对验证码进行自动识别
- 点击登录后获取到登录页面的URL,模拟对登录页面发起post请求,参数中携带验证码(动态变化的)
- 直接献上代码:
# @Time : 2022/1/20 0020 9:56 # @Author : Tzy0425 # @File : 古诗词网实现模拟登陆.py import requests from lxml import etree from chaojiying import Chaojiying_Client # 封装识别验证码图片的函数 def getCode(filePath): chaojiying = Chaojiying_Client('超级鹰用户账号', '超级鹰用户密码', '软件ID') im = open('code_gushi.jpg', 'rb').read() # 本地图片文件路径 return chaojiying.PostPic(im, 1004) # 对验证码图片进行捕获和识别 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } url = 'https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx' page_text = requests.get(url=url,headers=headers).text tree = etree.HTML(page_text) code_src = 'https://so.gushiwen.cn' + tree.xpath('//*[@id="imgCode"]/@src')[0] code_data = requests.get(url=code_src,headers=headers).content with open('./code_gushi.jpg','wb') as fp: fp.write(code_data) # 解析动态参数 __VIEWSTATE = tree.xpath('//*[@id="__VIEWSTATE"]/@value')[0] __VIEWSTATEGENERATOR = tree.xpath('//*[@id="__VIEWSTATEGENERATOR"]/@value')[0] code_text = getCode('code_gushi.jpg') code = code_text.get('pic_str') print(code) login_url = 'https://so.gushiwen.cn/user/login.aspx?from=http%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx' data = { '__VIEWSTATE':__VIEWSTATE, '__VIEWSTATEGENERATOR':__VIEWSTATEGENERATOR, 'from':' http://so.gushiwen.cn/user/collect.aspx', 'email':' 自己的账号', 'pwd':' 自己的密码', 'code':code, 'denglu':' 登录', } # 使用session进行post请求的发送 response = requests.post(url=login_url,data=data,headers=headers) login_page_text = response.text print(response.status_code) with open('./gushici.html','w',encoding='utf-8') as fp: fp.write(login_page_text)
正常情况下,上述代码便可成功的模拟用户进行登录,运行后生成的HTML应为登录成功后跳转的首页,但运行后却发现,返回的状态码虽然是200,但生成的页面却是登录页面而不是登录成功后的用户界面,Why???
别急,从以下几点解释后就会明白。
- http / https协议特性:
无状态,也就是当用户向服务器发出请求后,服务端并不会记录当前用户的相关状态。
- 没有请求到对应页面数据的原因:
所以说,代码中发起的第二次基于个人主页页面(即登录成功后跳转到的页面)请求的时候,前提是已经登录成功,但由于http / https协议无状态的特性,服务端并不知道该请求是基于登录状态下的请求,所以它会重新返回给你登录界面,那么服务端是通过什么记录客户端的相关状态的呢? ------ cookie
- cookie:用来让服务端记录客户端的状态
- 手动处理:通过抓包工具获取cookie值,将该值封装到headers中。(不建议,因为有的cookie是动态变化的,而且操作繁琐)
- 自动处理:首先我们要知道,cookie值是来源于在登录时发送的post请求后,由服务端创建。其次,要用到session会话对象,它可以进行请求的发送(编码方式和requests相同),并且如果在请求的过程中产生了cookie,则该cookie会被自动保存在session对象中。
- session使用流程:
(1)创建一个session对象:session = requests.Session()
(2)使用session对象进行模拟登录post请求的发送
(3)session对象对个人主页对应的get请求进行发送
那么,经过分析,其实只需要把之前通过requests进行请求,改为通过session进行请求即可,对于代码来说就是在最开始创建session对象,然后把后面的requests的部分改为session即可。
最后,在介绍一种反爬机制与对应的反反爬策略:
- 代理:存在一种反爬机制,是通过限制单位时间内ip的访问次数,反反爬策略就用到了ip代理。
- 代理相关的网站:快代理、西祠代理、www.goubanjia.com
- 代理ip的类型:http与https,分别应用于对应的协议当中
- 代理ip的匿名度:
(1)透明:服务器知道该次请求使用了代理,也知道请求对应的真实ip
(2)匿名:服务器知道使用了代理,但不知道真实ip
(3)高匿:服务器不知道使用了代理,更不知道真实的ip
相关代码:
只需要在requests的请求参数中添加proxies,然后赋一个代理ip即可。
import requests
url = 'https://www.baidu.com/s?wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers,proxies={"https":'222.110.147.50:3128'}).text
with open('ip.html','w',encoding='utf-8') as fp:
fp.write(page_text)