def demo_datetime(): from pyxllib.debug.dprint import dprint dprint(Datetime.now()) # [05]arrow_.py/247: Datetime.now()<__main__.Datetime>=<Datetime [2020-06-01T16:54:45.365788+08:00]> # 获取文件的创建时间,st_ctime获得的事timestamp格式 1579529472.2958975 dprint(Datetime(os.stat(__file__).st_ctime))
def int2myalphaenum(n): """ :param n: 0~52的数字 """ if 0 <= n <= 52: return '_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[n] else: dprint(n) # 不在处理范围内的数值 raise ValueError
def demo_timer(): """该函数也可以用来测电脑性能 代码中附带的示例结果是我在自己小米笔记本上的测试结果 Intel(R) Core(TM) i7-10510U CPU@ 1.80GHz 2.30 GHz,15G 64位 """ from pyxllib.debug.dprint import dformat, dprint import numpy print('1、普通用法(循环5*1000万次用时)') timer = Timer('循环') timer.start() for _ in range(5): for _ in range(10**7): pass timer.stop() timer.report() # 循环 用时: 0.727s print('2、循环多轮计时') timer = Timer('自己算均值标准差耗时') # 数据量=200是大概的临界值,往下自己算快,往上用numpy算快 # 临界量时,每万次计时需要0.45秒。其实整体都很快影响不大,所以Timer最终统一采用numpy来运算。 data = list(range(10)) * 20 for _ in range(5): timer.start() # 必须明确指定每次的 开始、结束 时间 for _ in range(10**4): n, sum_ = len(data), sum(data) mean1 = sum_ / n std1 = math.sqrt((sum([(x - mean1)**2 for x in data]) / n)) timer.stop() # 每轮结束时标记 timer.report() # 自己算均值标准差耗时 总耗时: 2.214s 均值标准差: 0.443±0.008s 总数: 5 最小值: 0.435s 最大值: 0.459s dprint(mean1, std1) # [05]timer.py/97: mean1<float>=4.5 std1<float>=2.8722813232690143 print('3、with上下文用法') with Timer('使用numpy算均值标准差耗时') as t: for _ in range(5): t.start() for _ in range(10**4): mean2, std2 = numpy.mean(data), numpy.std(data) t.stop() # 主要就是结束会自动report,其他没什么太大差别 # 使用numpy算均值标准差耗时 总耗时: 2.282s 均值标准差: 0.456±0.015s 总数: 5 最小值: 0.442s 最大值: 0.483s dprint(mean2, std2) # [05]timer.py/109: mean2<numpy.float64>=4.5 std2<numpy.float64>=2.8722813232690143 print('4、可以配合dformat输出定位信息') with Timer(dformat()) as t: for _ in range(5): t.start() for _ in range(10**6): pass t.stop()
def page2png(self): """查看单页渲染图片""" page = self.doc.loadPage(0) # 索引第i页,下标规律同py,支持-1索引最后页 dprint(page.bound()) # 页面边界,x,y轴同图像处理中的常识定义,返回Rect(x0, y0, x1, y1) pix = page.getPixmap() # 获得页面的RGBA图像,Pixmap类型;还可以用page.getSVGimage()获得矢量图 # pix.writePNG('page-0.png') # 将Pixmal pngdata = pix.getPNGData() # 获png文件的bytes字节码 chrome(pngdata, 'a.png') # 用我的工具函数打开图片 return pngdata
def ensure_gbk(s): """检查一个字符串的所有内容是否能正常转为gbk, 如果不能则ignore掉不能转换的部分""" try: s.encode('gbk') except UnicodeEncodeError: origin_s = s s = s.encode('gbk', errors='ignore').decode('gbk') dprint(origin_s, s) # 字符串存在无法转为gbk的字符 return s
def page_add_ele(self): """往页面添加元素 添加元素前后xrefstr的区别: https://paste.ubuntu.com/p/Dxhnzp4XJ2/ """ self.doc.select([0]) page = self.doc.loadPage(0) # page.insertText(fitz.Point(100, 200), 'test\ntest') file = Path('a.pdf', root=Path.TEMP).fullpath dprint(file) self.doc.save(file, garbage=4) chrome(file)
def pagetext(self): """单页上的文本""" page = self.doc[0] # 获得页面上的所有文本,还支持参数: html,dict,xml,xhtml,json text = page.getText('text') dprint(text) # 获得页面上的所有文本(返回字典对象) textdict = page.getText('dict') textdict['blocks'] = textdict['blocks'][:-1] chrome(pprint.pformat(textdict))
def split(t, s, ks): """原始元素为t,集合化的值为s,共有key是ks""" if isinstance(t, (set, list, tuple)): return ks, s - ks elif isinstance(t, dict): ls1 = sorted(map(lambda x: (x, t[x]), ks), key=lambda x: natural_sort_key(x[0])) ls2 = sorted(map(lambda x: (x, t[x]), s - ks), key=lambda x: natural_sort_key(x[0])) return ls1, ls2 else: dprint(type(s)) # s不是可以用来进行集合规律分析的类型 raise ValueError
def getmembers(object, predicate=None): """自己重写改动的 inspect.getmembers""" from inspect import isclass, getmro, types if isclass(object): mro = (object,) + getmro(object) else: mro = () results = [] processed = set() names = dir(object) # :dd any DynamicClassAttributes to the list of names if object is a class; # this may result in duplicate entries if, for example, a virtual # attribute with the same name as a DynamicClassAttribute exists try: for base in object.__bases__: for k, v in base.__dict__.items(): if isinstance(v, types.DynamicClassAttribute): names.append(k) except AttributeError: pass for key in names: # First try to get the value via getattr. Some descriptors don't # like calling their __get__ (see bug #1785), so fall back to # looking in the __dict__. try: value = getattr(object, key) # handle the duplicate key if key in processed: raise AttributeError # except AttributeError: except: # 加了这种异常获取,190919周四15:14,sqlalchemy.exc.InvalidRequestError dprint(key) # 抓不到对应的这个属性 for base in mro: if key in base.__dict__: value = base.__dict__[key] break else: # could be a (currently) missing slot member, or a buggy # __dir__; discard and move on continue if not predicate or predicate(value): results.append((key, value)) processed.add(key) results.sort(key=lambda pair: pair[0]) return results
def get_encoding(bstr): """输入二进制字符串,返回字符编码,并会把GB2312改为GBK :return: 'utf-8' 或 'GBK' 备注:又想正常情况用chardet快速识别,又想异常情况暴力编码试试,代码就写的这么又臭又长了~~ 200530周六21:31 附: 这个函数太别扭了,无特殊情况还是不要用吧,写的并不好 """ # 1、读取编码 detect = None if isinstance(bstr, bytes): # 如果输入是一个二进制字符串流则直接识别 detect = chardet.detect(bstr[:1024]) # 截断一下,不然太长了,太影响速度 encoding = detect['encoding'] elif is_file(bstr): # 如果是文件,则按二进制打开 # 如果输入是一个文件名则进行读取 if bstr.endswith('.pdf'): dprint(bstr) # 二进制文件,不应该进行编码分析,暂且默认返回utf8 return 'utf-8' with open(bstr, 'rb') as f: # 以二进制读取文件,注意二进制没有\r\n的值 bstr = f.read() encoding = get_encoding(bstr) else: # 其他类型不支持 return 'utf-8' # 检测结果存储在encoding # 2、智能适应优化,最终应该只能是gbk、utf8两种结果中的一种 if encoding in ('ascii', 'utf-8', 'ISO-8859-1'): # 对ascii类编码,理解成是utf-8编码;ISO-8859-1跟ASCII差不多 encoding = 'utf-8' elif encoding in ('GBK', 'GB2312'): encoding = 'GBK' elif bstr.strip(): # 如果bstr非空 # 进入这个if分支算是比较异常的情况,会输出原识别结果detect try: # 先尝试utf8编码,如果编码成功则认为是utf8 bstr.decode('utf8') encoding = 'utf-8' dprint(detect) # chardet编码识别异常,根据文件内容已优化为utf8编码 except UnicodeDecodeError: try: # 否则尝试gbk编码 bstr.decode('gbk') encoding = 'GBK' dprint(detect) # chardet编码识别异常,根据文件内容已优化为gbk编码 except UnicodeDecodeError: # 如果两种都有问题 encoding = 'utf-8' dprint(detect) # 警告:chardet编码识别异常,已强制使用utf8处理 else: encoding = 'utf-8' return encoding
def pdfs2pngs(path, scale=None): """pdf教材批量转图片 :param path: 要处理的目录 :param scale: 控制pdf2png的尺寸,一般要设1.2会清晰些 :return: 这个函数转换中,不要去删除原文件!不要去删除原文件!删除原文件请另外写功能。 警告:该函数针对pdf课本转图片上传有些定制功能,并不是纯粹的通用功能函数 """ cwd = os.getcwd() # 1、第1轮遍历,生成所有png for dirpath, dirnames, filenames in os.walk(path): os.chdir(dirpath) dprint(dirpath) executor = concurrent.futures.ThreadPoolExecutor(4) for file in filenames: if file.endswith('.pdf'): executor.submit(pdf2png, file, scale=scale) if file.endswith('.jpg'): # 大王物理中有jpg图片 executor.submit(subprocess.run, ['magick.exe', file, file[:-4] + '.png']) executor.shutdown() # 2、第2轮遍历,找出宽与高比例在1.3~1.6的png图片,只裁剪出右半部分 dprint('2、第2轮遍历,找出宽与高比例在1.3~1.6的png图片,只裁剪出右半部分') for dirpath, dirnames, filenames in os.walk(path): os.chdir(dirpath) executor = concurrent.futures.ThreadPoolExecutor(4) for file in filenames: if not file.endswith('.png'): continue w, h = get_image_size(file) if 1.3 <= w / h <= 1.6: # 有的文件太大PIL处理不了,所以还是让magick来搞~~ half_w = w // 2 executor.submit(subprocess.run, ['mogrify.exe', '-crop', f'{half_w}x{h}+{w - half_w}+0', file]) executor.shutdown() # 3、第3轮遍历,宽超过1000的,压缩到1000内 dprint('3、第3轮遍历,宽超过1000的,压缩到1000内') for dirpath, dirnames, filenames in os.walk(path): os.chdir(dirpath) executor = concurrent.futures.ThreadPoolExecutor(4) for file in filenames: if not file.endswith('.png'): continue w, h = get_image_size(file) if w > 1000: executor.submit(subprocess.run, ['mogrify.exe', '-resize', '1000x', file]) executor.shutdown() os.chdir(cwd) # 恢复原工作目录
def message(self): """查看pdf文档一些基础信息""" dprint(fitz.version) # fitz模块的版本 dprint(self.doc.pageCount) # pdf页数 dprint(self.doc._getXrefLength()) # 文档的对象总数