task
补齐禅道日志,每日新增工时不小于8不超过12
思路
- 登录禅道获取session
- 取出历史1000条工时记录作为填写内容随机抽取/取出三年内所有工时记录作为填写内容随机抽取
- 获取当前登录用户所有task和project,随机抽取一组
- 获取指定月份工作日日期,需要去掉周六日和传统节假日
- 需要具备新增/删除日志功能(整月)
实现
# coding:utf-8
import requests
import re
import hashlib
import datetime
import chinese_calendar
from bs4 import BeautifulSoup
import random
import logging
import os.path
import time
from colorama import Fore, Style
import sys
# logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',level=logging.INFO)
# 使用前修改禅道账号密码
account = ''
password = ''
class Chandao():
'''
禅道相关
'''
def __init__(self, account, password, year, month):
self.account = account
self.password = password
self.year = year
self.month = month
self.session = self.login()
def login(self):
'''
登录禅道
:return: session
'''
s = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.100.4844.11 Safari/537.36"
}
while (True):
rs1 = s.get("https://chandao.tingyun.com/pro/user-login.html", headers=headers)
rs1.encoding = 'utf-8'
rand = re.findall(r"'verifyRand' value='(.+?)'", rs1.text)
if len(rand[0]) == 10:
vrand = rand[0]
break
hash = hashlib.md5()
hash.update(password.encode('utf-8'))
f = hash.hexdigest() + vrand
hash2 = hashlib.md5(f.encode('utf-8'))
pwd = hash2.hexdigest()
data = {
"account": account,
"password": pwd,
"verifyRand": vrand
}
rs2 = s.post("https://chandao.tingyun.com/pro/user-login.html", headers=headers, data=data)
rs2.encoding = 'utf-8'
res4 = s.get('https://chandao.tingyun.com/pro/qa/')
result = re.findall(r"\<a href=\'\/pro\/user-logout.html' \>(.+?)\<\/a\>", res4.text)
if result[0] == "退出":
Logger().info(f"Account:{account}————> Login Success!")
return s
def get_task(self):
'''
返回当前登录用户的所有task和project
:return: task,project
'''
projects = []
task = []
res = self.session.get('https://chandao.tingyun.com/pro/effort-batchCreate.html?onlybody=yes')
# print(res.text)
# result = set(re.findall(r"<option value='task(.+?)data-keys", res.text))
# project = set(re.findall(f"<option value='(.+?)' title=(.+?)data-keys",res.text))
soup = BeautifulSoup(res.text, features="lxml")
options = set(soup.findAll('option'))
# print(len(options))
for option in options:
if "task" in option.get("data-keys"):
task.append(option.get("title").split(":")[0])
else:
# 去除custom
if option.get("value").isdigit():
# 去除0
if int(option.get("value"))!=0:
projects.append(option.get("value"))
Logger().info("当前用户所有task:"+str(task)+"\n当前用户所有project:"+str(projects))
return task,projects
def get_current_user_history_task(self):
history_works = []
res = self.session.get('https://chandao.tingyun.com/pro/my-effort-all-date_desc-1000-1000-1.html')
# print(res.text)
soup = BeautifulSoup(res.text, features="lxml")
for title in soup.findAll("td"):
# 筛选clas为c-work的td标签
if 'c-work' in title.get("class"):
# 去掉None
if title.get("title") != None:
history_works.append(title.get("title"))
Logger().info("当前用户前1000条历史日志记录:"+str(history_works))
return history_works
def get_current_user_annual_task(self):
'''
获取三年内所有日志内容
:return:三年内日志记录的工作内容列表
'''
year = datetime.datetime.now().year
annual_works = []
for i in range(3):
res = self.session.get(f'https://chandao.tingyun.com/pro/effort-ajaxGetEfforts-lijiacheng-{int(year)-i}.html')
if res.status_code == 200:
for daliy in res.json():
if '[T]' in daliy['title']:
annual_works.append(daliy['title'].split('[T]')[1])
else:
annual_works.append(daliy['title'])
else:
Logger().error(res.text)
Logger().info(f"{self.account} 三年内所有日志:"+str(annual_works))
return annual_works
def add_daily(self):
# 随机获取工时,保证每天的任务工时不同
work_hours = [1, 2, 3, 4, ]
# 当天的总工时在8~12之间
currentday_hour = 0
history_works = self.get_current_user_history_task()
three_year_works = self.get_current_user_annual_task()
cal, cal2 = Workday(self.year,self.month).getDateByTime()
i = 0
for c in cal:
url = f'https://chandao.tingyun.com/pro/effort-batchCreate-{cal2[i]}.html?onlybody=yes'
headers = {
"content-type": "application/x-www-form-urlencoded",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.100.4844.11 Safari/537.36"
}
while currentday_hour < 8:
current_hour = random.choice(work_hours)
data = {
"date": f"{cal[i]}",
"id[]": 2,
"work[]": f"{random.choice(history_works)}",
# "objectType[]": f"{random.choice(task)}",
# "project[]": int(random.choice(project)),
"left[2]": 99,
"consumed[]": current_hour,
}
# print(data)
self.session.post(url=url, headers=headers, data=data)
currentday_hour += current_hour
if currentday_hour >= 8:
currentday_hour = 0
break
i = i + 1
Logger().info(f"{self.year}年{self.month}月日志新增完成")
def del_daily(self):
# 当前月份内所有可删除日志地址
delete_url=[]
cal, cal2 = Workday(self.year,self.month).getDateByTime()
for c in cal2:
url = f'https://chandao.tingyun.com/pro/my-effort-{c}.html'
headers = {
"content-type": "application/x-www-form-urlencoded",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.100.4844.11 Safari/537.36"
}
res = self.session.get(url=url, headers=headers)
soup = BeautifulSoup(res.text, features="lxml")
options = set(soup.findAll('a'))
for option in options:
# print(option)
if option.get("href") != None:
if "delete" in option.get("href"):
# url末尾增加yes,直接删除
href = option.get("href").split('.')
delete_url.append("https://chandao.tingyun.com"+href[0]+"-yes."+href[1])
# print(delete_url)
# 删除日志
for url in delete_url:
try:
# print(url)
r = self.session.get(url)
except Exception as e:
Logger().error(e)
Logger().info(f"{self.year}年{self.month}月日志删除完成")
class Workday():
'''
获取填写日报的日期,规则:把当月所有的工作日时间全部返回
'''
def __init__(self,year, month):
self.year = year
self.month = month
def getDateByTime(self):
'''
获取某一年某一月的工作日
:return: %Y-%m-%d、%Y%m%d两种格式日期
'''
global tmp
holidays = self.get_holidays(year=self.year,include_weekends=False)
self.myDate = []
self.myDate2 = []
t = str(time.strftime(f'{self.year}-{self.month}-'))
for i in range(1, 32):
timeStr = t + str(i)
try:
# 字符串转换为规定格式的时间
tmp = time.strptime(timeStr, '%Y-%m-%d')
# 判断是否为周六、周日
if (tmp.tm_wday != 6) and (tmp.tm_wday != 5) and time.strftime('%Y-%m-%d', tmp) not in holidays:
self.myDate.append(time.strftime('%Y-%m-%d', tmp))
self.myDate2.append(time.strftime('%Y%m%d', tmp))
except Exception as e:
Logger().error(e)
if len(self.myDate) == 0 and time.strftime('%Y-%m-%d', tmp) not in holidays:
self.myDate.append(time.strftime('%Y-%m-%d'))
self.myDate2.append(time.strftime('%Y%m%d'))
Logger().info(f"{self.year}年{self.month}月工作日为:"+str(self.myDate))
return self.myDate,self.myDate2
def get_holidays(self,year=None, include_weekends=True):
"""
获取某一年的所有节假日,默认当年
:param year: which year
:param include_weekends: False for excluding Saturdays and Sundays
:return: list
"""
holidays = []
if not year:
year = datetime.datetime.now().year
else:
year = year
start = datetime.date(year, 1, 1)
end = datetime.date(year, 12, 31)
holidays_date = chinese_calendar.get_holidays(start, end, include_weekends)
for holiday in holidays_date:
holidays.append(holiday.strftime('%Y-%m-%d'))
# print(holidays)
return holidays
class Logger(object):
def __init__(self):
"""
指定保存日志的文件路径,日志级别,以及调用文件
将日志存入到指定的文件中
:param logger: 定义对应的程序模块名name,默认为root
"""
# 创建一个logger
self.logger = logging.getLogger(name=sys.argv[0])
self.logger.setLevel(logging.DEBUG) # 指定最低的日志级别 critical > error > warning > info > debug
# 创建一个handler,用于写入日志文件
rq = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time()))
log_path = os.getcwd() + "/logs/"
log_name = log_path + rq + ".log"
# 这里进行判断,如果logger.handlers列表为空,则添加,否则,直接去写日志,解决重复打印的问题
if not self.logger.handlers:
# 创建一个handler,用于输出到控制台
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.DEBUG)
# 定义handler的输出格式
formatter = logging.Formatter(
"%(asctime)s - %(filename)s[line:%(lineno)d] - %(name)s - %(message)s")
ch.setFormatter(formatter)
# 给logger添加handler
# self.logger.addHandler(fh)
self.logger.addHandler(ch)
def debug(self, msg):
"""
定义输出的颜色debug--white,info--green,warning/error/critical--red
:param msg: 输出的log文字
:return:
"""
self.logger.debug(Fore.WHITE + "DEBUG - " + str(msg) + Style.RESET_ALL)
def info(self, msg):
self.logger.info(Fore.GREEN + "INFO - " + str(msg) + Style.RESET_ALL)
def warning(self, msg):
self.logger.warning(Fore.RED + "WARNING - " + str(msg) + Style.RESET_ALL)
def error(self, msg):
self.logger.error(Fore.RED + "ERROR - " + str(msg) + Style.RESET_ALL)
def critical(self, msg):
self.logger.critical(Fore.RED + "CRITICAL - " + str(msg) + Style.RESET_ALL)
if __name__ == '__main__':
Logger().info('''
-----------------使用说明-----------------------
1. 修改文件顶部禅道账号及密码
2. 参数说明详见readme.md文件
-----------------谢谢使用-----------------------
''')
if account == '':
account = input("请输入禅道账号:")
if password == '':
password = input("请输入禅道密码:")
try:
if sys.argv[1] == "add":
Chandao(account,password,int(sys.argv[2]),int(sys.argv[3])).add_daily() # 新增日志
elif sys.argv[1] == "del":
Chandao(account,password,int(sys.argv[2]),int(sys.argv[3])).del_daily() # 删除日志
elif sys.argv[1] == 'query':
Chandao(account, password, 2020,1).get_current_user_annual_task()
except Exception as e:
Logger().error(e)
使用方式
1.修改禅道账号和密码
2.新增日志
格式为:python3 chandao.py add xxxx x
例如:新增2020年1月日志
python3 chandao.py add 2020 1
3.删除日志
格式为:python3 chandao.py del xxxx x
例如:删除2020年1月日志
python3 chandao.py del 2020 1
ぽっちゃりポルノ .hs81GlPQYfT
ラティーナポルノ .sEFershbTSa
ਮਸ਼ਹੂਰ ਪੋਰਨ .mnLQoC9hYY6
WOU1gYApm09
fP99qvnYULp
8bXG344BSc5
PnlWRz6T3Au
fOIRi23V62K
E9ApUwlIzFr
uplMEmxgjya
fvtwMQBKod2
6131TvhPM0s
eMtcKKTxT25
2m6Jfk3Hteo
hsS6pI3oTni
rsRXryeK2Qc
P5NgPzyCxeN
kpxNqZhMqF0
VWbjhYm9EMo
5cARSR2A7Is
OakmkXnZ80U
HyecnPdRnWu
tnxM6T5e7bd
hywZK2rTRbJ
UBB0o5OsfI5
LotyYIfbZVR
i6UyIR5wT6l
lA4BRvlyS1l
BhEXUVZe2xG
BLYGP0evES5
1uiqnAGN3zo
IbPhVhINeaa
XWQJcIG84ck
wqGD2C3e48z
YLPkFjVLRWA
2zSWKQPQebQ