爬取班级魔方未体温填报并且发送邮箱

前言

作为某大学的团支书,负责体温填报,每日每个时间段地提醒,有亿点点疲倦了。想写个爬虫来帮我完成,虽然之前写过一个爬虫来帮我每天填报。可那是直接用了别人的学生端登陆,可后台是老师端,这两者有点不一样。而且我本身的Python几乎0基础,主要学习的语言是C/C++和JAVA。但是我偶然看到一个selenium的技术,这玩意就是模拟点击,也可以算是半爬虫吧。但是本次用的就是这玩意。

功能和特性

  • 可以由程序无障碍登陆班级魔方后台并且进入体温填报后台界面
  • 可以获取Excel的学生的学号和邮箱
  • 判断时间点,然后根据时间点判断该同学是否填报该时间段的体温
  • 如果未填,则发送邮箱督促其填报。

编写代码过程的坎坷

1. 从Excel中获取数据

Excel表格如图

image-20220504182539703

def read():
    wb = openpyxl.load_workbook('./xl.xlsx')
    sheet = wb['Sheet1']
    active_sheet = wb.active
    for i in range(2, 38):
        studentId = active_sheet.cell(row=i, column=1).value
        studentName = active_sheet.cell(row=i, column=2).value
        studentPost = active_sheet.cell(row=i, column=3).value
        str(studentId)
        str(studentPost)
        str(studentName)
        arr = {"studentId": studentId, "studentName": studentName, "studentPost": studentPost}
        readlists.append(arr)

这里是从用了openpyxl模块,然后从excel中第2行遍历到第37行,取出每一个数据存到一个arr字典里面,然后把每一个字典存到列表里面。

2.模拟点击获取后台数据,然后将从excel获取到字典进行合并

2.1 模拟点击页面

这里先到班级魔方的教师登陆界面,然后用selenium用xpath模拟点击到体温填报界面,并且获取到界面。

易错点:这里因为页面数据较多,需要先sleep一定时间,要不然数据获取不到。

web = Chrome()
web.get("http://banjimofang.com/teacher/login?ref=%2Fteacher")

web.find_element_by_xpath('/html/body/div/div/div/form/div[3]/div[1]/input').send_keys("账号")
web.find_element_by_xpath('/html/body/div/div/div/form/div[3]/div[2]/input').send_keys("密码")
web.find_element_by_xpath('/html/body/div/div/div/form/div[3]/div[4]/button').click()
web.find_element_by_xpath('//*[@id="mainarea"]/div[3]/div[1]/a/div/h5').click()
web.find_element_by_xpath('/html/body/div/div[2]/div/div/div[7]/div[2]/div/div[1]/a/div[1]').click()
web.find_element_by_xpath('/html/body/div/div[2]/div/div/div[8]/a/div[1]/i').click()
web.switch_to.window(web.window_handles[-1])
time.sleep(5)
tr_list = web.find_elements_by_xpath('//*[@id="tmptablebody"]/tr')

2.2 获取班上的人并且合并成字典

这里是先获取到每一个小列表,然后提取数据,再匹配上面获取到的邮箱,将其整合成一个字典。再将其加入列表。

这样的字典就是

arr = {"studentId": studentId, "studentName": studentName, "studentPost": tmpstudentpost, "tem1": tem1, "tem2": tem2, "tem3": tem3}

包含学号,姓名,邮箱,以及早中晚的体温。

易错点:studentID比较注意类型,我本人因为这个改了一个晚上,一直把string == int进行比较。

for tr in tr_list:
    q = tr.find_element_by_xpath("./td[3]").text
    if q == "班级":
        studentId = tr.find_element_by_xpath("./td[2]").text
        studentName = tr.find_element_by_xpath("./td[1]").text
        tem1 = tr.find_element_by_xpath("./td[4]").text
        tem2 = tr.find_element_by_xpath("./td[5]").text
        tem3 = tr.find_element_by_xpath("./td[6]").text
        tmpstudentpost = "1"
        # studentId 是str
        str(studentId)
        #print(type(studentId))


        for i in readlists:
            #print(i["studentId"])
            #print(type(i["studentId"]))
            if str(i["studentId"]) == str(studentId):
                tmpstudentpost = i["studentPost"]
                break
        arr = {"studentId": studentId, "studentName": studentName, "studentPost": tmpstudentpost, "tem1": tem1, "tem2": tem2, "tem3": tem3}
        lists.append(arr)

3.判断时间点然后发送邮箱

3.1 获取当前时间并且返回状态码

这里就是判断时间点了,我这边是早上 0 - 11, 11-16,17-22。对应的状态码分别是1 2 3。

小难点:获取时间

def whichtime():
    start_time1 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '0:00', '%Y-%m-%d%H:%M')
    end_time1 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '11:00', '%Y-%m-%d%H:%M')

    start_time2 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '11:00', '%Y-%m-%d%H:%M')
    end_time2 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '16:00', '%Y-%m-%d%H:%M')

    start_time3 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '17:00', '%Y-%m-%d%H:%M')
    end_time3 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '22:00', '%Y-%m-%d%H:%M')

    now_time = datetime.datetime.now()
    if start_time1 < now_time < end_time1:
        return 1
    elif start_time2 < now_time < end_time2:
        return 2
    else:
        return 3

3.2匹配时间判断是否已经体温填报

这里没填报的体温是“0.0”这也方便我们进行比较,根据返回的状态码判断需要比较的是什么时候的体温。

易错点:连续发多封邮箱会导致一些问题,所以尽量等大部分人填完再进行发邮箱。

def work():
    for i in lists:
        nowtimestatus = whichtime()
        if nowtimestatus == 1:
            if str(i["tem1"]) == "0.0":
                receivers = str(i["studentPost"])
                send_msg_success(receivers)
                time.sleep(2)
                print(i["studentId"], nowtimestatus, receivers)
        elif nowtimestatus == 2:
            if str(i["tem2"]) == "0.0":
                receivers = str(i["studentPost"])
                send_msg_success(receivers)
                time.sleep(2)
                print(i["studentId"], nowtimestatus, receivers)
        else:
            if str(i["tem3"]) == "0.0":
                receivers = str(i["studentPost"])
                send_msg_success(receivers)
                time.sleep(2)
                print(i["studentId"], nowtimestatus, receivers)

后言

其实做出来后并没有想象中那么有效。很多同学QQ并没有开启QQ邮箱及时通知。而且程序也无法放到云函数或者其他地方运行。或者说是我不会。但是做这样一个项目,其实加深了我对知识点的理解。

下面附上几张我的痛苦面具吧。这也就是Python小白的无奈吧。

image-20220504190451944

image-20220504190515593

image-20220504190529664

image-20220504190546471

源码链接

源码

posted @ 2022-05-05 11:44  Rookie_Leixin  阅读(299)  评论(1)    收藏  举报