Python+Selenium某校的自动打卡脚本

Python+Selenium某校的自动打卡脚本

  • 使用selenium库
  • 百度OCR API识别验证码
  • 开启QQ邮箱SMTP服务,邮件提醒打卡状态
  • 阿里云服务器Crontab定时启动
  • 本脚本仅用于个人偷懒使用,并确保填写信息真实

    可能需要用到的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3
# -*- coding: utf-8 -*
import time
import unittest
from selenium.common.exceptions import NoSuchElementException
from selenium import webdriver
from PIL import Image
from aip import AipOcr
import re
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.select import Select
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
from email.header import Header
from selenium.webdriver.chrome.options import Options

获取登陆界面的验证码

  1. 保存原始验证码code.png
  2. 由于原视验证码较模糊,转换为灰度模式,处理后保存code_process.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_code(driver):
png = driver.find_element_by_id('code-box')
png.screenshot('code.png')
img = Image.open('code.png')
img = img.convert('L') # P模式转换为L模式(灰度模式默认阈值127)
count = 185 # 设定阈值
table = []
for i in range(256):
if i < count:
table.append(0)
else:
table.append(1)
img = img.point(table, '1')
img.save('code_process.png') # 保存处理后的验证码

调用百度OCR(文字识别API)识别验证码

  1. 验证码只有英文,并且只有4位。
  2. 识别过后可能会存在空格,使用正则表达式保留需要的元素返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def code_rec():
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)

def get_file_content(file_path):
with open(file_path, 'rb') as f:
return f.read()

image = get_file_content(file_path='code_process.png')
options = {'language_type': 'ENG', } # 识别语言类型,默认为'CHN_ENG'中英文混合

# 调用通用文字识别
result = client.basicGeneral(image, options) # 高精度接口 basicAccurate
for word in result['words_result']:
captcha = (word['words'])
print('验证码识别结果:' + captcha)
captcha_list = re.findall('[a-zA-Z]', captcha, re.S)[:4]
captcha_2 = ''.join(captcha_list)
print('验证码去杂结果:' + captcha_2)
return captcha_2

登陆

  1. 获取登陆界面表单元素
  2. 填入相应数据
  3. 提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def login(driver, captcha, stu_dic):
try:
# driver = webdriver.Chrome()
stu_id = driver.find_element_by_name('txtUid')
stu_pw = driver.find_element_by_name('txtPwd')
code = driver.find_element_by_name('code')
stu_id.send_keys(stu_dic['id'])
stu_pw.send_keys(stu_dic['pw'])
code.send_keys(captcha)
driver.find_element_by_id('Submit').click()
print("登陆表单提交成功!")
return True
except BaseException:
print("登陆表单提交失败!")
return False

测试元素是否存在(判断登陆结果)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 方法必须要继承自unittest.TestCase
class VisitSogouByIE(unittest.TestCase):
def setUp(self):
# 启动谷歌浏览器
self.driver = webdriver.Chrome()

def isElementPresent(self, by, value, driver):
try:
driver.find_element(by=by, value=value)
except NoSuchElementException:
print("没有找到指定元素!")
return False
else:
return True

填写并提交数据表单

  1. Xpath语法或其他方法定位到对应填写入口
  2. 获取对应数据并填入表单提交
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
def sub_form(driver):
try:
driver.find_element_by_xpath("//div[@id='platfrom2']/a").click()
select_1 = driver.find_element_by_name('FaProvince').get_attribute('value')
select1 = Select(driver.find_element_by_name('Province'))
select1.select_by_value(select_1)
print("行政区代码" + select_1)
select_2 = driver.find_element_by_name('FaCity').get_attribute('value')
select2 = Select(driver.find_element_by_name('City'))
select2.select_by_value(select_2)
select_3 = driver.find_element_by_name('FaCounty').get_attribute('value')
select3 = Select(driver.find_element_by_name('County'))
select3.select_by_value(select_3)
ck_cls = driver.find_element_by_xpath('//*[@id="form1"]/div[1]/div[5]/div[3]/div/div/label')
js = "var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
# ActionChains(driver).send_keys(Keys.END).perform()
ck_cls.click()
save_form = driver.find_element_by_class_name('save_form')
save_form.click()
print("信息表单提交成功!")
driver.quit()
return True
except BaseException as erro:
time.sleep(5)
print(erro)
already_text = driver.find_element_by_xpath(
"//*[@class='layui-m-layercont']").text
if already_text == '当前采集日期已登记!':
print(already_text)
driver.quit()
return already_text
else:
print("提交失败!")
print(already_text)
return False

