Python Requests模擬登錄實(shí)現(xiàn)圖書館座位自動(dòng)預(yù)約
本文實(shí)例為大家分享了Python實(shí)現(xiàn)圖書館座位自動(dòng)預(yù)約的具體代碼,供大家參考,具體內(nèi)容如下
配置
通過(guò)公網(wǎng)主機(jī)定時(shí)運(yùn)行腳本,并發(fā)送郵件到自己的qq郵箱,這樣在微信就會(huì)有消息提示是否預(yù)約成功
vim /etc/crontab
設(shè)置每到早上7:01自動(dòng)運(yùn)行腳本即可
程序流程
(以yuyue.juneberry.cn網(wǎng)站為例)
- get訪問(wèn)登錄頁(yè)面,獲取cookie和表單里面的隱藏post字段
- 構(gòu)造登錄post數(shù)據(jù),加入從表單里面拿到的隱藏post字段
- post構(gòu)造后的數(shù)據(jù),模擬登錄,激活cookie(使cookie有登入權(quán)限)
- get訪問(wèn)座位預(yù)約界面,激活cookie(使cookie有預(yù)約座位權(quán)限)
- post預(yù)約請(qǐng)求,實(shí)現(xiàn)預(yù)約座位
- 解析返回結(jié)果,判斷是否成功,并郵件提醒
要點(diǎn)
- requests庫(kù)中的requests.session() 能夠創(chuàng)建可傳遞cookies的會(huì)話
- 拿到<input type=hidden>的數(shù)據(jù)并傳遞到post的數(shù)據(jù)中
- 抓包判斷網(wǎng)站邏輯,篩選出各個(gè)請(qǐng)求的參數(shù),并在程序中實(shí)現(xiàn)
函數(shù)解釋
- class FUCK()主類
- _get_date_str(self):獲取當(dāng)前日期,并加上一天,用這個(gè)函數(shù)構(gòu)造url的特征字段(圖書館設(shè)置提前一天預(yù)約座位)
- def _get_order_url(self):構(gòu)造"預(yù)約座位"的post目標(biāo)url
- def _get_static_post_attr:這個(gè)函數(shù)解析get請(qǐng)求的返回頁(yè)面,并從中提取出<input type=hidden>的字段,用于之后的構(gòu)造post數(shù)據(jù)
- def login(self):實(shí)現(xiàn)登錄功能
- def run(self):實(shí)現(xiàn)座位預(yù)約功能
- def _is_success(self, text):判斷預(yù)約結(jié)果
- def error_log_once(self, text='default error (once)'):
- def error_log(self, text='default error'):這兩個(gè)函數(shù)設(shè)置程序狀態(tài)為"已經(jīng)出錯(cuò)"或者"未出錯(cuò)"狀態(tài)(用于自動(dòng)化運(yùn)行的時(shí)候避免將重復(fù)的錯(cuò)誤信息寫入日志)
- def error_log(self, text='default error'):單次將錯(cuò)誤信息寫入本地日志
- sendmail.send_mail()郵件發(fā)送模塊
代碼及注釋
# /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):
"""
以四個(gè)參數(shù)初始化,用戶名,密碼,要預(yù)約的座位號(hào),接受預(yù)約結(jié)果提醒郵件的郵箱
"""
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() # 創(chuàng)建可傳遞cookies的會(huì)話
# post data for login
self.data1 = {
'subCmd': 'Login',
'txt_LoginID': self.username, # S+學(xué)號(hào)
'txt_Password': self.password, # 密碼
'selSchool': 60, # 60表示北京交通大學(xué)
}
# post data for order a seat
self.data2 = {
'subCmd': 'query',
}
# 自定義http頭,然而我在程序里并沒(méi)有使用
self.headers = {
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
}
self.login()
self.run()
self._is_success(self.final_content)
# 懷疑程序出錯(cuò)時(shí),取消下行注釋,可打印一些參數(shù)
# 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參數(shù),并添加到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):
# 這個(gè)get的意思是:原先的cookie沒(méi)有預(yù)約權(quán)限,
# 訪問(wèn)這個(gè)get之后,會(huì)使cookie擁有預(yù)約權(quán)限,從而執(zhí)行下一個(gè)post
self.middle_content = self.s.get('http://yuyue.juneberry.cn/BookSeat/BookSeatListForm.aspx').content
# 經(jīng)測(cè)試,這個(gè)post只需要一個(gè)subCmd的參數(shù)就可以正常返回,因此不必根據(jù)get內(nèi)容更新post參數(shù)
# self.data2 = self._get_static_post_attr(middle_content, self.data2)
# 這個(gè)post請(qǐng)求完成了預(yù)約功能!
r = self.s.post(self.order_url, self.data2)
self.final_content = r.content
def _is_success(self, text):
"""
接受最終的html內(nèi)容,判斷是否成功,并觸發(fā)日志記錄和郵件提醒
"""
if '<h5 id="MessageTip">已經(jīng)存在有效的預(yù)約記錄。</h5>' in text:
self.clear_error_once('[done!] You already ordered a seat!')
elif '<h5 id="MessageTip">選擇的日期不允許預(yù)約。</h5>' in text:
self.clear_error_once('[done!] Date is wrong!')
elif '<h5 id="MessageTip">所選座位已經(jīng)被預(yù)約。</h5>' in text:
self.clear_error_once('[done!] This seat is not available, maybe taken by others!')
elif '<h5 id="MessageTip">座位預(yù)約成功' 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])
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python日期與時(shí)間模塊(datetime+time+Calendar+dateuil?)相關(guān)使用講解
這篇文章主要介紹了Python日期與時(shí)間模塊(datetime+time+Calendar+dateuil?)相關(guān)使用講解,文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09
mac PyCharm添加Python解釋器及添加package路徑的方法
今天小編就為大家分享一篇mac PyCharm添加Python解釋器及添加package路徑的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
淺談對(duì)pytroch中torch.autograd.backward的思考
這篇文章主要介紹了對(duì)pytroch中torch.autograd.backward的思考,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Python itertools庫(kù)高效迭代藝術(shù)實(shí)例探索
Python 中的?itertools?庫(kù)為迭代器操作提供了豐富的工具集,使得處理迭代對(duì)象變得更加高效和靈活,本篇文章將深入討itertools庫(kù)的常用方法,通過(guò)詳實(shí)的示例代碼演示其在解決各種問(wèn)題中的應(yīng)用2024-01-01
Python 跨.py文件調(diào)用自定義函數(shù)說(shuō)明
這篇文章主要介紹了Python 跨.py文件調(diào)用自定義函數(shù)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
python tkinter Entry控件的焦點(diǎn)移動(dòng)操作
這篇文章主要介紹了python tkinter Entry控件的焦點(diǎn)移動(dòng)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
Python?打印不帶括號(hào)的元組的實(shí)現(xiàn)
本文主要介紹了Python?打印不帶括號(hào)的元組,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04

