这是一个 2.0 版的 Fuck信仰不息🗽

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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
from selenium.webdriver.chrome.service import Service
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
from email.header import Header
from smtplib import SMTP_SSL
import random
import json
import requests
import os
import time
import cv2
import numpy as np


def send_email(msg, receiver):
host_server = '' # 邮箱smtp服务器
user = '' # user 为发件人的邮箱号码
pwd = '' #pwd 为邮箱的授权码
sender_mail = '' #发件人的邮箱
#邮件的正文内容
mail_content = msg

#添加机器人签名
mail_sign = \
'''
\n
---

No need to reply!
Contact me: wgx@dijk.eu.org
'''

#邮件标题
mail_title = '【打卡消息推送】'
#ssl登录
smtp = SMTP_SSL(host_server)
#set_debuglevel()是用来调试的。参数值为1表示开启调试模式,参数值为0关闭调试模式
smtp.set_debuglevel(0)
smtp.ehlo(host_server)
smtp.login(user, pwd)

msg = MIMEText(mail_content + mail_sign, "plain", 'utf-8')
msg["Subject"] = Header(mail_title, 'utf-8')
msg["From"] = sender_mail
msg["To"] = receiver
smtp.sendmail(sender_mail, receiver, msg.as_string())
smtp.quit()

def bin_img(img):
# 设定纯白色的阈值为255(注意:OpenCV使用BGR而不是RGB)
white_threshold = 246
# 通过比较找出不是纯白色的像素位置
not_white = np.any(img < white_threshold, axis=-1)
# 创建一个全黑色的图像
black_image = np.zeros_like(img)
# 将非纯白色的像素设为黑色,而其他的保持不变(可选,如果您想只保留纯白色的像素)
img[not_white] = [0, 0, 0]
return img

def download_image(url, filename):
response = requests.get(url)
if response.status_code == 200:
with open(filename, 'wb') as file:
file.write(response.content)

def match_img(big_image, small_image):
# 二值图像
big_image = bin_img(big_image)
small_image = bin_img(small_image)

# 使用模板匹配方法寻找小图在大图中的位置
result = cv2.matchTemplate(big_image, small_image, cv2.TM_CCOEFF_NORMED)

# 获取匹配结果中的最大值和它的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

# 滑块的顶部左侧点
top_left = max_loc

# 由于我们知道小图的大小,我们可以计算出匹配区域的右下角位置
# bottom_right = (top_left[0] + small_image.shape[1], top_left[1] + small_image.shape[0])

# # 在大图上绘制匹配到的区域
# cv2.rectangle(big_image, top_left, bottom_right, color=(0, 255, 0), thickness=2)

# 显示结果
# cv2.imshow('Match', big_image)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

xcenter_x = top_left[0] + small_image.shape[1] / 2
image_width = big_image.shape[1] # image.shape[1] 给出图像宽度

# 计算百分比
percentage = (xcenter_x / image_width)

return percentage

def wait_for_page_load(driver, timeout=10):
try:
# 使用WebDriverWait等待页面加载,通过执行JavaScript返回document.readyState == 'complete'
page_loaded = WebDriverWait(driver, timeout).until(
lambda d: d.execute_script('return document.readyState') == 'complete'
)
except TimeoutException:
print("在给定的时间内,页面未完全加载!")
return False
return True

