前言

  开学第一天学校突然规定图书馆需要预约座位,正好大四开学时间也不是那么紧张,遂和室友突然萌生出写一个自动预约座位的脚本。而显然对于我这种第一次写脚本的超级小白来说,过程是异常艰辛。本篇文章我会把自己的编写流程记录在这里,也算是对这个小脚本的一个总结。第一次写博客缺乏经验,也欢迎大家纠正整个过程中存在的问题。


一、编写思路

  整个编写思路较为简单,首先是登录到学校的图书馆预约管理系统,这里要找到登录界面对应的URL。一般来说找到登录界面浏览器上方网址栏对应的地址即可,不过稳妥起见可以通过查看浏览器自带的抓包分析工具(以Chrome为例,点击右键,选择检查,在检查界面中选择Network)来看请求的URL。登录成功后,先手动操作一遍预约流程,每操作一步在检查界面中的Network部分查看有哪些请求包以及服务器相应的响应。接下来只需要按照抓包工具解析好的各种HTTP请求包的Header,Data等部分,按照预约流程的每一步,来用我们脚本模拟该HTTP请求即可,最后测试一下大功告成!

二、具体实现

1. 导入模块

  由于本脚本涉及网络请求,文本处理等功能,因此需要提前导入如下模块: 

import requests
import json
import re
import time
import datetime

2. 登录部分

  登录部分我一开始的思路是向web服务器提交我的用户名与密码,但是通过抓包分析发现每次请求的Header部分都有一个变化的值,导致每次POST请求后,响应头中的Location都没有指向下一个需要请求的地址。我尝试了很长时间也没有成功,于是打算通过浏览器的cookies进行登录。一般来说登录成功后下次再次登录,浏览器会通过本地存储的cookies来完成自动登录过程,无需再次输入密码。如果想查看cookies可以去翻一翻浏览器存储cookies的地方。当然也可以自动登录一下预约网址,通过查看抓包分析工具,找到相应的cookies。这里我的cookies已经作为GET请求的header部分。 
 
在这里插入图片描述
 
  因此在我们脚本的的请求部分将cookies部分作为Header的一部分即可。这一部分代码为: 

def login(cookies=None):
    session = requests.session()
    if cookies is None:
        cookies = ''  # 这里是cookies

    header = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, "
                      "like Gecko)Chrome/92.0.4515.159 Safari/537.36",
        'Connection': 'keep-alive',
        'Cookie': cookies
    }
    order_page = ''  # 这里是预约系统的URl地址
    res = session.get(url=order_page, headers=header)
    verify_login(res.url)
    return session, header

3. 预约部分

  预约部分的本质与登录部分类似,即都是通过HTTP请求来完成相应的预约操作。具体的实现不同学校是不一样的,因此我以我们学校为例,我们学校的预约系统是这个样子: 
 
在这里插入图片描述
 
  在预约系统上进行手动预约,然后通过浏览器内置的包分析工具获取每一步操作所对应的请求包,同时记得查看对应的相应,通过服务器的相应我们可以查看是否预约成功以及是否需要提供一些验证信息。例如我们学校在预约的时候需要输入验证码,因此提供预约信息后需要对验证码进行处理,不过大致的思路就是如此。整体脚本编写完成后,我还对一些功能进行完善,下面附上全部代码: 

# -*- coding = utf-8 -*-

import requests
import json
import re
import time
import datetime


def main():
    cur_time = time.strftime("%H:%M:%S", time.localtime())
    flag = True
    while cur_time < '12:30:00':
        if flag is True:
            print('当前时段暂不可预约')
            flag = False
        cur_time = time.strftime("%H:%M:%S", time.localtime())
    cur_date = datetime.date.today()
    tor_date = cur_date + datetime.timedelta(days=1)
    tor_date = str(tor_date)
    session, header = login()
    v_number = validation(session, header)
    reserve(v_number, session, header, tor_date, 50)


