树莓派chromium自动化打卡操作思路流程
树莓派chromium自动化打卡操作思路流程

树莓派chromium自动化打卡操作思路流程

树莓派迷你计算机

声明

疫情防控当前,自觉做好健康打卡为每一个大学生应尽的社会责任。本案例仅用于学习python自动化与树莓派Linux系统使用,任何用于其他不正当用途的行为本文与本文作者概不负责。

科学是一种强有力的工具。怎样用它,究竟是给人带来幸福还是带来灾难,全取决于人自己,而不取决于工具。刀子在人类生活上是有用的,但它也能用来杀人。

——爱因斯坦

准备阶段

原材料:树莓派4B、chromium
工具:python selenium

个人打卡

判断模块:

st=>start: 输入某定位块
cond1=>condition: try
判断是否存在
op1=>operation: 输出True
op2=>operation: 输出False
e=>end: 调用结束

st->cond1(yes)->op1->e
cond1(no)->op2->e

代码实现:

def NodeExists(xpath):
   try:
      wd.find_element_xpath(xpath)
      return True
   except:
      return False

读取表格数据:

表格样例如下:

姓名 学号 密码 省代 市代 区代
张三 12343 zhangsan666 上海市 上海市 浦东新区 9 1 11
李四 12344 lisi521 北京市 北京市 东城区 1 1 1
王五 12345 wangwu12345 上海市 上海市 宝山区 9 1 4

流程图:

st=>start: 打开密码名单
op1=>operation: 创建相关列表用于存放数据,
设置读取行数x=1
cond1=>condition: 当在x行中,
判断第2列是否为空值
op2=>operation: 将相关值存入列表中
op3=>operation: x = x + 1
e=>end: 关闭表格,
释放内存

st->op1->cond1(no)->op2->op3(left)->cond1
cond1(yes,right)->e

代码实现:

wb = openpyxl.load_workbook(r'xxx.xlsx') #密码名单
ws = wb.active
name = [] #姓名
username = [] #学号
password = [] #密码
province = [] #省代码
city = [] #市代码
area = [] #区代码
x = 1 #从第一行开始读取
while ws.cell(row = x ,column = 2).value != None: #读取全部学号列不为空值的数据,全部存入对应数据列表
    name.append(ws.cell(row = x ,column = 1).value)
    username.append(ws.cell(row = x ,column = 2).value)
    password.append(ws.cell(row = x ,column = 3).value)
    province.append(ws.cell(row = x ,column = 7).value)
    city.append(ws.cell(row = x ,column = 8).value)
    area.append(ws.cell(row = x ,column = 9).value)
    x = x+1
wb.close() #关闭文件释放内存

自动控制chromedriver执行打卡

流程图(一)

st=>start: 调用打开chromedriver
控制浏览器
c=1
op1=>operation: 清空浏览器缓存
z=1
cond1=>condition: 判断当前打卡序号c
是否在打卡列表内
op2=>operation: 跳转至登陆页面
输入账号、密码
登录
cond2=>condition: 判断是否进入系统
(判断登陆密码是否正确)
op3=>operation: 进入i健康页面
进入每日疫情反馈页面
cond3=>condition: try:
执行正常打卡操作
op4=>operation: 提交打卡
cond4=>condition: 判断页面是否跳转
(判断打卡是否成功)
op5=>operation: c=c+1
op6=>operation: 密码错误
cond5=>condition: try:
判断是否弹窗已打卡
op7=>operation: 打卡失败
cond6=>condition: 判断打卡总次数 z
是否刷新过量
op8=>operation: 跳转页面,退出登录
cond7=>condition: 判断打卡人是否一致
(是否正常刷新)
e=>end: 结束打卡工作,退出浏览器

st->cond1(yes)->op1->op2->cond2(yes)->op3->cond3(yes)->op4->cond4(yes)->op5->op8
cond1(no,right)->e
cond2(no)->op6->op5->op8(left)->cond1
cond3(no,right)->cond5(no)->cond6(no)->op8
cond6(yes)->op7(left)->op5
cond5(yes)->cond7(yes)->op5
cond7(no,left)->op8
cond4(no)->cond6

代码实现

# 因水平有限,
#故“判断打卡人是否一致(是否正常刷新)”模块不能正常实现
#重新对流程图进行修改
#更改内容为:
#1、删去“判断打卡人是否一致(是否正常刷新)”模块
#2、对正常打卡操作失败的直接判定,“已打卡”
#3、对打卡失败的直接回到循环

流程图(二)

