最近公司的加班调休审批制度有一些调整,由于公司网站上没有清楚的标明各自有多少天可以调休,所以为了清楚的知道自己还有多少天可以调休,就想着使用爬虫爬一下考勤信息,把它放在一个Excel表中以方便查阅。最近项目不是很忙,也趁机学习学习Python爬虫。

一、环境准备

1.首先需要先安装Python,笔者使用的Python3.X。
2.然后使用pip安装工具安装爬虫所需要的非标准库
主要使用到以下一些非标准库:

selenium:为了模拟浏览器操作
win32:为了解密浏览器Cookies
openpyxl:为了操作Excel

使用pip工具安装:

pip install selenium
pip install pywin32
pip install openpyxl

3.由于笔者使用的是浏览器的模拟操作,所以还需要下载一个WebDriver,笔者使用的Chrome浏览器,所以下载与Chrome版本相对应的WebDriver放在Python的安装目录下。

二、编码

1.首先,我们把所有需要使用到的库加进来

from win32 import win32crypt
from os import getenv
import sqlite3
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
import datetime
import openpyxl
from openpyxl.comments import Comment
from openpyxl.styles import Font, colors, Alignment
import math
import re

2.使用浏览器模拟操作
使用浏览器模拟操作时,可以选择浏览器是否可见。

opt = webdriver.ChromeOptions()opt.headless = True  # 浏览器是否可见driver = webdriver.Chrome(options=opt)

创建好了WebDriver后,就可以登录网站了:

driver.get('https://mis.XXXXX.cn')

由于网站是需要登录的,所以要模拟登录过程。使用浏览器模拟登录有两种方式,使用账号密码直接登录和使用之前登录过的Cookies登录。

  • 直接登录
    直接登录需要找到账号与密码输入框,在账号密码框中输入相应的账号与密码,再点登录。
usr_name = driver.find_element_by_class_name("ant-input") # 找到账号输入框
psw = driver.find_element_by_id("inputPassword") # 找到密码输入框
submit_btn = driver.find_element_by_class_name("ant-btn") # 找到登录按钮
usr_name.send_keys("abc")  # 输入账号
psw.send_keys("abc") # 输入密码
submit_btn.click() # 点击登录按钮

BTW:由于各个网站使用的标签不一样,所以标签仅供参考。

  • 使用Cookies登录
    这里定义了一个函数专门获取Chrome浏览器下考勤网站的Cookie
def get_cookie_from_chrome():conn = sqlite3.connect(getenv("LOCALAPPDATA") + r"\Google\Chrome\User Data\Default\Cookies")cursor = conn.cursor()cursor.execute('select host_key, name, encrypted_value, path, is_httponly, is_secure from cookies where host_key like "%mis.XXXXX.cn%"')cookies = []for result in cursor.fetchall():value = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]if value:is_http_only = Falsesecure = Falseif result[4] != 0:is_http_only = Trueif result[5] != 0:secure = Truecookie = {'domain': result[0],'httpOnly': is_http_only,'name': result[1],'path': result[3],'secure': secure,'value': value.decode('utf-8')}cookies.append(cookie)cursor.close()return cookies

获取到Cookies之后将之添加到WebDriver中:

cookies = get_cookie_from_chrome()
for cookie in cookies:driver.add_cookie(cookie)
driver.get('https://mis.XXXXX.cn')

由于网站使用了大量的Ajax以及Frame技术,所以需要等待一段时间,让数据加载完成。可以直接使用

time.sleep

函数进行显示等待,也可以使用selenium的expected_conditions条件等待。
前者简单明了,但是如果在指定的时间内数据未加载完成,获取就会失败,出现异常;后者是设置一个最大等待时间,在此时间内根据设定的间隔时间不断检测是否出现指定的数据,如果出现则继续向后执行,否则等待直到最大等待时间超时。

这里网站使用了Frame技术,左边有一个树型结构,里面有一个“个人考勤”,点了“个人考勤”后,右边才会出现个人考勤的详细列表,如下图:

所以需要切换Frame,然后点击“个人考勤”

wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'left')))
work_day = wait.until(EC.element_to_be_clickable((By.ID, "sundefined5")))
work_day.click()

这段话的意思是直到找到ID为‘left’的Frame,成功切换过去为止,然后直到找到ID为"sundefined5"的元素且可以被点击时,点击它。点击了“个人考勤”后,右边就会出现详细的考勤列表。
由于这个时候还在“left”Frame中,需要切换到新的个人考勤,就需要先切换到“left“的父Frame再切到”个人考勤“Fame

driver.switch_to.parent_frame()
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'dz-kaoqin_iframe')))

切换到考勤详细列表后,开始找数据然后分析数据:

wait.until(EC.presence_of_element_located((By.XPATH, "//tbody/tr")))
date_list = wait.until(EC.presence_of_element_located((By.XPATH, "//tbody")))
flag, lst = parse_work_time(driver, text)  # 这里使用一个专门的函数来分析数据

考勤列表的日期项可以点开,然后弹出一个对话框,详细列出了打卡记录,但如果有没上班,则为空

