Python Requests模拟登录实现图书馆座位自动预约

作者:Xyntax 时间:2022-01-31 00:25:46 

本文实例为大家分享了Python实现图书馆座位自动预约的具体代码,供大家参考,具体内容如下

配置

通过公网主机定时运行脚本,并发送邮件到自己的qq邮箱,这样在微信就会有消息提示是否预约成功

vim /etc/crontab

设置每到早上7:01自动运行脚本即可

程序流程

(以yuyue.juneberry.cn网站为例)

  • get访问登录页面,获取cookie和表单里面的隐藏post字段

  • 构造登录post数据,加入从表单里面拿到的隐藏post字段

  • post构造后的数据,模拟登录,激活cookie(使cookie有登入权限)

  • get访问座位预约界面,激活cookie(使cookie有预约座位权限)

  • post预约请求,实现预约座位

  • 解析返回结果,判断是否成功,并邮件提醒

要点

  • requests库中的requests.session() 能够创建可传递cookies的会话

  • 拿到<input type=hidden>的数据并传递到post的数据中

  • 抓包判断网站逻辑,筛选出各个请求的参数,并在程序中实现

函数解释

  • class FUCK()主类

  • _get_date_str(self):获取当前日期,并加上一天,用这个函数构造url的特征字段(图书馆设置提前一天预约座位)

  • def _get_order_url(self):构造"预约座位"的post目标url

  • def _get_static_post_attr:这个函数解析get请求的返回页面,并从中提取出<input type=hidden>的字段,用于之后的构造post数据

  • def login(self):实现登录功能

  • def run(self):实现座位预约功能

  • def _is_success(self, text):判断预约结果

  • def error_log_once(self, text='default error (once)'):

  • def error_log(self, text='default error'):这两个函数设置程序状态为"已经出错"或者"未出错"状态(用于自动化运行的时候避免将重复的错误信息写入日志)

  • def error_log(self, text='default error'):单次将错误信息写入本地日志

  • sendmail.send_mail()邮件发送模块

代码及注释


# /bin/python
# -*- coding:utf-8 -*-
import time
import sys
import requests
from bs4 import BeautifulSoup
from mail import sendmail

__author__ = 'xy'

# 主类
class FUCK():
def __init__(self, username, password, seatNO, mailto):
"""
 以四个参数初始化,用户名,密码,要预约的座位号,接受预约结果提醒邮件的邮箱
"""
 self.username = username
 self.password = password
 self.seatNO = seatNO
 self.mailto = mailto
 self.base_url = 'http://yuyue.juneberry.cn'
 self.login_url = 'http://yuyue.juneberry.cn'
 self.order_url = self._get_order_url()

self.login_content = ''
 self.middle_content = ''
 self.final_content = ''

self.s = requests.session() # 创建可传递cookies的会话

# post data for login
 self.data1 = {
  'subCmd': 'Login',
  'txt_LoginID': self.username, # S+学号
  'txt_Password': self.password, # 密码
  'selSchool': 60, # 60表示北京交通大学
 }

# post data for order a seat
 self.data2 = {
  'subCmd': 'query',
 }

# 自定义http头,然而我在程序里并没有使用
 self.headers = {
  'Connection': 'keep-alive',
  'Content-Type': 'application/x-www-form-urlencoded',
 }

self.login()
 self.run()
 self._is_success(self.final_content)

# 怀疑程序出错时,取消下行注释,可打印一些参数
 # self._debug()

def _get_date_str(self):
 s = time.localtime(time.time())
 ########333
 date_str = str(s.tm_year) + '%2f' + str(s.tm_mon) + '%2f' + str(s.tm_mday + 1)
 date_str = date_str.replace('%2f1%2f32', '%2f2%2f1') \
  .replace('%2f2%2f29', '%2f3%2f1') \
  .replace('%2f3%2f32', '%2f4%2f1') \
  .replace('%2f4%2f31', '%2f5%2f1') \
  .replace('%2f5%2f32', '%2f6%2f1') \
  .replace('%2f6%2f31', '%2f7%2f1') \
  .replace('%2f7%2f32', '%2f8%2f1') \
  .replace('%2f8%2f32', '%2f9%2f1') \
  .replace('%2f9%2f31', '%2f10%2f1') \
  .replace('%2f10%2f32', '%2f11%2f1') \
  .replace('%2f11%2f31', '%2f12%2f1') \
  .replace('%2f12%2f32', '%2f1%2f1')
 return date_str

def _get_order_url(self):
 return "http://yuyue.juneberry.cn/BookSeat/BookSeatMessage.aspx?seatNo=101001" + self.seatNO + "&seatShortNo=01" + self.seatNO + "&roomNo=101001&date=" + self._get_date_str()

def _get_static_post_attr(self, page_content, data_dict):
 """
 拿到<input type='hidden'>的post参数,并添加到post_data中
 """
 soup = BeautifulSoup(page_content, "html.parser")
 for each in soup.find_all('input'):
  if 'value' in each.attrs and 'name' in each.attrs:
   data_dict[each['name']] = each['value'] # 添加到login的post_data中
   # self.data2[each['name']] = each['value'] # 添加到order的post_data中
 return data_dict

def _debug(self):