st=>start: 调用打开chromedriver
控制浏览器
c=1
op1=>operation: 清空浏览器缓存
z=1
cond1=>condition: 判断当前打卡序号c
是否在打卡列表内
op2=>operation: 跳转至登陆页面
输入账号、密码
登录
cond2=>condition: 判断是否进入系统
(判断登陆密码是否正确)
op3=>operation: 进入i健康页面
进入每日疫情反馈页面
cond3=>condition: try:
执行正常打卡操作
op4=>operation: 提交打卡
cond4=>condition: 判断页面是否跳转
(判断打卡是否成功)
op5=>operation: c=c+1
进入下一打卡人
op6=>operation: 密码错误
cond5=>condition: 判断当前是否为
第一次判定“已打卡”
op7=>operation: 打卡失败
cond6=>condition: 判断打卡总次数 z
是否刷新过量
op8=>operation: 跳转页面,退出登录
e=>end: 结束打卡工作,退出浏览器

st->cond1(yes)->op1->op2->cond2(yes)->op3->cond3(yes)->op4->cond4(yes)->op5->op8
cond1(no,right)->e
cond2(no)->op6->op5->op8(left)->cond1
cond3(no,right)->cond5(no)->op5
cond6(yes)->op7(left)->op5
cond5(yes)->op8
cond4(no)->op3

代码实现

wd = webdriver.Chrome() #调用打开chromedriver,Windows补充路径,Linux安装chromiumdriver
c = 1 # c为正在执行打卡人的序号
f = 0
while c < len(name): #判断当前打卡序号c是否在打卡列表内
        try:
            cookies = wd.get_cookies()
            wd.delete_all_cookies() #清空浏览器缓存
            z = 1
            wd.get('http://i1.gench.edu.cn/_web/fusionportal/stu/things.jsp?_p=YXM9MSZwPTEmbT1OJg')
            wd.implicitly_wait(10) #等待加载,最长加载时间为10秒
            element = wd.find_element_by_id('username')
            element.send_keys(username[c])
            element = wd.find_element_by_id('password')
            element.send_keys(password[c] +'\n')
            wd.implicitly_wait(10) #登录账号
            if wd.title == '事务中心' : #判断是否进入系统
                #TZD('http://i1.gench.edu.cn/_web/fusionportal/stu/skip.jsp?_p=YXM9MSZwPTEmbT1OJg__&appName=pc.sudy.xgfytbxs',".nav-li",'//*[@id="q-app"]/div/div/div/div[3]/div[2]' )   #进入i健康页面
                while True:
                    try:
                        wd.get("http://i1.gench.edu.cn/_web/fusionportal/stu/skip.jsp?_p=YXM9MSZwPTEmbT1OJg__&appName=pc.sudy.xgfytbxs")
                        WebDriverWait(wd,20).until(EC.presence_of_element_located((By.CSS_SELECTOR,".nav-li")))
                        break
                    except:
                        wd.refresh()
                wd.get("http://ihealth.hq.gench.edu.cn/mp/persondaily")
                e = c
                while e == c:
                    #进入每日疫情反馈页面
                    try: #执行正常打卡操作,若无法正常打卡则判断是否已打卡
                        wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[7]/div[3]/div[1]').click()
                        wd.implicitly_wait(10)
                        wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[8]/div[2]/div[1]').click()
                        wd.implicitly_wait(10)
                        wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[9]/div[3]/div[1]').click()
                        wd.implicitly_wait(10)
                        wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(2) > label:nth-child(1)').click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('body >  div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(province[c])).click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(2) > label:nth-child(2) > div > div > div.q-field__append.q-field__marginal.row.no-wrap.items-center.q-anchor--skip').click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('body > div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(city[c])).click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(3) > label > div > div > div.q-field__append.q-field__marginal.row.no-wrap.items-center.q-anchor--skip').click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('body > div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(area[c])).click()
                        time.sleep(1)
                        wd.find_element_by_css_selector('#q-app > div > div > div > div:nth-child(2) > button').click() #提交打卡
                        time.sleep(1) #打卡结束,页面跳转
                        if NodeExists('//*[@id="q-app"]/div/div/div/div[3]/div[2]'):
                            txt = txt + "<tr><td>" + name[c] + "已自动打卡成功</tr></td>" #页面跳转成功,打卡成功
                            Writehtml(txt)
                            c = c + 1
                            B = B + 1
                            f = 0
                    except:
                        if NodeExists('/html/body/div[3]/div[2]/div/div[3]/button'):
                            if f == 0 : #判断当前是否为第一次判定“已打卡”
                                f = 1
                                e = e - 1

                            else:
                                txt = txt + "<tr><td>" + name[c] + "已打卡</tr></td>"
                                Writehtml(txt)
                                f = 0
                                c = c + 1
                                A = A + 1
                        else:
                            txt = txt + "<tr><td>" + name[c] + "打卡失败</tr></td>"
                            Writehtml(txt)
                            f = 0
                            c = c + 1 #打卡序号+1,下一人打卡
                            C = C + 1 #统计
            else:
                txt = txt + "<tr><td>" + name[c] + "密码错误</tr></td>"
                Writehtml(txt)
                c = c + 1
                D = D + 1
        except:
            wd.refresh()
        wd.get('http://i1.gench.edu.cn/_web/fusionportal/stu/things.jsp?_p=YXM9MSZwPTEmbT1OJg')
        wd.implicitly_wait(10)
        wd.find_element_by_xpath('//*[@id="header"]/div/div/div/a[1]').click()