def verify(percentage, driver):
slider_button = driver.find_element(By.CSS_SELECTOR, ".ui-slider-btn.init")
slider_track = driver.find_element(By.CSS_SELECTOR, ".ui-slider-wrap") # 假定滑道元素类名是 "ui-slider-wrap"
# 获取滑道的长度
track_width = slider_track.size['width']
# 计算需要拖动的像素距离
offset = track_width * percentage
# 初始化ActionChains对象
action_chains = ActionChains(driver)
# 点击并按住滑块按钮
action_chains.click_and_hold(slider_button).perform()
# 这里我们添加一个非常短暂的延时来模拟人非常平滑的拖动滑块
for step in range(int(offset // 10)):
action_chains.move_by_offset(10, 0).perform() # 小步移动
time.sleep(0.05) # 稍微等待,让动作可见
remaining_offset = offset % 10
action_chains.move_by_offset(remaining_offset, 0).perform() # 移动剩余的距离
time.sleep(0.5) # 完成拖动后稍作停顿
action_chains.release().perform() # 释放滑块

def is_passed(driver):
# 找到包含指定文本的元素
text_element = driver.find_element(By.CLASS_NAME, "ui-slider-text")
# 提取并打印文本
slider_text = text_element.text
print(slider_text)
if slider_text[:4] == "验证成功":
return True
else:
return False

def login_recheck(driver):
elements = driver.find_elements(By.XPATH, '/html/body/form/div/div[2]/div[2]/table')
if len(elements) > 0:
return True
else:
return False

def parse_daka(driver):
# 假设html_content是包含上面所示HTML的字符串
html_content = driver.page_source
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(html_content, 'html.parser')
# 初始化结果列表
result = []
# 找到表格
table = soup.find('table', {'class': 'kq-message-table'})
# 获取表头中的所有th标签,用于列名称
headers = []
for th in table.find('thead').find_all('th'):
# 每个th标签,获取文本并消除空格和换行符
headers.append(' '.join(th.stripped_strings))
# 遍历表格的每一行
for row in table.find('tbody').find_all('tr'):
# 获取行中的所有td标签
cells = row.find_all('td')
# 每一行的数据都以字典形式存在,字典的键来自标题,值来自单元格数据
data = {}
for index, cell in enumerate(cells):
key = headers[index]
# 提取每个单元格的文本作为数据
data[key] = cell.get_text(strip=True)
# 将每行数据添加至结果列表
result.append(data)
# 将结果列表转换为JSON格式
json_data = json.dumps(result, ensure_ascii=False, indent=4)
return json_data

def daka(user,password, receiver):
options = Options()
options.binary_location = '/opt/google/chrome/google-chrome'
options.add_argument('--headless')
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")
service = Service(executable_path='/daka/chromedriver')
driver = webdriver.Chrome(service=service,options=options)

retry = 0
verify_adjust = [0.03, 0.02, 0.01, -0.01, -0.02, -0.03]
adjust_index = 0
while True:
driver.get('http://kq.neusoft.com')
while not is_passed(driver):
big_image_elem = driver.find_element(By.ID, "bigImage")
small_image_elem = driver.find_element(By.ID, "smallImage")

big_image_url = big_image_elem.get_attribute("src")
small_image_url = small_image_elem.get_attribute("src")

download_image(big_image_url, "big.png")
download_image(small_image_url, "small.png")
time.sleep(5)

big_image = cv2.imread('big.png')
small_image = cv2.imread('small.png')

percent = match_img(big_image, small_image)
print(percent)
verify(percent - verify_adjust[adjust_index], driver)
time.sleep(2)

retry += 1
adjust_index = retry // 10
if adjust_index > 5:
send_email("打卡失败:重试次数过多,放弃重试!",receiver)
return -1

print("通过验证码!")
user_input_element = driver.find_element(By.XPATH, '/html/body/div[1]/form/div[2]/div/div/div[2]/div[2]/input')
user_input_element.send_keys(user)

pass_input_element = driver.find_element(By.XPATH, "/html/body/div[1]/form/div[2]/div/div/div[2]/div[3]/input")
pass_input_element.send_keys(password)

login_button = driver.find_element(By.XPATH, '/html/body/div[1]/form/div[2]/div/div/div[2]/div[6]/input')
login_button.click()
time.sleep(1)
if login_recheck(driver):
print("登陆成功!")
break

time.sleep(2)
msg = parse_daka(driver)
button = driver.find_element(By.XPATH, '/html/body/form/div/div[2]/div[2]/div[1]/a[1]')
button.click()
msg = "打卡成功!\n请查看打卡记录:\n"
msg += parse_daka(driver)
print(msg)
send_email(msg, receiver)

if __name__ == '__main__':
user = ''
password = ''
receiver = ''
sleep_time = random.randint(1, 300)
print(f"{sleep_time} 秒后启动程序...")
time.sleep(sleep_time)
try:
daka(user, password, receiver)
except Exception as e:
msg = "未知异常,请检查!"
send_email(msg, receiver)