@ -0,0 +1,6 @@ | |||||
from flask import Flask | |||||
app = Flask(__name__) | |||||
app.config.from_object('config') | |||||
app._static_folder = "/autobook/app/static" | |||||
from app import views |
@ -0,0 +1,43 @@ | |||||
from flask_wtf import FlaskForm | |||||
from wtforms import StringField, PasswordField, SubmitField, SelectField | |||||
from wtforms.validators import DataRequired | |||||
class Book(FlaskForm): | |||||
username = StringField(label='student_id', | |||||
validators=[DataRequired()], | |||||
render_kw={ | |||||
'placeholder': 'Student ID', | |||||
'class': 'input_text' | |||||
}) | |||||
password = PasswordField(label='password', | |||||
validators=[DataRequired()], | |||||
render_kw={ | |||||
'placeholder': 'Password', | |||||
'class': 'input_text' | |||||
}) | |||||
email = StringField(label='email', | |||||
validators=[DataRequired()], | |||||
render_kw={ | |||||
'placeholder': 'Email', | |||||
'class': 'email' | |||||
}) | |||||
area = SelectField(label='area', | |||||
validators=[DataRequired()], | |||||
render_kw={ | |||||
'class': 'form-control' | |||||
}, | |||||
choices=[('F1_A','一楼A区'), | |||||
('F1_B','一楼B区'), | |||||
('F1_digital_reading_area','一楼数字阅览区'), | |||||
('F1_study_area','一楼自习区'), | |||||
('F3_foreign_books','三楼外文图书借阅区'), | |||||
('F3_newspaper','三楼报刊区'), | |||||
('F4_liberal_art_books_A','四楼中文文科图书借阅区A'), | |||||
('F4_liberal_art_books_B','四楼中文文科图书借阅区B'), | |||||
('F4_liberal_art_books_C','四楼中文文科图书借阅区C'), | |||||
('F5_liberal_art_books','五楼中文文科图书借阅区'), | |||||
('F6_science_books','六楼中文理科图书借阅区') | |||||
], | |||||
default='F1_A' | |||||
) | |||||
submit = SubmitField('confirm') |
@ -0,0 +1,193 @@ | |||||
body { | |||||
font-family: 'Montserrat', sans-serif; | |||||
text-rendering : optimizeLegibility; | |||||
-webkit-font-smoothing : antialiased; | |||||
} | |||||
#login-bg.container-fluid { | |||||
padding: 0; | |||||
height: 100%; | |||||
position: absolute; | |||||
} | |||||
/* Background image an color divs*/ | |||||
.bg-img , .bg-color { | |||||
min-width: 50%; | |||||
vertical-align: top; | |||||
padding: 0; | |||||
margin-left: 0; | |||||
height: 100%; | |||||
background-color: #CAF0D3; | |||||
display: inline-block; | |||||
overflow: hidden; | |||||
} | |||||
.bg-color { | |||||
margin-left: -5px; | |||||
} | |||||
.bg-img { | |||||
background-image: url(/static/bg-image.jpeg); | |||||
background-size: cover; | |||||
} | |||||
#login{ | |||||
padding-top: 10%; | |||||
text-align: center; | |||||
text-transform: uppercase; | |||||
} | |||||
.login { | |||||
width: 100%; | |||||
height: 500px; | |||||
background-color: #fff; | |||||
padding: 15px; | |||||
padding-top: 30px; | |||||
} | |||||
.login h1 { | |||||
margin-top: 30px; | |||||
font-weight: bold; | |||||
font-size: 60px; | |||||
letter-spacing: 3px; | |||||
} | |||||
.login form { | |||||
max-width: 420px; | |||||
margin: 30px auto; | |||||
} | |||||
.login .btn { | |||||
border-radius: 50px; | |||||
text-transform: uppercase; | |||||
font-weight: bold; | |||||
letter-spacing: 2px; | |||||
font-size: 20px; | |||||
padding: 14px; | |||||
background-color: #00B72E; | |||||
} | |||||
.form-group input { | |||||
font-size: 20px; | |||||
font-weight: lighter; | |||||
border: none; | |||||
background-color: #F0F0F0; | |||||
color: #465347!important; | |||||
padding: 26px 30px; | |||||
border-radius: 50px; | |||||
transition : 0.2s; | |||||
} | |||||
/* Form check styles*/ | |||||
.form-check { | |||||
padding: 0; | |||||
text-align: left; | |||||
} | |||||
.form-check label { | |||||
vertical-align: top; | |||||
padding-top: 5px; | |||||
padding-left: 5px; | |||||
font-size: 15px; | |||||
color: #606060; | |||||
font-size: 14px; | |||||
} | |||||
.forgot-password { | |||||
text-align: right; | |||||
float: right; | |||||
font-weight: bold; | |||||
} | |||||
.forgot-password a { | |||||
color: #00B72E; | |||||
opacity: 0.6; | |||||
} | |||||
.forgot-password a:hover { | |||||
opacity: 1; | |||||
} | |||||
/* Switch styles */ | |||||
.switch { | |||||
position: relative; | |||||
display: inline-block; | |||||
width: 60px; | |||||
height: 30px; | |||||
} | |||||
/* Hide default HTML checkbox */ | |||||
.switch input {display:none;} | |||||
/* The slider */ | |||||
.slider { | |||||
position: absolute; | |||||
cursor: pointer; | |||||
top: 0; | |||||
left: 0; | |||||
right: 0; | |||||
bottom: 0; | |||||
background-color: #F0F0F0; | |||||
-webkit-transition: .4s; | |||||
transition: .4s; | |||||
border-radius: 30px; | |||||
} | |||||
.slider:before { | |||||
position: absolute; | |||||
content: ""; | |||||
height: 22px; | |||||
width: 22px; | |||||
left: 4px; | |||||
bottom: 4px; | |||||
background-color: white; | |||||
-webkit-transition: .4s; | |||||
transition: .4s; | |||||
border-radius: 50%; | |||||
} | |||||
input:checked + .slider { | |||||
background-color: #00B72E; | |||||
} | |||||
input:focus + .slider { | |||||
box-shadow: 0 0 1px #00B72E; | |||||
} | |||||
input:checked + .slider:before { | |||||
-webkit-transform: translateX(30px); | |||||
-ms-transform: translateX(30px); | |||||
transform: translateX(30px); | |||||
} | |||||
/* Media queries */ | |||||
@media(max-width: 500px) { | |||||
.bg-img , .bg-color { | |||||
min-width: 100%; | |||||
height: 50%; | |||||
margin: 0; | |||||
} | |||||
.forgot-password { | |||||
text-align: right; | |||||
float: left; | |||||
padding: 20px 0; | |||||
} | |||||
#login { | |||||
padding-top: 50px; | |||||
} | |||||
} |
@ -0,0 +1,67 @@ | |||||
<html lang="en"> | |||||
<head> | |||||
<!-- Required meta tags --> | |||||
<meta charset="utf-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |||||
<!-- Bootstrap CSS --> | |||||
<link rel="stylesheet" href="/static/bootstrap.min.css"> | |||||
<!-- Loding font --> | |||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,700" rel="stylesheet"> | |||||
<!-- Custom Styles --> | |||||
<link rel="stylesheet" type="text/css" href="/static/styles.css"> | |||||
<title>Login</title> | |||||
</head> | |||||
<body> | |||||
<!-- Backgrounds --> | |||||
<div id="login-bg" class="container-fluid"> | |||||
<div class="bg-img"></div> | |||||
<div class="bg-color"></div> | |||||
</div> | |||||
<!-- End Backgrounds --> | |||||
<div class="container" id="login"> | |||||
<div class="row justify-content-center"> | |||||
<div class="col-lg-8"> | |||||
<div class="login"> | |||||
<h1>One-touch Book!</h1> | |||||
<!-- form --> | |||||
<form action="/confirmed" method="POST" name="login" id="form"> | |||||
{{ form.hidden_tag() }} | |||||
<div class="form-group"> | |||||
{{ form.username(class="form-control") }} | |||||
</div> | |||||
<div class="form-group"> | |||||
{{ form.password(type="password",class="form-control") }} | |||||
</div> | |||||
<div class="form-group"> | |||||
{{ form.email(class="form-control") }} | |||||
</div> | |||||
<div class="form-group"> | |||||
{{ form.area(style="border-radius: 20px;")}} | |||||
</div> | |||||
<button type="submit" class="btn btn-lg btn-block btn-success">confirm</button> | |||||
</form> | |||||
<!-- End form --> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</body> | |||||
</html> |
@ -0,0 +1,50 @@ | |||||
<html lang="en"> | |||||
<head> | |||||
<!-- Required meta tags --> | |||||
<meta charset="utf-8"> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |||||
<!-- Bootstrap CSS --> | |||||
<link rel="stylesheet" href="/static/bootstrap.min.css"> | |||||
<!-- Loding font --> | |||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,700" rel="stylesheet"> | |||||
<!-- Custom Styles --> | |||||
<link rel="stylesheet" type="text/css" href="/static/styles.css"> | |||||
<title>Login</title> | |||||
</head> | |||||
<body> | |||||
<!-- Backgrounds --> | |||||
<div id="login-bg" class="container-fluid"> | |||||
<div class="bg-img"></div> | |||||
<div class="bg-color"></div> | |||||
</div> | |||||
<!-- End Backgrounds --> | |||||
<div class="container" id="login"> | |||||
<div class="row justify-content-center"> | |||||
<div class="col-lg-8"> | |||||
<div class="login"> | |||||
<h1>Success!</h1> | |||||
<br> | |||||
<br> | |||||
<br> | |||||
<br> | |||||
<h>Please wait for our notification mail</h> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</body> | |||||
</html> |
@ -0,0 +1,24 @@ | |||||
from flask import render_template,request | |||||
from app import app | |||||
from .form import Book | |||||
import os | |||||
import _thread | |||||
@app.route('/') | |||||
@app.route('/index') | |||||
def index(): | |||||
return render_template('login.html',form=Book()) | |||||
@app.route('/confirmed', methods=['get', 'post']) | |||||
def BookTest(): | |||||
form = Book() | |||||
if request.method == 'POST': | |||||
if form.validate_on_submit(): | |||||
username = form.username.data | |||||
password = form.password.data | |||||
email = form.email.data | |||||
area = form.area.data | |||||
cmd='python3 auto.py '+username+' '+password+' '+email+' '+area | |||||
_thread.start_new_thread(os.system,(cmd,)) | |||||
return render_template('success.html') |
@ -0,0 +1,143 @@ | |||||
import sys | |||||
import time | |||||
import datetime | |||||
from selenium import webdriver | |||||
from selenium.webdriver.common.action_chains import ActionChains | |||||
from selenium.webdriver.chrome.options import Options | |||||
import smtplib | |||||
from email.mime.text import MIMEText | |||||
from email.header import Header | |||||
from email.utils import formataddr | |||||
from pyvirtualdisplay import Display | |||||
display = Display(visible=0, size=(800, 800)) | |||||
display.start() | |||||
if __name__ == "__main__": | |||||
#prepare info | |||||
username=sys.argv[1] | |||||
password=sys.argv[2] | |||||
verificationCode="1111" | |||||
area=sys.argv[4] | |||||
email=sys.argv[3] | |||||
#login page and num of seats | |||||
if area=='F1_A': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=8&segment=1404341&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=23:50') | |||||
seatsNum=76 | |||||
elif area=='F1_B': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=40&segment=1404354&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=23:50') | |||||
seatsNum=150 | |||||
elif area=='F1_digital_reading_area': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=7&segment=1404328&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=23:50') | |||||
seatsNum=24 | |||||
elif area=='F1_study_area': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=3&segment=1404315&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=23:50') | |||||
seatsNum=48 | |||||
elif area=='F3_foreign_books': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=14&segment=1404198&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=66 | |||||
elif area=='F3_newspaper': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=13&segment=1404185&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=68 | |||||
elif area=='F4_liberal_art_books_A': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=16&segment=1404224&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=72 | |||||
elif area=='F4_liberal_art_books_B': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=17&segment=1404237&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=90 | |||||
elif area=='F4_liberal_art_books_C': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=18&segment=1404250&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=98 | |||||
elif area=='F5_liberal_art_books': | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=20&segment=1404276&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=154 | |||||
else: | |||||
url=('http://seats.lib.ecnu.edu.cn/web/seat3?area=22&segment=1404302&day='+datetime.datetime.now().strftime('%Y-%m-%d') | |||||
+'&startTime='+datetime.datetime.now().strftime('%H:%M')+'&endTime=21:55') | |||||
seatsNum=18 | |||||
options = webdriver.ChromeOptions() | |||||
options.add_argument('--headless') | |||||
options.add_argument('--disable-gpu') | |||||
options.add_argument("--no-sandbox") | |||||
options.add_argument('window-size=1920x3000') | |||||
#initiate a explorer object | |||||
window=webdriver.Chrome(executable_path ='/usr/bin/chromedriver',options=options) | |||||
window.get(url) | |||||
time.sleep(3) | |||||
#close dialog box | |||||
ActionChains(window).move_by_offset(1, 1).click().perform() | |||||
#login | |||||
window.find_element_by_xpath('/html/body/div[2]/div[1]/ul/li[6]/a').click() | |||||
#input username, password and verification code | |||||
inputUsername=window.find_element_by_name("username") | |||||
inputPassword=window.find_element_by_name("password") | |||||
inputVerificationCode=window.find_element_by_name("verify") | |||||
inputUsername.send_keys(username) | |||||
inputPassword.send_keys(password) | |||||
inputVerificationCode.send_keys(verificationCode) | |||||
#click login button | |||||
window.find_element_by_class_name("ui-dialog-autofocus").click() | |||||
time.sleep(2) | |||||
ActionChains(window).move_by_offset(1, 1).click().perform() | |||||
time.sleep(2) | |||||
ActionChains(window).move_by_offset(1, 1).click().perform() | |||||
#traverse to book a seat | |||||
flag=0 | |||||
timenow=datetime.datetime.now() | |||||
while datetime.datetime.now()<(timenow+datetime.timedelta(hours=1)): | |||||
for i in range(1,seatsNum+1): | |||||
xPath=('//*[@id="floor"]/ul/li['+str(i)+']') | |||||
print(xPath) | |||||
if window.find_element_by_xpath(xPath).get_attribute("class")=='seat ava-icon': | |||||
window.find_element_by_xpath(xPath).click() | |||||
time.sleep(3) | |||||
window.find_element_by_class_name('ui-dialog-autofocus').click() | |||||
flag=1 | |||||
break | |||||
if flag == 1: | |||||
break | |||||
window.refresh() | |||||
time.sleep(8) | |||||
#notification | |||||
sender='anthonyyoung_ecnu@foxmail.com' | |||||
pwd='cleedzbuzlgrbgba' | |||||
receiver=email | |||||
if flag==1: | |||||
msg=MIMEText('您的预定已成功!请到图书馆个人中心查看!','plain','utf-8') | |||||
msg['From']=formataddr(["One-touch Book!",sender]) | |||||
msg['To']=formataddr(["",receiver]) | |||||
msg['Subject']="已为您保留座位" | |||||
else: | |||||
msg=MIMEText('您的预定超时!','plain','utf-8') | |||||
msg['From']=formataddr(["One-touch Book!",sender]) | |||||
msg['To']=formataddr(["",receiver]) | |||||
msg['Subject']="预定失败" | |||||
server=smtplib.SMTP_SSL("smtp.qq.com", 465) | |||||
server.login(sender, pwd) | |||||
server.sendmail(sender,[receiver,],msg.as_string()) | |||||
server.quit() |
@ -0,0 +1,2 @@ | |||||
CSRF_ENABLED = True | |||||
SECRET_KEY = 'you-will-never-guess' |
@ -0,0 +1,4 @@ | |||||
#!flask/bin/python | |||||
from app import app | |||||
from gevent import pywsgi | |||||
app.run() |