wd.quit()
txt = txt + "</tr></td></table>" + '<table><td><tr>自动打卡成功</tr></td><td><tr>' + str(B) + '人</tr></td>'
txt = txt + "<td><tr>" + '已打卡</tr></td><td><tr>' + str(A) + '人</tr></td>'
txt = txt + "<td><tr>" + '密码错误</tr></td><td><tr>' + str(D) + '人</tr></td>'
txt = txt + "<td><tr>" + '打卡失败</tr></td><td><tr>' + str(C) + '人</tr></td>'
txt = txt + "<td><tr>" + '合计</tr></td><td><tr>' + str(A+B+C+D) + '人</tr></td>'
Writehtml(txt)

优化更改

2022/01/25

c = 1 # c为正在执行打卡人的序号
f = 0
while time.strftime("%H",time.localtime()) == "20" or c < len(name):
    try:
        wd = webdriver.Chrome() #调用打开chromedriver,Windows补充路径,Linux安装chromiumdriver
        while c < len(name): #判断当前打卡序号c是否在打卡列表内
            try:
                cookies = wd.get_cookies()
                wd.delete_all_cookies() #清空浏览器缓存
                z = 1
                wd.get('http://i1.gench.edu.cn/_web/fusionportal/stu/things.jsp?_p=YXM9MSZwPTEmbT1OJg')
                wd.implicitly_wait(10) #等待加载,最长加载时间为10秒
                element = wd.find_element_by_id('username')
                element.send_keys(username[c])
                element = wd.find_element_by_id('password')
                element.send_keys(password[c] +'\n')
                wd.implicitly_wait(10) #登录账号
                if wd.title == '事务中心' : #判断是否进入系统
                    #TZD('http://i1.gench.edu.cn/_web/fusionportal/stu/skip.jsp?_p=YXM9MSZwPTEmbT1OJg__&appName=pc.sudy.xgfytbxs',".nav-li",'//*[@id="q-app"]/div/div/div/div[3]/div[2]' )   #进入i健康页面
                    while True:
                        try:
                            wd.get("http://i1.gench.edu.cn/_web/fusionportal/stu/skip.jsp?_p=YXM9MSZwPTEmbT1OJg__&appName=pc.sudy.xgfytbxs")
                            WebDriverWait(wd,20).until(EC.presence_of_element_located((By.CSS_SELECTOR,".nav-li")))
                            break
                        except:
                            wd.refresh()
                    wd.get("http://ihealth.hq.gench.edu.cn/mp/persondaily")
                    e = c
                    while e == c:
                        #进入每日疫情反馈页面
                        try: #执行正常打卡操作,若无法正常打卡则判断是否已打卡
                            wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[7]/div[3]/div[1]').click()
                            wd.implicitly_wait(10)
                            wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[8]/div[2]/div[1]').click()
                            wd.implicitly_wait(10)
                            wd.find_element_by_xpath('//*[@id="q-app"]/div/div/div/div[1]/div[9]/div[3]/div[1]').click()
                            wd.implicitly_wait(10)
                            wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(2) > label:nth-child(1)').click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('body >  div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(province[c])).click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(2) > label:nth-child(2) > div > div > div.q-field__append.q-field__marginal.row.no-wrap.items-center.q-anchor--skip').click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('body > div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(city[c])).click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('#q-app > div > div > div > div.q-pa-md.q-gutter-md > div:nth-child(6) > div:nth-child(3) > label > div > div > div.q-field__append.q-field__marginal.row.no-wrap.items-center.q-anchor--skip').click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('body > div.q-menu.scroll > div.q-virtual-scroll__content > div:nth-child({}) > div.q-item__section.column.q-item__section--main.justify-center'.format(area[c])).click()
                            time.sleep(1)
                            wd.find_element_by_css_selector('#q-app > div > div > div > div:nth-child(2) > button').click() #提交打卡
                            time.sleep(1) #打卡结束,页面跳转
                            if NodeExists('//*[@id="q-app"]/div/div/div/div[3]/div[2]'):
                                txt = txt + "<tr><td>" + name[c] + "</td><td>已自动打卡成功</td></tr>" #页面跳转成功,打卡成功
                                Writehtml(txt)
                                c = c + 1
                                B = B + 1
                                f = 0
                        except:
                            if NodeExists('/html/body/div[3]/div[2]/div/div[3]/button'):
                                if f == 0 : #判断当前是否为第一次判定“已打卡”
                                    f = 1
                                    e = e - 1
                                else:
                                    txt = txt + "<tr><td>" + name[c] + "</td><td>已打卡</td></tr>"
                                    Writehtml(txt)
                                    f = 0
                                    c = c + 1
                                    A = A + 1
                            else:
                                if f == 0 : #判断当前是否为第一次判定“已打卡”
                                    f = 1
                                    e = e - 1
                                else:
                                    txt = txt + "<tr><td>" + name[c] + "</td><td>打卡失败</td></tr>"
                                    Writehtml(txt)
                                    f = 0
                                    c = c + 1 #打卡序号+1,下一人打卡
                                    C = C + 1 #统计
                else:
                    txt = txt + "<tr><td>" + name[c] + "</td><td>密码错误</td></tr>"
                    Writehtml(txt)
                    c = c + 1
                    D = D + 1
            except:
                wd.refresh()
            try:
                wd.get('http://i1.gench.edu.cn/_web/fusionportal/stu/things.jsp?_p=YXM9MSZwPTEmbT1OJg')
                wd.implicitly_wait(10)
                wd.find_element_by_xpath('//*[@id="header"]/div/div/div/a[1]').click()
            except:
                pass
        wd.quit()
    except:
        wd.quit()