所以需要模拟点击日期,再获取打卡记录,获取完后,再把“打卡信息”对话框关闭,继续获取下一天的信息

item = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, lst[0])))
item.click() # 点击日期
wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//iframe[@frameborder="0"]'))) # 切换到“打卡信息”对话框
time.sleep(0.2)  # 这里只能使用sleep,因为这里可能只有tbody而没有数据
record_text = driver.find_element_by_xpath("//tbody").text  # 获取所有打卡记录,保存在record_text中
driver.switch_to.parent_frame() # 返回父Frame
close_btn = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "layui-layer-ico"))) # 找到“打卡信息”对话框的关闭按钮
close_btn.click() # 点击关闭按钮,关闭“打卡信息”对话框

如果有考勤异常或者请假单之类的,也会有一个链接,可以查看请假单记录:

bill_list = driver.find_elements_by_class_name("link-billId")
for bill in bill_list:bill.click()wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//iframe[@frameborder="0"]')))time.sleep(0.2)form = driver.find_element_by_xpath('//form')work_time.bill_text = form.textdriver.switch_to.parent_frame()close_btn = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "layui-layer-ico")))close_btn.click()return

把考勤信息爬取到后,就需要写入Excel表了。这里使用openpyxl库来写入,因为我试了xlwings以及xlwt两个库都不支持批注,只有openpyxl支持。

def write_to_excel(work_time_list, file_path):wb = openpyxl.Workbook()    # 打开一个工作薄wb.encoding = 'utf-8'  # 使用UTF8编码sh = wb.worksheets[0]  # 获取第一个sheetsh.title = "考勤"  #将标题改为考勤sheet = wb.create_sheet("原始文本记录")  # 创建一个“原始文本记录”的表# 设置“考勤”表的表头row = 1col = 1sh.cell(row, col, '日期')sh.cell(row, col + 1, '上班时间')sh.cell(row, col + 2, '下班时间')sh.cell(row, col + 3, '上班打卡时间')sh.cell(row, col + 4, '下班打卡时间')sh.cell(row, col + 5, '最晚到时间')sh.cell(row, col + 6, '迟到分钟')sh.cell(row, col + 7, '早退分钟')sh.cell(row, col + 8, '考勤状态')sh.cell(row, col + 9, '单据编号')sh.cell(row, col + 10, '单据类型')sh.cell(row, col + 11, '工作分钟')sh.cell(row, col + 12, '工作小时')sh.cell(row, col + 13, '是否加班')sh.cell(row, col + 14, '剩余可调休加班小时')# 设置“考勤”表的列宽sh.column_dimensions['A'].width = 18sh.column_dimensions['B'].width = 8sh.column_dimensions['C'].width = 8sh.column_dimensions['D'].width = 12sh.column_dimensions['E'].width = 12sh.column_dimensions['F'].width = 10sh.column_dimensions['G'].width = 8sh.column_dimensions['H'].width = 8sh.column_dimensions['I'].width = 8sh.column_dimensions['J'].width = 18sh.column_dimensions['K'].width = 20sh.column_dimensions['L'].width = 8sh.column_dimensions['M'].width = 8sh.column_dimensions['N'].width = 8sh.column_dimensions['O'].width = 18sheet.column_dimensions['A'].width = 100blue_font = Font(name='宋体', size=11, italic=False, color=colors.BLUE, bold=False)red_font = Font(name='宋体', size=11, italic=False, color=colors.RED, bold=False)over_work_time_acc = 0for item in work_time_list:calc_work_time(item)time_hour = parse_bill_info(item)sheet.cell(row, 1).value = item.origin_textrow = row + 1col = 1dt = datetime.datetime.strptime(item.date, "%Y-%m-%d")weekday = dt.weekday() + 1cell = sh.cell(row, col, item.date + '(星期' + str(weekday) + ')')has_comment = Falseif item.record_text.__len__() > 0:cell.comment = Comment(item.record_text, None, width=350)  # 设置批注has_comment = Truesh.cell(row, col + 1, item.start_time)sh.cell(row, col + 2, item.end_time)sh.cell(row, col + 3, item.real_start_time)sh.cell(row, col + 4, item.real_end_time)sh.cell(row, col + 5, item.late_start_time)sh.cell(row, col + 6, item.late_time)sh.cell(row, col + 7, item.before_time)sh.cell(row, col + 8, item.status)sh.cell(row, col + 9, item.handle_sn)if item.bill_text.__len__() > 0:sh.cell(row, col + 9).comment = Comment(item.bill_text, None, width=550)sh.cell(row, col + 10, item.handle_type)sh.cell(row, col + 11, item.valid_work_time)valid_work_time = math.floor(item.valid_work_time / 60)if valid_work_time > 8:valid_work_time = 8sh.cell(row, col + 12, valid_work_time)if weekday == 6 or weekday == 7:if has_comment and item.status == '休息':sh.cell(row, col + 13, '加班')over_work_time_acc += valid_work_timeover_work_time_acc -= time_hoursh.cell(row, col + 14, over_work_time_acc)if weekday == 6 or weekday == 7:for col in range(1, sh.max_column + 1):if has_comment:sh.cell(row, col).font = red_fontelse:sh.cell(row, col).font = blue_fontwb.save(file_path)  # 保存Excel表wb.close() # 关闭return

