forked from sugerworld/demo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
217 lines (184 loc) · 9.11 KB
/
main.py
File metadata and controls
217 lines (184 loc) · 9.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
import requests
import yaml
import random
from datetime import datetime, timedelta
import json
import os
import logging
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
logging.basicConfig(
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
datefmt='%H:%M:%S',
level=logging.DEBUG)
time_zone = 8 # 时区
# 两天后日期
def get_seats_with_config(user_config, date_config, seat_config):
# 二楼东/二楼西/四楼/三楼大厅/守正书院/求新书院/自定义
seat_name = date_config['name']
if seat_name == "自定义":
return user_config['自定义']
return list(range(seat_config[seat_name]['begin'], seat_config[seat_name]['end']))
class SeatAutoBooker:
def __init__(self, booker_config):
self.json = None
self.resp = None
self.user_data = None
logging.info('Creating SeatAutoBooker object')
self.un = os.environ["SCHOOL_ID"].strip() # 学号
print("使用用户:{}".format(self.un))
self.pd = os.environ["PASSWORD"].strip() # 密码
self.SCKey = None
try:
self.SCKey = os.environ["SCKEY"]
except KeyError:
print("没有Server酱的key,将不会推送消息")
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
self.driver = webdriver.Chrome(service=Service('/usr/local/bin/chromedriver'), options=chrome_options)
self.wait = WebDriverWait(self.driver, 10, 0.5)
self.cookie = None
self.cfg = booker_config
def book_favorite_seat(self, user_config, seat_config):
#判断是否到了预约时间
# 阅览室晚上9点开始预约,自习室晚上8点半开始预约
the_day_after_tomorrow = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'][(datetime.now().weekday() + 2) % 7]
seat_type = seat_config[user_config[the_day_after_tomorrow]['name']]["type"]
if seat_type == "自习室":
start_time = datetime.now().replace(hour=20-time_zone, minute=0, second=0, microsecond=0)
end_time = datetime.now().replace(hour=20-time_zone, minute=15, second=0, microsecond=0)
else:
start_time = datetime.now().replace(hour=19-time_zone, minute=59, second=0, microsecond=0)
end_time = datetime.now().replace(hour=20-time_zone, minute=5, second=0, microsecond=0)
start_time = start_time - timedelta(minutes=self.cfg["cron-delta-minutes"])
if datetime.now() < start_time or datetime.now() > end_time:
return -1, "未到预约时间"
logging.info('Booking favorite seat')
retry_sleep_time = timedelta(minutes=self.cfg["cron-delta-minutes"]).seconds*2/(self.cfg["max-retry"]-2) - 10
for tried_times in range(self.cfg["max-retry"]):
try:
return self._book_favorite_seat(user_config, seat_config, tried_times)
except Exception as e:
logging.exception(e)
print(e.__class__, "尝试第{}次".format(tried_times))
time.sleep(retry_sleep_time)
def _book_favorite_seat(self, user_config, seat_config, tried_times=0):
logging.info('Entering _book_favorite_seat method')
the_day_after_tomorrow = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'][(datetime.now().weekday() + 2) % 7]
date_config = user_config[the_day_after_tomorrow]
seats = get_seats_with_config(user_config, date_config, seat_config)
today_0_clock = datetime.strptime(datetime.now().strftime("%Y-%m-%d 00:00:00"), "%Y-%m-%d %H:%M:%S")
book_time = today_0_clock + timedelta(days=2) + timedelta(hours=date_config['开始时间'])
delta = book_time - self.cfg["start-time"]
total_seconds = delta.days * 24 * 3600 + delta.seconds
if date_config['name'] == '自定义' and tried_times<self.cfg["max-retry"]/3*2:
seat = seats[0]
else:
seat = random.choice(seats)
data = f"beginTime={total_seconds}&duration={3600 * date_config['持续小时数']}&&seats[0]={seat}&seatBookers[0]={self.user_data['uid']}"
headers = self.cfg["headers"]
headers['Cookie'] = self.cookie
print(data)
self.resp = requests.post(self.cfg["target"], data=data, headers=headers)
self.json = json.loads(self.resp.text)
return self.json["CODE"], self.json["MESSAGE"] + " 座位:{}".format(seat)
def login(self):
logging.info('Login in')
pwd_path_selector = """//*[@id="react-root"]/div/div/div[1]/div[2]/div/div[1]/div[2]/div/div/div/div/div[1]/div[2]/div/div[3]/div/div[2]/input"""
button_path_selector = """//*[@id="react-root"]/div/div/div[1]/div[2]/div/div[1]/div[2]/div/div/div/div/div[1]/div[3]"""
try:
logging.info('开始登陆...')
self.driver.get("https://hdu.huitu.zhishulib.com/")
logging.debug('打开网站.')
self.wait.until(EC.presence_of_element_located((By.NAME, "login_name")))
logging.debug('找到用户名输入框.')
self.wait.until(EC.presence_of_element_located((By.XPATH, pwd_path_selector)))
logging.debug('找到密码输入框.')
self.wait.until(EC.presence_of_element_located((By.XPATH, button_path_selector)))
logging.debug('找到登录按钮.')
self.driver.find_element(By.NAME, 'login_name').clear()
self.driver.find_element(By.NAME, 'login_name').send_keys(self.un) # 传送帐号
logging.info('输入用户名')
self.driver.find_element(By.XPATH, pwd_path_selector).clear()
self.driver.find_element(By.XPATH, pwd_path_selector).send_keys(self.pd) # 输入密码
logging.info('输入密码')
logging.info('点击登录按钮')
self.driver.find_element(By.XPATH, button_path_selector).click()
time.sleep(5)
cookie_list = self.driver.get_cookies()
self.cookie = ";".join([item["name"] + "=" + item["value"] + "" for item in cookie_list])
self.cfg["headers"]['Cookie'] = self.cookie
logging.info("登录成功!")
except Exception as e:
logging.error(f"登录失败:{e}")
return -1
return 0
def get_user_info(self):
logging.info('Getting user info')
headers = self.cfg["headers"]
headers['Cookie'] = self.cookie
try:
resp = requests.get("https://hdu.huitu.zhishulib.com/Seat/Index/searchSeats?LAB_JSON=1",
headers=headers)
self.user_data = resp.json()['DATA']
_ = self.user_data['uid']
except Exception as e:
logging.exception(e)
print(self.user_data)
print(e.__class__.__name__ + ",获取用户数据失败")
return -1
print("获取用户数据成功")
return 0
def wechatNotice(self, message, desp=None):
logging.info('Sending WeChat notice')
if self.SCKey != '':
url = 'https://sctapi.ftqq.com/{0}.send'.format(self.SCKey)
data = {
'title': message,
desp: desp,
}
try:
r = requests.post(url, data=data)
if r.json()["data"]["error"] == 'SUCCESS':
print("Server酱通知成功")
else:
print("Server酱通知失败")
except Exception as e:
logging.exception(e)
print(e.__class__, "推送服务配置错误")
def is_booking_enable(date_cfg):
if date_cfg['启用']:
return True
return False
if __name__ == "__main__":
logging.info('Start of the program')
with open("user_config.yml", 'r') as f_obj:
user_config = yaml.safe_load(f_obj)
with open("config/basic_config.yml", 'r') as f_obj:
basic_config = yaml.safe_load(f_obj)
with open("config/seat_config.yml", 'r') as f_obj:
seat_config = yaml.safe_load(f_obj)
the_day_after_tomorrow = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'][(datetime.now().weekday() + 2) % 7]
if not is_booking_enable(user_config[the_day_after_tomorrow]):
logging.info('预约未启用')
print("预约未启用")
exit(0)
s = SeatAutoBooker(basic_config["SeatAutoBooker"])
if not s.login() == 0:
s.driver.quit()
logging.info('Login unsuccessful')
exit(-1)
if not s.get_user_info() == 0:
s.driver.quit()
logging.info('Getting user info unsuccessful')
exit(-1)
s.book_favorite_seat(user_config=user_config, seat_config=seat_config)
s.driver.quit()
logging.info('End of the program')