def inserttimeitem2db(timestr: str): dbname = touchfilepath2depth(getdirmain() / 'data' / 'db' / 'wcdelay.db') conn = lite.connect(dbname) cursor = conn.cursor() tablename = 'wcdelay' def istableindb(tablename: str, dbname: str): cursor.execute("select * from sqlite_master where type='table'") table = cursor.fetchall() print(table) chali = [x for item in table for x in item[1:3]] print(chali) return tablename in chali if not istableindb(tablename, dbname): cursor.execute( f'create table {tablename} (time int primary key, delay int)') conn.commit() print(f"数据表:\t{tablename} 被创建成功。") timetup = time.strptime(timestr, "%Y-%m-%d %H:%M:%S") timest = time.mktime(timetup) elsmin = (int(time.time()) - time.mktime(ttuple)) // 60 cursor.execute(f"insert into {tablename} values(?, ?)", (timest, elsmin)) print(f"数据成功写入{dbname}\t{(timest, elsmin)}") conn.commit() conn.close()
def getownername(): """ 获取登录用户的昵称(NickName),当然默认登录微信 """ # pklabpath = os.path.relpath(touchfilepath2depth(getdirmain() / 'itchat.pkl')) pklabpath = getdirmain() / 'itchat.pkl' if isitchat(pklabpath): return itchat.search_friends()['NickName']
def showbattinfoimg(dbname: str, jingdu: int = 300): ''' show the img for battery info ''' jujinm, battinfodf = getbattinfodb(dbname) print(f"充电记录新鲜度:刚过去了{jujinm}分钟") register_matplotlib_converters() plt.figure(figsize=(36, 12)) plt.style.use("ggplot") # 使得作图自带色彩,这样不用费脑筋去考虑配色什么的; def drawdelayimg(pos, timedfinner, title): # 画出左边界 tmin = timedfinner.index.min() tmax = timedfinner.index.max() shicha = tmax - tmin bianjie = int(shicha.total_seconds() / 40) logstr = f"左边界:{bianjie}秒,也就是大约{int(bianjie / 60)}分钟" print(logstr) # plt.xlim(xmin=tmin-pd.Timedelta(f'{bianjie}s')) plt.subplot(pos) plt.xlim(xmin=tmin) plt.xlim(xmax=tmax + pd.Timedelta(f"{bianjie}s")) # plt.vlines(tmin, 0, int(timedf.max() / 2)) # plt.vlines(tmax, 0, int(timedfinner.max() / 2)) # 绘出主图和标题 plt.scatter(timedfinner.index, timedfinner, s=timedfinner) plt.scatter(timedfinner[timedfinner == 0].index, timedfinner[timedfinner == 0], s=0.5) plt.title(title, fontsize=40) plt.tick_params(labelsize=20) plt.tight_layout() timedf = battinfodf['percentage'] drawdelayimg(321, timedf[timedf.index > timedf.index.max( ) + pd.Timedelta('-2d')], "电量(%,最近两天)") plt.ylim(0, 110) drawdelayimg(312, timedf, "电量(%,全部)") plt.ylim(0, 110) # imgwcdelaypath = touchfilepath2depth(getdirmain() / "img" / "hard" / "battinfo.png") timedf = battinfodf['temperature'] drawdelayimg(322, timedf[timedf.index > timedf.index.max( ) + pd.Timedelta('-2d')], "温度(℃,最近两天)") plt.ylim(20, 40) drawdelayimg(313, timedf, "温度(℃,全部)") plt.ylim(20, 40) fig1 = plt.gcf() imgwcdelaypath = touchfilepath2depth( getdirmain() / "img" / "hard" / "batttempinfo.png") # plt.show() fig1.savefig(imgwcdelaypath, dpi=jingdu) print(os.path.relpath(imgwcdelaypath)) return imgwcdelaypath
def formatmsg(msg): """ 格式化并重构msg,获取合适用于直观显示的用户名,对公众号和群消息特别处置 """ timetuple = time.localtime(msg['CreateTime']) timestr = time.strftime("%Y-%m-%d %H:%M:%S", timetuple) # print(msg['CreateTime'], timetuple, timestr) men_wc = getcfpoptionvalue('everwebchat', get_host_uuid(), 'host_nickname') # 信息延时登记入专门数据库文件 dbname = touchfilepath2depth(getdirmain() / "data" / "db" / f"wcdelay_{men_wc}.db") inserttimeitem2db(dbname, msg['CreateTime']) # owner = itchat.web_init() meu_wc = getcfpoptionvalue('everwebchat', get_host_uuid(), 'host_username') send = (msg['FromUserName'] == meu_wc) if 'NickName' in msg["User"].keys(): showname = msg['User']['NickName'] if len(msg['User']['RemarkName']) > 0: showname = msg['User']['RemarkName'] elif 'UserName' in msg['User'].keys(): showname = msg['User']['UserName'] elif 'userName' in msg['User'].keys(): showname = msg['User']['userName'] else: showname = "" log.warning(f"NickName或者UserName或者userName键值不存在哦") showmsgexpanddictetc(msg) # 过滤掉已经研究过属性公众号信息,对于尚未研究过的显示详细信息 ignoredmplist = getinivaluefromnote('webchat', 'ignoredmplist') imlst = re.split('[,,]', ignoredmplist) ismp = type(msg['User']) == itchat.storage.MassivePlatform if ismp and (showname not in imlst): showmsgexpanddictetc(msg) # print(f"{showname}\t{imlst}") # 处理群消息 if type(msg['User']) == itchat.storage.templates.Chatroom: isfrom = msg['FromUserName'].startswith('@@') isto = msg['ToUserName'].startswith('@@') # qunmp = isfrom or isto # showmsgexpanddictetc(msg) if isfrom: # print(f"(群)\t{msg['ActualNickName']}", end='') showname += f"(群){msg['ActualNickName']}" elif isto: # print(f"(群)\t{msg['User']['Self']['NickName']}", end='') showname += f"(群){msg['User']['Self']['NickName']}" # print(f"\t{msg['Type']}\t{msg['MsgType']}\t{msg['Text']}") # print(f"\t{send}\t{msg['Type']}\t{msg['Text']}") fmtext = msg['Text'] finnalmsg = {'fmId': msg['MsgId'], 'fmTime': timestr, 'fmSend': send, 'fmSender': showname, 'fmType': msg['Type'], 'fmText': fmtext} return finnalmsg
def fetchmjurlfromfile(ownername): """ fetch all zhanji urls from chatitems files """ ownpy = Pinyin().get_pinyin(ownername, '') datapath = getdirmain() / 'data' / 'webchat' datafilelist = os.listdir(datapath) print(datapath) resultlst = list() for filenameinner in datafilelist: if not filenameinner.startswith('chatitems'): continue filename = datapath / filenameinner rstlst = [] # 应对文本文件编码不同的情况 decode_set = [ 'utf-8', 'gb18030', 'ISO-8859-2', 'gb2312', 'gbk', 'Error' ] for dk in decode_set: try: with open(filename, "r", encoding=dk) as f: filelines = f.readlines() rstlstraw = [ inurl for line in filelines for inurl in splitmjurlfromtext(line) ] # drops the duplicates url rstlst = list(set(rstlstraw)) print(len(rstlst), len(rstlstraw), filename, dk) break except UnicodeDecodeError as eef: print(eef) continue except LookupError as eel: print(eel) if dk == 'Error': print(f"{filename}没办法用预设的字符集正确打开") break resultlst.extend(rstlst) resultlst = list(tuple(resultlst)) # print(resultlst[:10]) if (urlsnum := getcfpoptionvalue(f'evermuse_{ownpy}', ownername, 'urlsnum')): if urlsnum == len(resultlst): changed = False log.info(f"战绩链接数量暂无变化, till then is {len(resultlst)}.") else: changed = True urlsnumnew = len(resultlst) setcfpoptionvalue(f'evermuse_{ownpy}', ownername, 'urlsnum', f"{urlsnumnew}") log.info(f"战绩链接数 is set to {urlsnumnew} now.")
def fileetc_reply(msg): innermsg = formatmsg(msg) createtimestr = time.strftime("%Y%m%d", time.localtime(msg['CreateTime'])) filepath = getdirmain() / "img" / "webchat" / createtimestr filepath = filepath / f"{innermsg['fmSender']}_{msg['FileName']}" touchfilepath2depth(filepath) log.info(f"保存{innermsg['fmType']}类型文件:\t{str(filepath)}") msg['Text'](str(filepath)) innermsg['fmText'] = str(filepath) writefmmsg2txtandmaybeevernotetoo(innermsg)
def df2smsdb(indf: pd.DataFrame, tablename="sms"): dbname = touchfilepath2depth(getdirmain() / "data" / "db" / f"phonecontact_{getdeviceid()}.db") checkphoneinfotable(dbname) conn = lite.connect(dbname) recordctdf = pd.read_sql(f"select * from {tablename}", con=conn) indf.to_sql(tablename, con=conn, if_exists="append", index=False) afterinsertctdf = pd.read_sql(f"select * from {tablename}", con=conn) conn.close() logstr = f"记录既有数量:\t{recordctdf.shape[0]}," + f"待添加的记录数量为:\t{indf.shape[0]}," + f"后的记录数量总计为:\t{afterinsertctdf.shape[0]}" log.info(logstr)
def getdatapath(indatapath=None): """ 获取数据所在路径 """ if indatapath is None: indatapath = getdirmain() else: # os.path.expanduser() 解决用户home目录的绝对路径问题 indatapath = os.path.expanduser('~') / Path(indatapath) cpath = indatapath / 'data' / 'freeinfo.txt' return cpath
def log2notetimer(jiangemiao): print(getdirmain()) pathlog = getdirmain() / 'log' files = os.listdir(str(pathlog)) loglines = [] for fname in files[::-1]: with open(pathlog / fname, 'r', encoding='utf-8') as flog: loglines = loglines + [ line.strip() for line in flog if line.find('CRITICAL') >= 0 ] print(f'日志共有{len(loglines)}条记录') # global cfp, inifilepath cfp, cfppath = getcfp('everwork') everlogc = cfp.getint('evernote', 'everlogc') if len(loglines) == everlogc: # <=调整为==,用来应对log文件崩溃重建的情况 log.info('暂无新记录,不更新everworklog笔记。') else: loglinestr = '\n'.join(loglines[::-1]) loglinestr = loglinestr.replace('<', '《') loglinestr = loglinestr.replace('>', '》') loglinestr = loglinestr.replace('&', '并符') loglinestr = loglinestr.replace('=', '等于') loglinestr = '<pre>' + loglinestr + '</pre>' # print(loglinestr) noteguid_lognote = '4a940ff2-74a8-4584-be46-aa6d68a4fa53' try: nstore = get_notestore() imglist2note(nstore, [], noteguid_lognote, 'everwork日志严重错误信息', loglinestr) cfp.set('evernote', 'everlogc', '%d' % len(loglines)) cfp.write(open(cfppath, 'w', encoding='utf-8')) log.info('新的log错误信息成功更新入笔记,将于%d秒后再次自动检查并更新' % jiangemiao) except Exception as eeee: log.critical('处理新log错误信息到笔记时出现未名错误。%s' % (str(eeee))) global timer_log2note timer_log2note = Timer(jiangemiao, log2notetimer, [jiangemiao]) timer_log2note.start()
def showinfostream(keyin: str): print(keyin) dbname = touchfilepath2depth(getdirmain() / "data" / "db" / "phonecontact.db") tablename = "sms" checkphoneinfotable(dbname) conn = lite.connect(dbname) recordctdf = pd.read_sql( f"select * from {tablename} where (number like \'%{keyin}%\') or (name like \'%{keyin}%\')", con=conn) conn.close() return recordctdf
def checknewthenupdatenote(): """ 查验程序文件是否有更新(文件时间作为判断标准)并更新至笔记 """ nbdf = findnotebookfromevernote() ttt = list() findfilesincluedef(getdirmain(), ttt, '.py') ptnfiledesc = re.compile(r"(?:^\"\"\"(.*?)\"\"\"$)", re.MULTILINE | re.DOTALL) ptnnamedesc = re.compile( r"""^def\s+((?:\w+)\(.*?\))\s*:\s*\n (?:\s+\"\"\"(.*?)\"\"\")?""", re.MULTILINE | re.DOTALL) protitle = 'p_ew_' netnblst = list(nbdf.名称) for fn in ttt: nbnamelst = fn.rsplit('/', 1) if len(nbnamelst) == 1: nbnamelst.insert(0, 'root') nbnamelst[0] = protitle + nbnamelst[0] # ['p_ew_jpy', 'chuqin.py'] nbname, filename = nbnamelst[0], nbnamelst[1] if (ennotetime := getcfpoptionvalue('evercode', nbname, filename)) is None: # 获取笔记本的guid,笔记本不存在则构建之 if (nbguid := getcfpoptionvalue('evercode', nbname, 'guid')) is None: logstr = f"笔记本《{nbname}》在ini中不存在,可能需要构造之。" log.info(logstr) if nbname in netnblst: nbguid = nbdf[nbdf.名称 == nbname].index.values[0] # print(nbguid) else: notebook = createnotebook(nbname) netnblst.append(nbname) nbguid = notebook.guid setcfpoptionvalue('evercode', nbname, "guid", nbguid) # 获取笔记的guid,笔记不存在则构建之 if (noteguid := getcfpoptionvalue('evercode', nbname, f'{filename}_guid')) is None: logstr = f"笔记《{filename}》在ini中不存在,可能需要构造之。" log.info(logstr) items = findnotefromnotebook(nbguid, filename) if len(items) > 0: # [noteguid, notetitle, note.updateSequenceNum] noteguid = items[-1][0] else: note = makenote(gettoken(), get_notestore(), filename, parentnotebook=nbguid) noteguid = note.guid
def showdelayimg(dbname: str, jingdu: int = 300): ''' show the img for wcdelay ''' jujinm, timedf = getdelaydb(dbname) # timedf.iloc[-1] print(f"记录新鲜度:出炉了{jujinm}分钟") register_matplotlib_converters() plt.figure(figsize=(36, 12)) plt.style.use("ggplot") # 使得作图自带色彩,这样不用费脑筋去考虑配色什么的; def drawdelayimg(pos, timedfinner, title): # 画出左边界 tmin = timedfinner.index.min() tmax = timedfinner.index.max() shicha = tmax - tmin bianjie = int(shicha.total_seconds() / 40) print(f"左边界:{bianjie}秒,也就是大约{int(bianjie / 60)}分钟") # plt.xlim(xmin=tmin-pd.Timedelta(f'{bianjie}s')) plt.subplot(pos) plt.xlim(xmin=tmin) plt.xlim(xmax=tmax + pd.Timedelta(f"{bianjie}s")) # plt.vlines(tmin, 0, int(timedf.max() / 2)) plt.vlines(tmax, 0, int(timedfinner.max() / 2)) # 绘出主图和标题 plt.scatter(timedfinner.index, timedfinner, s=timedfinner) plt.scatter(timedfinner[timedfinner == 0].index, timedfinner[timedfinner == 0], s=0.5) plt.title(title, fontsize=40) plt.tick_params(labelsize=20) plt.tight_layout() drawdelayimg( 211, timedf[timedf.index > timedf.index.max() + pd.Timedelta('-2d')], "信息频率和延时(分钟,最近两天)") drawdelayimg(212, timedf, "信息频率和延时(分钟,全部)") fig1 = plt.gcf() plt.show() imgwcdelaypath = touchfilepath2depth(getdirmain() / "img" / "webchat" / "wcdelay.png") fig1.savefig(imgwcdelaypath, dpi=jingdu) print(os.path.relpath(imgwcdelaypath)) return imgwcdelaypath
def makeexcelfileownpy(ownername): """ init excelpath for dataset store, and ownername in pinyin """ ownpy = Pinyin().get_pinyin(ownername, '') excelpath = getdirmain() / 'data' / 'muse' / f'huojiemajiang_{ownpy}.xlsx' touchfilepath2depth(excelpath) if not excelpath.exists(): excelwriter = pd.ExcelWriter(excelpath) clnames = [ 'roomid', 'time', 'guest', 'guestid', 'client', 'zimo', 'jingding', 'dianpao', 'laizigang', 'score', 'host' ] rstdf = pd.DataFrame(list(), columns=clnames) rstdf.to_excel(excelwriter, index=False, encoding='utf-8') excelwriter.close() return excelpath, ownpy
def showpngimgfrombytes(inputbytes: bytes): imgfrombytes = Image.open(BytesIO(inputbytes)) # print(imgfrombytes._getexif()) # 拉回来的bytes中不包含任何exif值 # print(sha3hexstr(imgfrombytes.getdata())) # 但是data就是不一样啊 # print(sha3hexstr(imgfrombytes)) # bytes图片数据集就更不用说了,就是不一样 # 转成array格式——常规 simgnp = np.array(imgfrombytes) print(sha3hexstr(simgnp)) # 尼玛,转换成np数组倒是终于一样了^_^。我的老天爷啊!好吧 # imgbytestmp = BytesIO() # imgfrombytes.save(imgbytestmp, format='PNG') # print(sha3hexstr(imgbytestmp.getvalue())) # 展示array代表的图像 plt.imshow(simgnp) # plt.show() imgtmppath = getdirmain() / 'img' / 'wcheadimg.png' plt.savefig(imgtmppath) print(sha3hexstr(np.array( Image.open(imgtmppath)))) # 非得写入文件,再提取回来序列值就一样了,唉
def log2note(noteguid, loglimit, levelstr='', notetitle='everwork日志信息'): namestr = 'everlog' if levelstr == 'CRITICAL': levelstrinner = levelstr + ':' levelstr4title = '严重错误' countnameinini = 'everlogcc' else: levelstrinner = levelstr levelstr4title = '' countnameinini = 'everlogc' # log.info(getdirmain()) pathlog = getdirmain() / 'log' files = os.listdir(str(pathlog)) loglines = [] for fname in files[::-1]: # log.info(fname) if not fname.startswith('everwork.log'): log.warning(f'文件《{fname}》不是合法的日志文件,跳过。') continue with open(pathlog / fname, 'r', encoding='utf-8') as flog: charsnum2showinline = getinivaluefromnote('everlog', 'charsnum2showinline') # print(f"log行最大显示字符数量为:\t{charsnum2showinline}") loglines = loglines + [line.strip()[:charsnum2showinline] for line in flog if line.find(levelstrinner) >= 0] ptn = re.compile('\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}') tmlst = [pd.to_datetime(re.match(ptn, x).group()) for x in loglines if re.match(ptn, x)] loglines = [x for x in loglines if re.match(ptn, x)] logsr = pd.Series(loglines, index=tmlst) logsr = logsr.sort_index() # print(logsr.index) # print(logsr) loglines = list(logsr) # log.info(loglines[:20]) # print(len(loglines)) print(f'日志的{levelstr4title}记录共有{len(loglines)}条,只取时间最近的{loglimit}条') if not (everlogc := getcfpoptionvalue(namestr, namestr, countnameinini)): everlogc = 0
def phonecontact2db(): """ 手机联系人数据入库 """ ctstr = termux_contact_list() ctlst = eval(ctstr) ctdf = pd.DataFrame(ctlst) ctdf['number'] = ctdf['number'].apply(lambda x: x.replace(" ", '')) ctdf.drop_duplicates('number', inplace=True) ctdf['appendtime'] = time.time() print(ctdf.shape[0]) tablename = "phone" dbname = touchfilepath2depth(getdirmain() / "data" / "db" / f"phonecontact_{getdeviceid()}.db") checkphoneinfotable(dbname) conn = lite.connect(dbname) recordctdf = pd.read_sql(f"select * from {tablename}", con=conn) ctdf.to_sql(tablename, con=conn, if_exists="append", index=False) afterinsertctdf = pd.read_sql(f"select * from {tablename}", con=conn) conn.close() logstr = f"联系人记录既有数量:\t{recordctdf.shape[0]}," + f"待添加的联系人记录数量为:\t{ctdf.shape[0]}," + f"添加后的联系人记录数量总计为:\t{afterinsertctdf.shape[0]}" log.info(logstr)
def fetchmjfang(owner): """ 从数据目录中符合命名标准的文本档案库中提取开房信息(发布时间和房号) param owner: 文本档案库的所属主人 return: DataFrame 开房信息df """ datapath = getdirmain() / 'data' / 'webchat' datafilelist = os.listdir(datapath) resultlst = list() # http://s0.lgmob.com/h5_whmj_qp/?d=217426 ptn = re.compile("h5_whmj_qp/\\?d=(\\d+)") for filenameinner in datafilelist: if not filenameinner.startswith('chatitems'): continue filename = datapath / filenameinner rstlst = [] # 应对文本文件编码不同的情况 decode_set = [ 'utf-8', 'gb18030', 'ISO-8859-2', 'gb2312', 'gbk', 'Error' ] for dk in decode_set: try: with open(filename, "r", encoding=dk) as f: filelines = f.readlines() # 2020-02-13 11:27:21 True 搓雀雀(群)白晔峰 Text http://s0.lgmob.com/h5_whmj_qp/?d=852734 fanglst = [ line.strip() for line in filelines if re.search(ptn, line) ] rstlst = [[ pd.to_datetime(lnspt[0]), re.findall(r'\b\w+\b', lnspt[2])[-1], int(lnspt[-1].split('=')[-1]) ] for line in fanglst if (lnspt := line.split('\t'))] print(filename, dk) break except UnicodeDecodeError as eef: continue
def getphoneinfodb(): """ 从联系人信息数据表提取数据(DataFrame) """ # tablename = "wcdelaynew" dbname = touchfilepath2depth(getdirmain() / "data" / "db" / f"phonecontact_{getdeviceid()}.db") tablename = "phone" checkphoneinfotable(dbname) conn = lite.connect(dbname) recordctdf = pd.read_sql(f"select * from {tablename}", con=conn) conn.close() recordctdf["appendtime"] = recordctdf["appendtime"].apply( lambda x: pd.to_datetime( time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(x)))) if (tdfsize := recordctdf.shape[0]) != 0: print(f"联系人记录共有{tdfsize}条") jujinmins = int( (pd.to_datetime(time.ctime()) - recordctdf['appendtime'].max()).total_seconds() / 3600)
def getcfp(cfpfilename: str): cfpson = ConfigParser() inipathson = Path(getdirmain()) / 'data' / (cfpfilename + '.ini') touchfilepath2depth(inipathson) try: cfpson.read(inipathson, encoding='utf-8') except (DuplicateSectionError, DuplicateOptionError) as dse: log.critical( f"ini文件《{inipathson}》中存在重复的section或option名称,备份文件并试图修复文件……{dse}") fixinifile(inipathson) except Exception as eee: log.critical(eee) try: cfpson.read(inipathson, encoding='utf-8') log.critical(f"ini文件《{inipathson}》修复成功!!!") except Exception as e: log.critical(f"读取配置文件《{inipathson}》时失败!!!{e}") log.critical(f"试图强制删除该配置文件《{inipathson}》") os.remove(inipathson) log.critical(f"配置文件《{inipathson}》被强制删除!!!") return return cfpson, inipathson
def getservice(): """ 构建Gmail连接服务service,全局化,可以复用 """ global service if service: log.info(f"Gmail连接服务已经存在,无需重新构建\t{service}") return service creds = None # The file token.pickle stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. imppath = getdirmain() / "data" / 'imp' picklepath = imppath / 'token.pickle' credentialspath = imppath / 'gmail_credentials.json' if os.path.exists(picklepath): with open(picklepath, 'rb') as token: creds = pickle.load(token) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( credentialspath, SCOPES) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(picklepath, 'wb') as token: pickle.dump(creds, token) service = build('gmail', 'v1', credentials=creds) log.info(f"成功构建Gmail连接服务\t{service}") return service
plt.show() imgwcdelaypath = touchfilepath2depth(getdirmain() / "img" / "webchat" / "wcdelay.png") fig1.savefig(imgwcdelaypath, dpi=jingdu) print(os.path.relpath(imgwcdelaypath)) return imgwcdelaypath # %% [markdown] # ## 主函数main # %% if __name__ == "__main__": if not_IPython(): logstrouter = "运行文件\t%s" % __file__ log.info(logstrouter) # owner = 'heart5' owner = '白晔峰' dbnameouter = touchfilepath2depth(getdirmain() / "data" / "db" / f"wcdelay_{owner}.db") xinxian, tdf = getdelaydb(dbnameouter) print(xinxian) print(tdf.sort_index(ascending=False)) if not_IPython(): logstrouter = "文件%s运行结束" % (__file__) log.info(logstrouter)
# + import time import numpy as np import pandas as pd import matplotlib.pyplot as plt from binascii import hexlify, unhexlify from PIL import Image from pandas.plotting import register_matplotlib_converters from io import BytesIO import pathmagic with pathmagic.context(): from func.first import touchfilepath2depth, getdirmain qrpath = getdirmain() / "QR.png" with open(qrpath, 'rb') as fqr: fbytes = fqr.read() print(type(fbytes), f"{fbytes[:20]}\t……") fbyteshfl = hexlify(fbytes).decode() print(f"fbyteshfl:\t{hexlify(fbytes).decode()[:40]}\t……") imgfrombytes = Image.open(BytesIO(fbytes)) print(imgfrombytes) imgnp = np.array(imgfrombytes) print(imgnp) # 展示array代表的图像 plt.figure(figsize=(10,5)) #设置窗口大小 plt.suptitle('bytes字节流恢复图片') # 图片名称 plt.subplot(1,2,1), plt.title('QR(原图)') plt.imshow(imgnp), plt.axis('off')
def getmail(hostmail, usernamemail, passwordmail, port=993, debug=False, mailnum=100000, dirtarget='Inbox', unseen=False, topicloc='subject', topic='', datadir=os.path.join(getdirmain(), 'data', 'work')): def parseheader(message): headermsg = [] """ 解析邮件首部 """ # 发件人 # mailfrom = email.utils.parseaddr(message.get('from'))[1] # print('From:', mailfrom) # 时间 datestr = message.get('date') if datestr is None: log.error('从邮件头部提取时间失败,只好从邮件内容中寻找时间信息。') pattern = re.compile( r'(?:X-smssync-backup-time: )(?P<date>\d{1,2} \w{3} \d{4} \d{2}:\d{2}:\d{2})', re.I) items = re.split(pattern, str(message)) if len(items) > 1: print(items[1]) datemail = datetime.datetime.strptime(items[1], '%d %b %Y %H:%M:%S') else: log.critical("从邮件内容中也没有找到有效的时间信息。") datemail = None # print(message) else: datemail = email.utils.parsedate_to_datetime(message.get('date')) localdate = datemail.astimezone( datetime.timezone(datetime.timedelta(hours=8))) # print('Date:', localdate) headermsg.append(localdate) # if mailfrom.startswith('*****@*****.**'): # headermsg.append(str(localdate) + '\t发出\t') # else: # headermsg.append(str(localdate) + '\t收到\t') # 主题 subject = message.get('subject') # print(subject) subjectdecoded = str( email.header.make_header(email.header.decode_header(subject))) # print(subjectdecoded) headermsg.append(subjectdecoded) # 发件人 mailfrom = email.utils.parseaddr(message.get('from'))[1] # print('From:', mailfrom) headermsg.append(mailfrom) # 收件人 # print(message.get('to')) mailto = email.utils.parseaddr(message.get('to'))[1] # print('To:', mailto) headermsg.append(mailto) # print('To:', message.get('to')) # 抄送人 # print('Cc:', email.utils.parseaddr(message.get_all('cc'))[1]) return headermsg def parsebody(message, msgencoding): bodymsg = [] """ 解析邮件/信体 """ # 循环信件中的每一个mime的数据块 for part in message.walk(): partitem = [] # 这里要判断是否是multipart,是的话,里面的数据是一个message 列表 if not part.is_multipart(): # charset = part.get_charset() # print('charset: ', charset) contenttype = part.get_content_type() # print('content-type', contenttype) namepart = part.get_param("name") # 如果是附件,这里就会取出附件的文件名 if namepart: # 有附件 # 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名 fh = email.header.Header( namepart) # =?gb18030?B?tbyz9sr9vt0ueGxz?= # print(fh) fdh = email.header.decode_header( fh ) # [(b'=?gb18030?B?tbyz9sr9vt0ueGxz?=', 'us-ascii')] # print(fdh) fnamestr = fdh[0][0].decode( fdh[0][1]) # bytes to str with it's encoding fname = email.header.make_header( email.header.decode_header( fnamestr)) # Header类型的数据,内容为“导出数据.xls” fname = str(fname) # 字符串格式的“导出数据.xls” log.info(f'附件名:{fname}') attach_data = part.get_payload( decode=True) # 解码出附件数据,然后存储到文件中 pointat = fname.rfind('.') timenowstr = datetime.datetime.now().strftime( '__%Y%m%d%H%M%S_%f') datadiri = datadir if fname.startswith('销售订单'): # print(fname) datadiri = os.path.join(datadiri, '销售订单') elif fname.startswith('订单明细'): # print(fname) datadiri = os.path.join(datadiri, '订单明细') attachfile = os.path.join( datadiri, fname[:pointat] + timenowstr + fname[pointat:]) try: fattach = open(attachfile, 'wb') # 注意一定要用wb来打开文件,因为附件一般都是二进制文件 except Exception as eeee: print(eeee) attachfile = os.path.join(datadiri, '未名文件' + timenowstr) fattach = open(attachfile, 'wb') fattach.write(attach_data) fattach.close() partitem.append('attach') partitem.append(attachfile) else: # 不是附件,是文本内容 # print(part) if not contenttype == 'text/plain': # 只要plain文本部分 continue partdecode = part.get_payload(decode=True) # print(partdecode) bodystr = partdecode.decode(msgencoding) # 解码出文本内容 # print(bodystr) bodystr = BeautifulSoup(bodystr, "html.parser"). \ get_text().replace('\r', '').replace('\n', '').replace('\t', '') # 文本化后去掉回车、换行符等 # print(bodystr) partitem.append('text') partitem.append(bodystr) # pass # print '+'*60 # 用来区别各个部分的输出 if len(partitem) > 0: bodymsg.append(partitem) return bodymsg @trycounttimes2(f'{hostmail}邮箱服务器') def getservmail(): servmail = imaplib.IMAP4_SSL(hostmail, port) servmail.login(usernamemail, passwordmail) log.info(f'成功登陆到邮箱:{hostmail}。{servmail}') return servmail serv = getservmail() # if debug: # serv.debug = 4 if debug: typ, dirs = serv.list() # print(dirs) for itemdirs in dirs: print(itemdirs.decode('ascii').split(') \"/\" \"')[1][:-1], end='\t') print() typ, dirs = serv.list(directory=dirtarget) print(typ, dirs) if unseen: statutuplestr = '(unseen)' else: statutuplestr = '(messages)' print(statutuplestr) # print(serv.status(dirtarget,statutuplestr)) # print(serv.status('"[Gmail]/All Mail"','(messages)')) # print(serv.status('Ifttt/Notification','(UIDVALIDITY)')) # print(serv.status('Ifttt/SmsLog','(UIDNEXT)')) # print(serv.select('"&TgCCLH9RU8s-"')) mailstatus = list() typess, data = serv.select(dirtarget) mailstatus.append(int(data[0].decode('ascii'))) if len(topic) > 0: # 搜索邮件内容 # typ, data = serv.search(None, '(TO "*****@*****.**" subject "sms")' ) # typ, data = serv.search(None, '(from "*****@*****.**")' ) # typ, data = serv.search(None, '(subject "%s" since "01-Jan-2017")' %zhuti) # typ, data = serv.search(None, '(unseen subject "Status")') zhuti = topic serv.literal = zhuti.encode('utf-8') # typ, data = serv.uid('SEARCH', 'CHARSET', 'UTF-8', 'Since','22-Jan-2018', 'text') # typ, data = serv.search('utf-8', 'Since','01-Feb-2018','text') if unseen: typ, data = serv.search('utf-8', 'unseen', topicloc) else: typ, data = serv.search('utf-8', topicloc) # typ, data = serv.search(None, 'text "Android"') else: if unseen: typ, data = serv.search(None, 'unseen') else: typ, data = serv.search(None, 'ALL') serv.close() serv.logout() mailstatus.append(len(data[0].split())) if debug: print(data[0].decode('ascii').split()[::-1]) print(mailstatus) numlist = data[0].decode('ascii').split()[::-1] if len(numlist) == 0: # 无新邮件则返回False newstr = '新' if unseen else '' topicstr = '主题为“%s”的' % topic if len(topic) > 0 else '' log.info('邮箱目录《%s》中没有%s%s邮件' % (dirtarget, topicstr, newstr)) return False if len(numlist) > mailnum: numlist = numlist[:mailnum] def getnummail(numlistinside, mailitemsinside): countstart = len(mailitemsinside) counttarget = len(numlistinside) log.info('已有%d封邮件,准备处理%d封邮件……' % (countstart, counttarget)) servinner = getservmail() type, data = servinner.select(dirtarget) count = 0 totalcount = 0 for num in numlistinside: # print(num) if (totalcount - count) >= 20: log.critical('无法正确处理的邮件超过%d封,此邮件编码列表跳过正常处理流程。%s' % (totalcount - count, numlistinside)) log.info('实际处理邮件%d封,该邮件编码列表总数量为%d。' % (count, len(numlistinside))) return numlistinside totalcount += 1 mailitem = [] message = None try: typ, data = servinner.fetch(num, '(RFC822)') # print(data) text = data[0][1] # text = text.replace('gb-2312','gb2312') message = email.message_from_bytes(text) # 转换为email.message对象 # print(message) pattern = re.compile( r"(UTF-8)|(gb2312)|(gbk)|(gb18030)|(cp936)", re.I) subject = message.get('subject') resultre = re.search(pattern, str(subject)) if resultre: mailencodings = resultre.group() if mailencodings.lower().startswith( 'gb'): # gb18030是最大的字符集,向下兼容gb2312和gbk mailencodings = 'gb18030' else: mailencodings = 'UTF-8' # print(mailencodings) # print(message) mailitem.append(parseheader(message)) mailitem.append(parsebody(message, mailencodings)) # print(mailitem) mailitemsinside.append(mailitem) count = count + 1 except ConnectionAbortedError as cae: log.critical("获取邮件[%s,%d/%d]时出现ConnectionAbortedError错误。%s" % (num, count, totalcount, str(cae))) except OSError as ose: if ose.errno == 10053: log.critical("获取邮件[%s,%d/%d]时出现操作系统错误,和服务器的连接被强行终止。%s" % (num, count, totalcount, str(ose))) else: log.critical("获取邮件[%s,%d/%d]时出现操作系统错误。%s" % (num, count, totalcount, str(ose))) except imaplib.IMAP4.error as iie: log.critical("获取邮件[%s,%d/%d]时出现imaplib.IMAP4.error错误。%s" % (num, count, totalcount, str(iie))) except imaplib.IMAP4.abort as iia: log.critical( "获取邮件[%s,%d/%d]时出现imaplib.IMAP4.abort错误,和服务器的连接被强行终止。%s" % (num, count, totalcount, str(iia))) except UnicodeDecodeError as ude: log.critical("处理邮件[%s,%d/%d]内容时出现UnicodeDecodeError错误。%s" % (num, count, totalcount, str(ude))) except AttributeError as abe: log.critical("处理邮件[%s,%d/%d]时出现AttributeError错误。%s" % (num, count, totalcount, str(abe))) except TypeError as te: log.critical("处理邮件[%s,%d/%d]时出现TypeError错误。%s" % (num, count, totalcount, str(te))) print(message) except Exception as eeefetch: log.critical("处理邮件[%s,%d/%d]时出现未名错误。%s" % (num, count, totalcount, str(eeefetch))) finally: log.info(f"邮件编码列表:{numlistinside}") log.info(f"邮件主题列表:{mailitemsinside}") servinner.close() servinner.logout() log.info('实际处理邮件%d封,该邮件编码列表总数量为%d。' % (count, len(numlistinside))) mailitemsresult = list() kelidu = 200 fenjie = int((len(numlist)) / kelidu) threadlist = [] for i in range(fenjie + 1): inputnumlist = numlist[(i * kelidu):(i + 1) * kelidu] # print(inputnumlist) t = threading.Thread(target=getnummail, args=( inputnumlist, mailitemsresult, )) threadlist.append(t) log.info('处理邮箱目录%s,共计有%d个线程准备运行。' % (dirtarget, len(threadlist))) threadnum = 8 threadzushu = int(len(threadlist) / threadnum) for i in range(threadzushu + 1): threadxiaozu = threadlist[(i * threadnum):(i + 1) * threadnum] # if i > 0: # break # threadxiaozu = threadlist[140:141] log.info('此批次启动%d个线程:' % len(threadxiaozu)) for t in threadxiaozu: t.start() # log.info('%d个线程全部启动……' % len(threadxiaozu)) for t in threadxiaozu: t.join() log.info('累积有[%d/%d]个线程执行完毕。' % (i * threadnum + len(threadxiaozu), len(threadlist))) log.info('总计的%d个线程全部执行完毕!' % len(threadlist)) return mailitemsresult
n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75) plt.xlabel('Smarts') plt.ylabel('Probability') plt.title('Histogram of IQ') plt.text(60, .025, r'$\mu=100,\ \sigma=15$') plt.axis([40, 160, 0, 0.03]) plt.grid(True) plt.show() # + import pathmagic with pathmagic.context(): from func.first import touchfilepath2depth, getdirmain, dirmainpath from work.zymessage import searchcustomer, searchqiankuan, searchpinxiang print(getdirmain()) rstfile, rststr = searchqiankuan(['兴客隆', '汉阳']) print(rststr) linelist = rststr.split('\n') print(linelist) figure(figsize=(8, 6), dpi=150) for i in range(len(linelist)): plt.text(0.02, 0.9 - i * 0.07, linelist[i], fontsize=8, bbox=dict(facecolor='red', alpha=0.1)) plt.show() # -
cfpin.add_section(sectionname) cfpin.write(open(cfpinpath, 'w', encoding='utf-8')) return else: return cfpin.items(f'{sectionname}') is_log_details = getcfpoptionvalue('everinifromnote', 'everwork', 'logdetails') # cfp, inifilepath = getcfp('everwork') # cfpdata, inidatanotefilepath = getcfp('everdatanote') # cfplife, inilifepath = getcfp('everlife') # cfpzysm, inizysmpath = getcfp('everzysm') # cfpworkplan, iniworkplanpath = getcfp('everworkplan') if __name__ == '__main__': if not_IPython() and is_log_details: print(f'开始测试文件\t{__file__}') # cp, cppath = getcfp('everwork') # print(cp, cppath) cfpapiname = 'everapi' inipathson = Path(getdirmain()) / 'data' / (cfpapiname + '.ini') name = '[notestore]' cp, cppath = getcfp(cfpapiname) print(cp) # removesection(cfpapiname, nssectionname) # ict = fixinifile(inipathson) seccontent = getcfpsectionvalue('everwork', 'evernote') print(seccontent) if not_IPython() and is_log_details: print('Done.')
from func.first import getdirmain, touchfilepath2depth from func.configpr import getcfpoptionvalue, setcfpoptionvalue from muse.majjianghuojie import fetchmjfang, zhanjidesc, updateurllst, updateallurlfromtxt from life.wccontact import getownername # - updateallurlfromtxt('白晔峰') # %time # #### 【漏掉的战绩链接数据直接入库】 # + owner = getownername() # owner = 'heart5' fpath = getdirmain() / 'data' / 'webchat' / f'chatitems({owner}).txt' fpath ptn = re.compile('three') with open(fpath) as f: threelst = [ x.strip().split('\t')[-1] for x in f.readlines() if re.findall(ptn, x)] urllst = [x for x in threelst if x.startswith('http')] for url in urllst: updateurllst(url) # - # ##### ~~从文本库文件中提取链接~~ specialurl = "updateurllst(url)" updateurllst()
把格式化好的微信聊天记录写入文件,并根据笔记ini设定更新相应账号的聊天笔记 """ # 判断是否延时并增加提示到条目内容中 if (humantimestr := gethumantimedelay(inputformatmsg['fmTime'])): inputformatmsg['fmText'] = f"[{humantimestr}]" + inputformatmsg['fmText'] msgcontent = "" for item in inputformatmsg: if item == "fmId": continue msgcontent += f"{inputformatmsg[item]}\t" # 去除最后一个\t msgcontent = msgcontent[:-1] print(f"{msgcontent}") men_wc = getcfpoptionvalue('everwebchat', get_host_uuid(), 'host_nickname') chattxtfilename = str(getdirmain() / 'data' / 'webchat' / f'chatitems({men_wc}).txt') chatitems = readfromtxt(chattxtfilename) global note_store # webchats.append(chatmsg) chatitems.insert(0, msgcontent) write2txt(chattxtfilename, chatitems) # if inputformatmsg['fmText'].startswith('收到转账'): # showjinzhang() # if inputformatmsg['fmText'].startswith('微信支付收款'): # showshoukuan() # readinifromnote() # cfpfromnote, cfpfromnotepath = getcfp('everinifromnote')
def getcutpoint(inputdatapath): """ 根据时间间隔找到分割点,生成最近一次的图像和全部综合图像并返回 """ totalmen = gettotalmem(getdatapath(inputdatapath)) inputdf = getdatadf(getdatapath(inputdatapath)) ds = inputdf['time'] - inputdf['time'].shift() deltads = ds[ds > getdelta()] outlst = list() for ix in deltads.index: ipos = list(inputdf.index).index(ix) # 处理内存占满(但未重启)的特殊情况 if inputdf.iloc[ipos - 1]['freeper'] == 0: continue print() print(ipos, ix, deltads[ix]) outlst.append(ipos) # bfdf = inputdf[inputdf.index >= (ix - deltads[ix] + pd.Timedelta(minutes=-5))] # tmpdf = bfdf[bfdf.index < (ix + pd.Timedelta(minutes=5))] # print(tmpdf) outlst.insert(0, 0) outlst.append(inputdf.shape[0]) plt.rcParams['font.sans-serif'] = 'SimHei' olen = len(outlst) if olen == 2: picheight = 1 elif olen == 3: picheight = 2 else: picheight = 3 plt.figure(figsize=(10, 10 * picheight)) imgpath = getdirmain() / 'img' / 'freemen.png' touchfilepath2depth(imgpath) # fig, ax1 = plt.subplots() # 针对数据集周期次数进行处理,主要是处理小于三次的情况 if len(outlst) > 3: plt.subplot(311) elif len(outlst) == 3: plt.subplot(211) # 最近数据集图形化输出 plt.ylabel(f'空闲内存百分比({totalmen}G)') cutdf = inputdf.iloc[outlst[-2]:outlst[-1]] plt.plot(cutdf.index, cutdf['freeper']) plt.ylim(0, 100) plt.title('最近一次运行') plt.annotate(cutdf.index[0].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[0], cutdf.iloc[0, 1]]) plt.annotate(cutdf.index[-1].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[-1], cutdf.iloc[-1, 1]]) # 针对单次(一般也是首次运行)数据集进行处理 if len(outlst) == 2: plt.savefig(imgpath) return str(imgpath) # 针对数据集周期次数进行处理,主要是处理小于三次的情况 if len(outlst) == 3: plt.subplot(212) elif len(outlst) > 3: plt.subplot(312) plt.ylabel(f'空闲内存百分比({totalmen}G)') plt.ylim(0, 100) plt.title('最近两次运行') twolst = outlst[-3:] for i in range(len(twolst) - 1): cutdf = inputdf.iloc[twolst[i]:twolst[i + 1]] plt.plot(cutdf.index, cutdf['freeper']) plt.annotate(cutdf.index[0].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[0], cutdf.iloc[0, 1]]) plt.annotate(cutdf.index[-1].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[-1], cutdf.iloc[-1, 1]]) # 综合(全部)数据集图形输出 # 针对仅有两次数据集进行处理 if len(outlst) == 3: plt.savefig(imgpath) return str(imgpath) else: plt.subplot(313) plt.ylabel(f'空闲内存百分比({totalmen}G)') plt.ylim(0, 100) plt.title('历次运行') for i in range(len(outlst) - 1): cutdf = inputdf.iloc[outlst[i]:outlst[i + 1]] plt.plot(cutdf.index, cutdf['freeper']) plt.annotate(cutdf.index[0].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[0], cutdf.iloc[0, 1]]) plt.annotate(cutdf.index[-1].strftime("%y-%m-%d %H:%M"), xy=[cutdf.index[-1], cutdf.iloc[-1, 1]]) plt.savefig(imgpath) return str(imgpath)
def getdbname(dbpath: str, ownername: str, title='wccontact'): return touchfilepath2depth(getdirmain() / dbpath / f"{title}_{ownername}.db")
def getworknewmail(): """ 获取work标签下的新邮件并保存附件 """ global service service = getservice() # Call the Gmail API results = service.users().labels().list(userId='me').execute() labels = results.get('labels', []) """获取目标label的id""" worklabelname = "Work" worklabelid = None if not labels: print('No labels found.') else: # print('Labels:') # pprint.pprint(labels) for label in labels: # print(label['name'], label['id'], label['messagesTotal'], label['messagesUnread']) if label['name'] == worklabelname: # pprint.pprint(label) worklabelid = label['id'] # 获取目标label下的未读邮件信息 label4work = service.users().labels().get(userId='me', id=worklabelid).execute() pprint.pprint(label4work) msg4work = service.users().messages().list(userId='me', labelIds=[worklabelid], q='is:unread').execute() pprint.pprint(msg4work) print(f"未读邮件数量为:{msg4work['resultSizeEstimate']}") if msg4work['resultSizeEstimate'] == 0: log.info(f"目录《{worklabelname}》\t{worklabelid}没有新邮件") return # 从配置文件读出已处理邮件列表并装配成list待用 msgidsrecordstr = getcfpoptionvalue('evergmailc', 'mail', '已处理') if not msgidsrecordstr: msgidsrecordlst = [] else: msgidsrecordlst = msgidsrecordstr.split(',') # 遍历待处理邮件并做相应处置 msgidlst = list() for msg in msg4work['messages']: # 遍历,通过头部插入实现升序排列 msgidlst.insert(0, msg['id']) msgchulilst = list() for msgid in msgidlst: # 判断是否在已处理列表中,是则跳过继续循环 if msgid in msgidsrecordlst: print(f"邮件\t{msgid}\t已处理过") continue # 获取邮件 mailmsg = service.users().messages().get(userId='me', id=msgid).execute() print(msgid) # pprint.pprint(mailmsg) # print(f"{mailmsg['snippet']}") # 处理邮件标题 hnamelst = list() hvaluelst = list() for headerinner in mailmsg['payload']['headers']: hnamelst.append(headerinner['name']) hvaluelst.append(headerinner['value']) headercontentdict = dict(zip(hnamelst, hvaluelst)) pprint.pprint(headercontentdict) msgheader = headercontentdict['Subject'] print(msgheader) # 处理邮件中的附件 pprint.pprint(mailmsg['payload']['parts']) msgattachmentslst = list() for part in mailmsg['payload']['parts']: attachname = part['filename'] if attachname: pprint.pprint(part) attach = service.users().messages().attachments().get( userId='me', id=part['body']['attachmentId'], messageId=msgid).execute() file_data = base64.urlsafe_b64decode( attach['data'].encode('utf-8')) # 处理附件文件名,按照主题保存到相应的目录下 datadirwork = getdirmain() / 'data' / 'work' pointat1 = attachname.rfind('.') timenowstr = datetime.datetime.now().strftime( '__%Y%m%d%H%M%S_%f') datadiri = datadirwork if attachname.startswith('销售订单'): # print(fname) datadiri = os.path.join(datadirwork, '销售订单') elif attachname.startswith('订单明细'): # print(fname) datadiri = os.path.join(datadirwork, '订单明细') attachfile = os.path.join( datadiri, attachname[:pointat1] + timenowstr + attachname[pointat1:]) print(attachfile, attach['size']) touchfilepath2depth(Path(attachfile)) f = open(attachfile, 'wb') f.write(file_data) f.close() msgattachmentslst.append(attachname) print(msgattachmentslst) # credentials只有读取的权限,无法做出写入和更改处理,修改操作只能先注释掉 # modifylabeldict = {'addLabelIds':[], 'removeLabelIds':['Unread']} # modifymsg = service.users().messages().modify(userId='me', id=msg['id'], body=modifylabeldict).execute() print(f"邮件{msgid}处理完毕,标记为已处理") msgidsrecordlst.insert(0, msgid) msgchulilst.append(msgid) log.info(f"邮件{msgid}\t{msgheader}处理完毕,附件列表为:{msgattachmentslst}") setcfpoptionvalue('evergmailc', 'mail', '已处理', ','.join(msgidsrecordlst)) log.info(f"共有{len(msgchulilst)}封邮件处理完毕,邮件编号列表:{msgchulilst}")