项目背景
- 本项目设立目的是为了通过脚本,实现学校体育场馆的“秒约”。便于同学瞬间抢到热门时间段的体育场。
- 服务器工作峰值时浏览器可能会卡死,因此例如selenium等需要加载浏览器界面的库可能会降低效率。
- 采用requests库直接向服务器发送请求,效率更高。
项目的组成部分
通过selenium库模拟登录获取cookies
如果在预约界面,点击“预约”按钮。然后抓包获取headers
、cookies
等参数,很有可能只获取的一部分cookies
。
如果传递的cookies
参数不够全面,很有可能重新跳转至登录界面。requests.post()
返回的内容如下:
(返回跳转到登录网址的代码,而不是原网址内容)
而如果通过requests库,走正常流程登录时,登录系统用户名及密码通常进行过加密。使得我们不知道如何向系统传递参数进行登录。(如图)
因此我们可以通过用selenium模拟用户成功登录后,通过selenium获取cookies传递给requests,借壳上市,实现requests对页面的成功访问。同时也不会影响在抢预约时的效率。
此外需要注意的是,建议采用requests.Session()
来进行访问。Session
对象可以获取响应的cookies值并自动进行记录,可以保持一个持续会话的状态,避免后面访问网址需要多次传递cookies
具体代码如下:
print('开始自动化操作')
# 绕过人机检查
options = webdriver.EdgeOptions()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
# 采用Edge驱动
wb = webdriver.Edge(options = options,service=Service(r'D:\软件\PyCharm Community Edition 2023.1.3\edgedriver_win64\msedgedriver.exe'))
# 绕过人机检查
wb.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
# 直接获取预约界面,随后跳转至登录界面。完成登录后,会再跳转至预约界面。
wb.get(r'http://XXX.XXX.edu.cn/eduplus/order/initOrderIndex.do?sclId=1')
# 设置隐式等待5秒
wb.implicitly_wait(5)
# 在登录界面,找到用户名和密码框
user = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[1]/input')
password = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[2]/input[1]')
login = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[5]')
# 输入用户名及密码完成登录
user.send_keys('XXX')
password.send_keys('XXXX')
login.click()
time.sleep(3)
# 打印wb中所有的cookies
print(wb.get_cookies())
# 设置访问头
headers = {
略...
}
# 创建session对话对象
se = requests.Session()
# 将wb中所有的cookies传递给session对象
for co in wb.get_cookies():
requests.utils.add_dict_to_cookiejar(se.cookies, {co['name']: co['value']})
# 撤销wb对象内存
wb.close()
# 打印session对象中所有的cookies
print(se.cookies)
# 访问预约网址
r1 = se.get(r'http://.XXX.edu.cn/eduplus/order/initOrderIndex.do?sclId=1', headers=headers)
# 打印预约网址源码,打印成功即成功登录
print(r1.text)
向服务器发送请求获取验证码并识别
至此,即将进入本项目第二个难点。获取验证码及识别。
在选好场地和时间后,需要输入手机号及验证码才能点击预约。(如图)
通过抓包,我们能够清楚的知道请求网址及传递的参数。(如图)
现在唯一需要做的就是验证码的识别。通过开发者工具确定验证码图片位置,随后通过Session
对象访问图片地址,并保存在本地。、
实现代码如下:
# 访问验证码地址
r2 = se.get(r'http://yuyue.XXX.XXX.cn/eduplus/validateimage', headers = headers)
image_path = 'test' + str(random.randint(0,99999)) + '.jpg'
with open(image_path, 'wb') as f:
f.write(r2.content)
随后通过第三方接口,实现对验证码的识别及输出。
(此次我选择的是图灵,虽然收费但是十分便宜)
实现代码如下:
# 图灵官方提供的API接口
def b64_api(username, password, img_path, ID):
with open(img_path, 'rb') as f:
b64_data = base64.b64encode(f.read())
b64 = b64_data.decode()
data = {"username": username, "password": password, "ID": ID, "b64": b64, "version": "3.1.1"}
data_json = json.dumps(data)
result = json.loads(requests.post("http://www.fdyscloud.com.cn/tuling/predict", data=data_json).text)
return result
# 通过图灵官方接口,识别验证码
result = b64_api(username="XXX", password="XXX", img_path=image_path, ID="XXXX")
validate_code = result.get('data').get('result')
向服务器发送请求,实现预约
最后汇总参数向服务器发起预约。以下为项目整体代码:文章来源:https://www.toymoban.com/news/detail-764963.html
import time
import random
import json
import base64
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
import requests
# 图灵验证码识别官方接口
def b64_api(username, password, img_path, ID):
with open(img_path, 'rb') as f:
b64_data = base64.b64encode(f.read())
b64 = b64_data.decode()
data = {"username": username, "password": password, "ID": ID, "b64": b64, "version": "3.1.1"}
data_json = json.dumps(data)
result = json.loads(requests.post("http://www.fdyscloud.com.cn/tuling/predict", data=data_json).text)
return result
print('开始自动化操作')
# 绕过人机检查
options = webdriver.EdgeOptions()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
# 采用Edge驱动
wb = webdriver.Edge(options = options,service=Service(r'D:\软件\PyCharm Community Edition 2023.1.3\edgedriver_win64\msedgedriver.exe'))
# 绕过人机检查
wb.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
# 直接获取预约界面,随后跳转至登录界面。完成登录后,会再跳转至预约界面。
wb.get(r'http://XXX.XXX.edu.cn/eduplus/order/initOrderIndex.do?sclId=1')
# 设置隐式等待5秒
wb.implicitly_wait(5)
# 在登录界面,找到用户名和密码框
user = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[1]/input')
password = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[2]/input[1]')
login = wb.find_element(By.XPATH, '/html/body/div/div[2]/div[3]/div/div[4]/div/form/p[5]')
# 输入用户名及密码完成登录
user.send_keys('XXX')
password.send_keys('XXX')
login.click()
time.sleep(3)
# 打印wb中所有的cookies
print(wb.get_cookies())
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Host': 'XXX.XXX.edu.cn',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
}
# 创建session对话对象
se = requests.Session()
# 将wb中所有的cookies传递给session对象
for co in wb.get_cookies():
requests.utils.add_dict_to_cookiejar(se.cookies, {co['name']: co['value']})
# 撤销wb对象内存
wb.close()
# 打印session对象中所有的cookies
print(se.cookies)
# 访问预约网址
r1 = se.get(r'http://XXX.XXX.edu.cn/eduplus/order/initOrderIndex.do?sclId=1', headers=headers)
# 打印预约网址源码,打印成功即成功登录
print(r1.text)
# 访问验证码网址
r2 = se.get(r'http://XXX.XXX.edu.cn/eduplus/validateimage', headers = headers)
image_path = 'test' + str(random.randint(0,99999)) + '.jpg'
with open(image_path, 'wb') as f:
f.write(r2.content)
# 通过图灵官方接口,识别验证码
result = b64_api(username="XXX", password="XXX", img_path=image_path, ID="XXX")
validate_code = result.get('data').get('result')
# 相关预约参数
data={
'useTime': 'XXX', # 预约时段
'预约项目': 'XXX', # 时段项目, 10 为九龙湖羽毛球
'allowHalf': '2',
'validateCode': validate_code, # 验证码
'phone': 'XXX', # 手机号
'remark': '' # 备注
}
# 向网站发出预约
r3 = se.post('http://XXX.XXX.edu.cn/eduplus/order/order/getOrderInfo.do?sclId=1', headers=headers, data=data)
input('结束')
新人项目,欢迎指教交流!文章来源地址https://www.toymoban.com/news/detail-764963.html
到了这里,关于selenium+requests 实现网页跳转登录及爬取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!