print self.order_url
 print self.data1
 print self.data2
 print self.headers
 print self.s.cookies

# print self.login_content
 # print self.middle_content
 print self.final_content

def login(self):
 homepage_content = self.s.get(self.base_url).content
 self.data1 = self._get_static_post_attr(homepage_content, self.data1)
 r = self.s.post(self.login_url, self.data1)
 self.login_content = r.content

def run(self):

# 这个get的意思是:原先的cookie没有预约权限,
 # 访问这个get之后,会使cookie拥有预约权限,从而执行下一个post
 self.middle_content = self.s.get('http://yuyue.juneberry.cn/BookSeat/BookSeatListForm.aspx').content

# 经测试,这个post只需要一个subCmd的参数就可以正常返回,因此不必根据get内容更新post参数
 # self.data2 = self._get_static_post_attr(middle_content, self.data2)

# 这个post请求完成了预约功能!
 r = self.s.post(self.order_url, self.data2)

self.final_content = r.content

def _is_success(self, text):
 """
 接受最终的html内容,判断是否成功,并触发日志记录和邮件提醒
 """
 if '<h5 id="MessageTip">已经存在有效的预约记录。</h5>' in text:
  self.clear_error_once('[done!] You already ordered a seat!')
 elif '<h5 id="MessageTip">选择的日期不允许预约。</h5>' in text:
  self.clear_error_once('[done!] Date is wrong!')
 elif '<h5 id="MessageTip">所选座位已经被预约。</h5>' in text:
  self.clear_error_once('[done!] This seat is not available, maybe taken by others!')
 elif '<h5 id="MessageTip">座位预约成功' in text:
  self.clear_error_once('[done!] Success! An email is sending to you!')
  sendmail.send_mail('BJTU Library Seat_NO:' + self.seatNO + 'ordered!',
       'Sending by robot. Do not reply this mail!', self.mailto)
 else:
  self.error_log_once('Error! 302 to login page')

def error_log_once(self, text='default error (once)'):
 try:
  is_error_file = open('./isopen_xy.txt', 'r')
 except:
  is_error_file = open('./isopen_xy.txt', 'w')
 if '1' not in is_error_file.read():
  print 'writting error to log...'
  self.error_log(text)
 else:
  print 'already written to log'
 is_error_file.close()
 sendmail.send_mail('BJTU_Library system error once !', 'error text!')

def error_log(self, text='default error'):
 is_error_file = open('./isopen_xy.txt', 'w')
 is_error_file.write('1\n')
 is_error_file.close()

f = open("./log_xy.txt", 'a')
 f.write(time.strftime("%Y-%m-%d %X", time.localtime()) + text + '\n')
 f.close()

def clear_error_once(self, text='success'):
 print text
 is_error_file = open('./isopen_xy.txt', 'w')
 is_error_file.write('0\n')
 is_error_file.close()

if __name__ == '__main__':
if len(sys.argv) < 5:
 print 'Usage: python library.py [username] [password] [seat_NO] [email]'
 print 'eg. python library.py S13280001 123456 003 XXXX@qq.com\n'
 print 'Any problems, mail to: i[at]cdxy.me'
 print '#-*- Edit by cdxy 16.03.24 -*-'
 sys.exit(0)
else:
 FUCK(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

来源:https://blog.csdn.net/cd_xuyue/article/details/50996681

标签:Python,登录,自动预约
0
投稿

猜你喜欢

  • 基于Opencv的图像卡通化实现代码

    2023-07-10 06:58:55
  • django 使用内置messages的操作

    2023-04-23 13:35:56
  • Python与人工神经网络:使用神经网络识别手写图像介绍

    2022-05-23 03:11:36
  • PHP中round()函数对浮点数进行四舍五入的方法

    2023-11-23 21:35:24
  • CSS框架/命名/规则 注意要点

    2008-06-03 13:07:00
  • golang接收post和get请求参数处理

    2024-04-25 15:26:54
  • PyQt5每天必学之组合框

    2023-08-30 07:55:06
  • 一文搞懂Golang 时间和日期相关函数

    2024-02-06 00:29:01
  • Python实现批量检测HTTP服务的状态

    2023-02-21 12:50:55
  • vue.js初学入门教程(1)

    2023-07-02 17:06:21
  • js实现将选中内容分享到新浪或腾讯微博

    2023-08-25 07:39:02
  • 关于Python OS模块常用文件/目录函数详解

    2023-07-04 06:30:06
  • 用ReactJS和Python的Flask框架编写留言板的代码示例

    2021-09-29 07:33:14
  • js使用栈来实现10进制转8进制与取除数及余数

    2024-04-19 09:52:12
  • Python实现字符串反转的常用方法分析【4种方法】

    2022-01-05 04:08:08
  • python matplotlib拟合直线的实现

    2023-01-27 15:42:35
  • python实现Dijkstra算法的最短路径问题

    2023-05-18 23:22:15
  • 如何将Python字符串转换为JSON的实现方法

    2022-07-11 02:58:37
  • Appium中scroll和drag_and_drop根据元素位置滑动

    2023-03-16 23:34:38
  • Python标准库之循环器(itertools)介绍

    2023-09-16 02:41:43
  • asp之家 网络编程 m.aspxhome.com