txt = txt + '<tr><td colspan="2">自动打卡成功' + str(B) + '人</td></tr>'
txt = txt + '<tr><td colspan="2">已打卡' + str(A) + '人</td></tr>'
txt = txt + '<tr><td colspan="2">密码错误' + str(D) + '人</td></tr>'
txt = txt + '<tr><td colspan="2">打卡失败' + str(C) + '人</td></tr>'
txt = txt + '<tr><td colspan="2">合计' + str(A+B+C+D) + '人</td></tr>'
Writehtml(txt)

对应模块

def Writehtml(txt):
    GEN_HTML = "/var/www/html/cff.html"
    #打开文件,准备写入
    f = open(GEN_HTML,'w')
    message = """
    <html>
    <head>打卡情况
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>dev.xuanchenbin.com/cff.html</title>
    </head>
    <body>
    %s
    %s
    </body>
    </html>"""%(txt,"update at:" + time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime()))
    f.write(message)
    #关闭文件
    f.close()

定时执行

在我查阅了大量的资料后发现,大致有两种执行方式:
一种是运用time库去控制程序一直执行,再定时开始打卡,另一种是用Linux的crontab去控制程序自动执行。
相比之下第二种方式无需占用大量的内存,故选择第二种方式去执行。故对第一种方式不进行过多阐述。

crontab

常用命令参数

crontab

-u user:用来设定某个用户的crontab服务,例如,“-u ixdba”表示设定ixdba用户的crontab服务,此参数一般有root用户来运行。
file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。
-e:编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。
-l:显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。
-r:从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。
-i:在删除用户的crontab文件时给确认提示。

命令格式

crontab 文件的格式:
{minute} {hour} {day-of-month} {month} {day-of-week} {full-path-to-shell-script}
o minute: 区间为 0 – 59
o hour: 区间为0 – 23
o day-of-month: 区间为0 – 31
o month: 区间为1 – 12. 1 是1月. 12是12月.
o Day-of-week: 区间为0 – 7. 周日可以是0或7.

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

Crontab 命令示例

1. 在 12:01 a.m 运行,即每天凌晨过一分钟。这是一个恰当的进行备份的时间,因为此时系统负载不大。
1 0 * * * /root/bin/backup.sh

2. 每个工作日(Mon – Fri) 11:59 p.m 都进行备份作业。
59 11 * * 1,2,3,4,5 /root/bin/backup.sh

下面例子与上面的例子效果一样:
59 11 * * 1-5 /root/bin/backup.sh

3. 每5分钟运行一次命令
*/5 * * * * /root/bin/check-status.sh

4. 每个月的第一天 1:10 p.m 运行
10 13 1 * * /root/bin/full-backup.sh

5. 每个工作日 11 p.m 运行。
0 23 * * 1-5 /root/bin/incremental-backup.sh

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注