保存下来的内容如图所示:

祝好

使用Python爬取考勤信息相关推荐

  1. python爬取机票信息

    python爬取机票信息 飞机和高铁列车不同,在同样的航线中有着不同的票价,借此我们希望获取尽量多的机票信息来分析机票的变化规律. 首先我们选取京东机票为爬取对象http://jipiao.jd.co ...

  2. Python 爬取网页信息并保存到本地爬虫爬取网页第一步【简单易懂,注释超级全,代码可以直接运行】

    Python 爬取网页信息并保存到本地[简单易懂,代码可以直接运行] 功能:给出一个关键词,根据关键词爬取程序,这是爬虫爬取网页的第一步 步骤: 1.确定url 2.确定请求头 3.发送请求 4.写入 ...

  3. python爬取控制台信息_python爬虫实战之爬取智联职位信息和博客文章信息

    1.python爬取招聘信息 简单爬取智联招聘职位信息 # !/usr/bin/env python # -*-coding:utf-8-*- """ @Author  ...

  4. Python爬取售房信息并保存至CSV文件

    Python爬取售房信息并保存至CSV文件 在上一篇文章: Python爬取租房信息并保存至Excel文件,介绍了如何使用Python爬取租房信息并保存至Excel文件,在本案例中则是使用Python ...

  5. python爬取网页信息

    最近在学习python,发现通过python爬取网页信息确实方便,以前用C++写了个简单的爬虫,爬取指定网页的信息,代码随便一写都几百行,而要用python完成相同的工作,代码量相当少.前几天看到了一 ...

  6. python爬取电影信息并插入至MySQL数据库

    在上篇博文中,博主使用python爬取了豆瓣电影的影片信息,接下来,博主考虑到在之前做的JavaWeb电影院项目中需要向数据库中一个个的插入影片数据,十分的繁琐,那么在使用了python爬虫后,这个操 ...

  7. python爬取招聘信息_python 爬取boss直聘招聘信息实现

    原标题:python 爬取boss直聘招聘信息实现 1.一些公共方法的准备 获取数据库链接: importpymysql ''' 遇到不懂的问题?Python学习交流群:821460695满足你的需求 ...

  8. 使用python爬取天气信息(包括历史天气数据)

    使用Python爬虫获取城市天气信息(包括历史天气数据) 使用python爬取历史天气数据 文章目录 使用Python爬虫获取城市天气信息(包括历史天气数据) 一.准备工作 二.完整代码 更新 一.准 ...

  9. python爬取个人信息_Python爬取个人微信朋友信息操作示例

    本文实例讲述了Python爬取个人微信朋友信息操作.分享给大家供大家参考,具体如下: 利用Python的itchat包爬取个人微信号的朋友信息,并将信息保存在本地文本中 思路要点: 1.利用itcha ...

最新文章

  1. [评测] 联想 Mirage Solo 一体机:基本性能强大,价格定位很迷
  2. 日语学习-多邻国-平假名2
  3. ufs3.0和ufs2.1的区别体现在哪些方面?
  4. 没有做数据备份 网站随时毁于一旦
  5. win8蓝屏错误代码DPC_WATCHDOG_VIOLATION您的电脑遇到错误需要重启修复
  6. Linux服务器查看内存型号
  7. 【MapReuce】读取本地美国疫情数据存储结果到MySQL
  8. java 根据条码字体_barcode4j使用自定义字体生成条形码
  9. 微信小程序订阅消息报错,by user TAP gesture (适用于tabBar页面)
  10. VIVO市场ASO实战详解,vivo应用市场优化
  11. 承上启下的总结+从吴军的书《态度》总结出的20条为人方法生活状态
  12. android华为登录云服务,华为云服务登录网页版
  13. python提取txt数据到excel
  14. 计算机底层知识之内存
  15. 电脑提示丢失MSVCP140.dll无法启动此程序怎么办【解决方法】
  16. 【文末有惊喜!】iOS日历攻略:提醒调休并过滤法定节假日
  17. 清理蓝藻的机器人_蓝藻打捞机 蓝藻打捞设备 蓝藻清除机 绿藻打捞设备 水华清除机...
  18. php 生成excel透视表,是否可以使用PhpExcel库生成或克隆数据透视表?
  19. 「解析」Self-Attention 关键点
  20. 读书笔记《产品经理必懂的技术那些事儿》03-04

热门文章

  1. linux acl库编译与使用,acl_cpp 的编译与使用
  2. 腾讯会议突然中断,录制的视频怎么恢复。如何找到腾讯会议保存的视频,腾讯会议怎样录制视频
  3. 配置mysql命令_Mysql 数据库常用配置命令
  4. C++ 基础类型万能转换器
  5. 善待安达信的孩子zz
  6. 宝贝成长记事(97)
  7. 组态软件二次开发平台之前景与需求
  8. Android发展史
  9. 文档主服务器什么意思,服务器和云主机什么意思
  10. unturned服务器重置,《Unturned》服务器建立方法详解