@ -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() |