# 用于验证登录是否成功
def verify_login(url):
    order_page = ''
    if url == order_page:
        print('登录成功')
    else:
        print('登录失败')


# 该登录函数利用客户端的cookie信息完成登录,首次使用需要手动登录并获取cookie
def login(cookies=None):
    session = requests.session()
    if cookies is None:
        cookies = ''  # 这里是cookies

    header = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, "
                      "like Gecko)Chrome/92.0.4515.159 Safari/537.36",
        'Connection': 'keep-alive',
        'Cookie': cookies
    }
    order_page = ''  # 这里是预约系统的URl地址
    res = session.get(url=order_page, headers=header)
    verify_login(res.url)
    return session, header


# 该函数用于获得验证码的取值
def validation(session, header):
    valid_page = ''
    val_params = {
        'act': 'SetNumberCode'
    }
    res = session.get(url=valid_page, params=val_params, headers=header)
    res_text = json.loads(res.text)
    pic_num = []
    v_number = 0
    for i in range(4):
        tmp = re.search(r'(\D*)(\d)(\D*)', res_text['data'][i])
        pic_num.append(int(tmp.group(2)))
    if res_text['data'][4] == '-':
        v_number = pic_num[0] * 10 + pic_num[1] - (pic_num[2] * 10 + pic_num[3])
    else:
        v_number = pic_num[0] * 10 + pic_num[1] + (pic_num[2] * 10 + pic_num[3])
    return v_number


# 目前仅支持西土城校区401室,4S-001-4S-072号座位的选择
# 若未指定座位号则默认搜索所有可用座位
def reserve(v_number, session, header, date, seat_num=None):
    tot_num = 73
    flag = True
    reserve_page = ''
    if seat_num is not None:
        dev_id = seat_num + 105107154
        res_param = {
            'dialogid': '',
            'dev_id': str(dev_id),
            'lab_id': '',
            'kind_id': '',
            'room_id': '',
            'type': 'dev',
            'prop': '',
            'test_id': '',
            'term': '',
            'Vnumber': str(v_number),
            'classkind': '',
            'test_name': '',
            'start': date + ' 08:10',
            'end': date + ' 21:00',
            'start_time': '0810',
            'end_time': '2100',
            'up_file': '',
            'memo': '',
            'act': 'set_resv'
        }
        res = session.get(url=reserve_page, headers=header, params=res_param)
        tmp = json.loads(res.text)
        if tmp['msg'] == '操作成功!':
            print('------------------------')
            print('预约成功')
            print('座位号:', '4S-%03d' % seat_num)
            print('------------------------')
            return
        else:
            print(tmp['msg'])
            print('正在搜索其他座位...')
            flag = False
    for seat_num in range(20, tot_num):
        dev_id = seat_num + 105107154
        res_param = {
            'dialogid': '',
            'dev_id': str(dev_id),
            'lab_id': '',
            'kind_id': '',
            'room_id': '',
            'type': 'dev',
            'prop': '',
            'test_id': '',
            'term': '',
            'Vnumber': str(v_number),
            'classkind': '',
            'test_name': '',
            'start': date + ' 08:00',
            'end': date + ' 21:00',
            'start_time': '0800',
            'end_time': '2100',
            'up_file': '',
            'memo': '',
            'act': 'set_resv'
        }
        res = session.get(url=reserve_page, headers=header, params=res_param)
        tmp = json.loads(res.text)
        if tmp['msg'] == '操作成功!':
            print('------------------------')
            print('预约成功')
            print('座位号:', '4S-%03d' % seat_num)
            print('------------------------')
            return
        else:
            if flag is True:
                print('搜索全部座位...')
                flag = False
            else:
                print('进度:%.2f%%' % (seat_num * 100.0 / (tot_num - 1)))
    print('当天已无可预约座位')


if __name__ == "__main__":
    start_time = time.time()
    main()
    end_time = time.time()
    print('耗时:%.2fs' % (end_time - start_time))
Logo

快速构建 Web 应用程序

更多推荐