注意:这篇文章上次更新于279天前,文章内容可能已经过时。
这是一个 2.0 版的 Fuck信仰不息🗽
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)