邮件提醒打卡状态

  1. 利用QQ邮箱或其他SMTP服务或自己服务器搭建的邮件服务发送邮件
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
def send_email(text, stu_dic):
try:
email_from = ''
email_to = stu_dic['email_to'] # 接收邮箱
hostname = 'smtp.qq.com' # QQ邮箱的smtp服务器地址
login = '' # 发送邮箱的用户名
password = '' # 发送邮箱的密码,即开启smtp服务得到的授权码。
subject = '打卡状态' # 邮件主题
# text = "恭喜您!打卡成功!" # 邮件正文内容

smtp = SMTP_SSL(hostname) # SMTP_SSL默认使用465端口
smtp.login(login, password)

msg = MIMEText(text, 'plain', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['from'] = email_from
msg['to'] = email_to

smtp.sendmail(email_from, email_to, msg.as_string())
smtp.quit()
print("发送成功!")
return True
except BaseException:
print("发送失败!")
return False

主函数

  1. 程序运行成功邮件提醒
  2. 程序运行失败异常处理及邮件提醒
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
if __name__ == "__main__":
try:
chrome_options = Options()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--headless')
stu = [
{'id': 'xxxxx', 'pw': 'xxxxx', 'email_to': 'xxxxx@foxmail.com'},
]
for stu_dic in stu:
test = VisitSogouByIE() # 实例化对象
# driver = webdriver.Chrome(options=chrome_options,executable_path='/usr/local/bin/chromedriver') # 实例化对象
driver = webdriver.Chrome(options=chrome_options)
driver.get('http://xsc.sicau.edu.cn/SPCP/Web/')
driver.implicitly_wait(20)
get_code(driver)
captcha = code_rec()
while True:
try:
if len(captcha) < 4:
driver.refresh()
time.sleep(2)
get_code(driver)
captcha = code_rec()
else:
login(driver, captcha, stu_dic)
time.sleep(5)
is_exist = test.isElementPresent(
driver=driver, by='id', value='platfrom2')
if not is_exist:
if not test.isElementPresent(driver=driver, by='id', value='layui-m-layer0'):
break
driver.back()
time.sleep(2)
driver.refresh()
time.sleep(2)
get_code(driver)
captcha = code_rec()
print("登陆失败!")
elif is_exist:
print("登陆成功!")
break
except Exception as erro:
print(erro)
captcha = 'xxx'
continue
time.sleep(2)
is_sub = sub_form(driver)
if is_sub:
text = "恭喜您!打卡成功!"
if is_sub == '当前采集日期已登记!':
text = is_sub
send_email(text, stu_dic)
elif not is_sub:
print("打卡失败!稍后重试!")
text = "打卡失败!稍后重试!"
send_email(text, stu_dic)
text = "程序运行结束,所有STU均已操作一遍!"
send_email(text, stu[0])
except BaseException as E:
me = {'id': 'xxxx', 'pw': 'xxxx', 'email_to': 'xxxx@foxmail.com'}
print(E)
print("程序意外终止!")
text = "程序意外终止!"
send_email(text,me)

写得比较匆忙有的地方还可以改进,已经开学了,不用打卡了,代码放出来做个记录,顺便水一篇博客。

Python+Selenium某校的自动打卡脚本

http://tianyuzhou.github.io/2020/09/03/自动打卡/

作者

TIANYUZHOU

发布于

2020-09-03

更新于

2021-02-17

许可协议

评论