图片萝莉 sex萝莉 sex
小爬最近接到一个毒手任务:需要索求手机话费电子发票PDF文献中的数据。接到这个任务的第一技能,小爬决定征集各个地区各个技能段的电子发票文献,望望其中的相反点。和不详统计下来,PDF文献的表格框架是融合的,关联词数据部分则有较大相反:
.
小爬领先料想的是借助器用索求发票的文本内容,然后用re正则抒发式进行章程化的匹配数据,找到每个字王人信息;这其中大部分的python-pdf默契库王人能胜任.
可要津的问题是,索求出来的文本相反性绝顶大,比如说:各段翰墨出现的礼貌并不是按照PDF中的翰墨的Z序摆设.举个例子:"称号:"后头紧跟的只怕是果真的用户称号字符,可能是"单价".这就给RE抒发式带来了极浩劫度.其后小爬才清爽到,我需要的是一个不详对"表格"数据的援手绝顶友好的PDF默契库.同期对表格外的图片&翰墨信息也具备很好的索求材干.
咱们得处治二维码:发票PDF文献的左上角位置是一个二维码对象,该二维码中不错默契到 "机器编号","发票代码","发票号码","开票日历" 和"校验码".这个时候需要用到fitz.好多东说念主不知说念fitz库是啥,其实它是pymupdf中的一个模块,操作PDF绝顶逍遥,只需要pip安设即可:
pip install pymupdf
该方法基本鉴戒了这篇博客的方法:Python索求PDF中的图片,代码示举例下:
def pdf2pic(pdf_path): #t0 = time.clock() # 生成图片启动技能 checkXO = r"/Type(?= */XObject)" # 使用正则抒发式来查找图片 checkIM = r"/Subtype(?= */Image)" doc = fitz.open(pdf_path) # 翻开pdf文献 imgcount = 0 # 图片计数 lenXREF = doc._getXrefLength() # 获取对象数目长度 # 遍历每一个对象 for i in range(1, lenXREF): text = doc._getXrefString(i) # 界说对象字符串 isXObject = re.search(checkXO, text) # 使用正则抒发式稽查是否是对象 isImage = re.search(checkIM, text) # 使用正则抒发式稽查是否是图片 if not isXObject or not isImage: # 淌若不是对象也不是图片,则continue continue imgcount += 1 pix = fitz.Pixmap(doc, i) # 生成图像对象 #new_name = "图片{}.png".format(imgcount) # 生成图片的称号 new_name=pdf_path.replace("pdf","png").replace("手机话费发票","二维码图片") if pix.n < 5: # 淌若pix.n<5,不错平直存为PNG pix.writePNG(new_name) else: # 不然先调节CMYK pix0 = fitz.Pixmap(fitz.csRGB, pix) pix0.writePNG(new_name) pix0 = None pix = None break return new_name # 开释资源
使用它,咱们就不错默契得到PDF文献中的二维码图片元素,并保存为PNG图片.再诈骗pyzbar咱们不错很减弱地默契出二维码中的信息.之是以要单独索求出二维码并保存为图片,再识别妥协析二维码,是因为淌若咱们把通盘的pdf内容处理为png图片,再让Pyzbar库来默契二维码,则pyzbar需要先定位二维码在图片中的位置,才能出手默契.这么png图片中骚动元素变多,识别率势必下落.而单纯地识别PDF文献中的索求到的二维码图片,则pyzbar库的识别率绝顶高,简直达到100%.
关联词凡事总有例外,有些PDF文献不章程,无法通过遍历元素的方法得到这个二维码对象元素.此时,咱们不错借助截取PDF画面右上角的固定区域来得到二维码图片.具体代码如下:
def crop_to_png(pdfPath): ''' 假设pdf唯唯一页,只调节第一页的内容的左上角部分(二维码区域)为png图片 tl:TopLeft br:BottomRight mp:MiddlePoint ''' doc = fitz.open(pdfPath) pngPath=pdfPath[:-4] page = doc[0] rotate = int(0) # 每个尺寸的缩放整个为3,这将为咱们生因素辨率擢升九倍的图像。 zoom_x = 3.0 zoom_y = 3.0 trans = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate) rect = page.rect mp = rect.tl + (rect.br - rect.tl) * 1/5 #二维码矩形区域右下角坐标 clip = fitz.Rect(rect.tl,mp) #裁切的二维码区域的左上角、右下角坐标,定位裁切的矩形区位置 pm = page.getPixmap(matrix=trans, alpha=False,clip=clip) pngPath=pdfPath.replace("pdf","png").replace("手机话费发票","二维码图片") pm.writePNG(pngPath) doc.close() return pngPath
得到了二维码图片,咱们先按照 pdf2pic(pdf_path) 方法,交给pyzbar默契,淌若识别不了,再用第二种裁切画面的方法:crop_to_png(pdfPath) 得到二维码图片的方法,交给pyzbar默契.淌若两种方法王人不成通过pyzbar默契,则复返信息提醒用户.具体方法如下:
def parse_invoice_qrcode(pdfPath,pngPath): """ 通过默契二维码信息,得到发票的发票代码、发票号码 开票日历、锤真金不怕火码、机器编号等信息 """ invoice_code,invoice_number,total_money,invoice_date,check_code=(None,None,None,None,None) img=Image.open(pngPath) #img_size=img.size #print(img_size) qrcodes=pyzbar.decode(img) #print(qrcodes) try: qrcodeInfo=qrcodes[0].data.decode("utf-8").split(",") except: print("%s:decode error,try another way to decode it"%pngPath) pngPath=crop_to_png(pdfPath) #使用另一种裁切图片的方法得到二维码图片,并复返图片的旅途 img=Image.open(pngPath) qrcodes=pyzbar.decode(img) try: qrcodeInfo=qrcodes[0].data.decode("utf-8").split(",") except: print("%s:still decode error"%pngPath) return invoice_code,invoice_number,total_money,invoice_date,check_code invoice_code=qrcodeInfo[2] #发票代码 invoice_number=qrcodeInfo[3] #发票号码 total_money=qrcodeInfo[4] #不含税总金额 invoice_date=qrcodeInfo[5] #发票日历 check_code=qrcodeInfo[6] #锤真金不怕火码 print("二维码图片称号:%s\n发票代码:%s\n发票号码:%s\n不含税金额:%s\n开票日历:%s\n锤真金不怕火码:%s"%(pngPath,invoice_code,invoice_number,total_money,invoice_date,check_code)) return invoice_code,invoice_number,total_money,invoice_date,check_code
之后,咱们用pdfPlumber库来要点索求pdf发票的表格信息.
解决想想:pdfplumber库的 extract_text()索求文本,辅助以extract_tables()方法来索求表格内容.探究到extract_tables()方法得到的是一个表格列表,咱们的发票PDF文献中唯唯一个表格,是以使用extract_tables()[0]来取得第一个表格对象,该对象里面是一个二维列表.遍历列表元素,咱们就不错得到表格每个区域的内容然后用RE抒发式来要点索求.具体代码示举例下:
with pdfplumber.open(pdf_path) as pdf: p0 = pdf.pages[0] print("pdf称号:%s"%pdf_path) contents=p0.extract_text() #print(contents) if contents is None: print("%s:pdf文献局势特殊,索求不到文本内容\n"%pdf_path) continue else: contents=contents.replace(" ","").replace(":",":") #打印通盘的文本 """地区""" if p0.extract_tables()==[]: print("%s:局势不步伐,索求不到表格内容\n"%pdf_path) elif len(p0.extract_tables()[0])<4: #话费pdf文献中表格共有4块 print("%s:局势不步伐,索求到的表格内容不圆善\n"%pdf_path) else: table = p0.extract_tables()[0] """销售方称号:运营商""" pattern=re.search(r".*?(中国.*?)\n.*?",table[3][1],re.S) salesName=pattern.group(1) if pattern else "" print("salesname:",salesName) if salesName: if "中国移动通讯集团" in salesName: operation_corp="移动" """索求用户名、电话和账期字段""" txt=table[0][1].replace(":",":").replace(" ","") #称号 &征税东说念主识笔名字段 userName=re.search(r"称号:(.*?)\n.*?",txt).group(1) if "(号码" in userName: userName=userName.split("(")[0] #pattern=re.search(r".*?\D(1[0-9]{10}).*?",txt) if not tel: pattern=re.findall(r'\d+',txt) #这串数字(11位)前后王人不是数字字符,幸免从其他数字中索求了一段算作电话号码 if pattern: for element in pattern: if element[0]=="" and len(element)==11: tel=element break comment=table[3][7].replace("\n","").replace(" ","").replace(":",":") #发票的备注栏,频频有手机号和账期等信息,探究到换行,去掉这些必要的换行符、空格符,账期有时在规格型号栏,云南区域 pattern=re.search(".*?(20[0-9]{4})-(20[0-9]{4}).*?",comment) #账期:201812-201902 ,多个月的发票开在整个 if pattern: if pattern.group(1)!=pattern.group(2): print("%s:(%s-%s)---不淡薄将几个月的话费开在归拢张发票内!\n"%(pdf_path,pattern.group(1),pattern.group(2))) continue pattern=re.search(".*?(20[0-9]{2}[0-1]{1}[0-9]{1}).*?",comment) if pattern: period=pattern.group(1) #账期:诸如201906 或者2019年06月 else: pattern=re.search(".*?(20[0-9]{2}年[0-1]{1}[0-9]{1}月).*?",comment) if pattern: period=pattern.group(1) else: pattern=re.search(".*?(20[0-9]{2}.[0-1]{1}[0-9]{1}).*?",comment) #局势:2019.02 if pattern: period=pattern.group(1) else: type_size=table[1][2] #规格型号栏 pattern=re.search(".*?(20[0-9]{2}[0-1]{1}[0-9]{1}).*?",type_size) #局势:201902 if pattern: period=pattern.group(1) else: content=table[1][0] pattern=re.search(".*?(20[0-9]{2}年[0-9]{2}月).*?",content) #局势:2019年02月 period=pattern.group(1) if pattern else "unknown" period=period.replace("年","").replace("月","").replace(".","").replace("-","") if not tel: pattern=re.findall(r'号码:\d+',comment) if pattern: for element in pattern: if element[3]=="" and len(element)==14: tel=element[3:] break # 该方法索求一语气的一段数字,判断数字淌若刚好是11位且以数字1打头,则觉得在该场景下的这段数字应该是电话号码. if not tel: #淌若最终照旧不成索求到对应的号码,则退出当次轮回 continue print("用户名:%s"%userName) print("电话:%s"%tel) print("账期:%s"%period) print("\n") else: ("运营商不属于中国移动!") continue else: print("不步伐的运营商称号(必须以“中国”滥觞)") continue
原则上借助该方法,不错索求发票的明细项和对应内容,发票账期,东说念主名,电话号码,税率等内容.
关联词本色的数据索求经由中,部分PDF发票用pdfPlumber模块的 extract_tables()==[],可能拿获的是一个空列表.小爬的例子阐发 pdfPlumber不是全能的.知乎上力推的 tabula-py库是基于java的tabula的二次封装.要在python下使用该库,咱们还需要安设Java的JRE环境,未来的封装exe亦然一个大问题.小爬因此莫得继续尝试.其他的python pdf2htmlEX库,小爬亲测了下,对表格的适用性不太好,尤其是(合并单位格的不章程表格)效用够不上要求.
小爬试了下 camelot库.这个pdf默契库在windows系统下的安设绝顶不顺利,几番折腾才得以告捷安设.由于网上的诸多教程王人莫得很好的进展这个库的安设经由.这里小爬特此 证据该怎么正确安设.领先不是平直安设:PIP install camelot.咱们需要的库名叫camelot-py.正确的方法是,进到camelot在github上的仓库,下载zip文献解压后,用setup方法运行.地址如下:
https://github.com/camelot-dev/camelot
图片
安设方法:
才能翻开cmd或者powerShell到达安设目次python setup.py buildpython setup.py install
由于该库还依赖于tk库,CV库以及Ghostscript(一个exe文献),pandas,numpy等库,咱们需要一一安设这些依赖文献.
淌若只想用PIP安设,则需要通过pip install tk,然后再用pip install camelot-py[cv]
妖媚婷儿 户外就不错在安设camelot-py的同期安设上兼容的CV库.而Ghostscript并不是通过pip install来安设,它在windows系统下有exe的安设文献,下载地址如下:https://www.ghostscript.com/download/gsdnld.html咱们只需要下载系统对应的版块就好.
图片
安设该软件,并牢记添加用户环境变量旅途.
图片
有了这些才能,咱们的camelot库才算不错平常运行.底下是官网给出的一个例子,供参考:
>>> import camelot>>> tables = camelot.read_pdf('foo.pdf')>>> tables<TableList n=1>>>> tables.export('foo.csv', f='csv', compress=True) # json, excel, html, sqlite>>> tables[0]<Table shape=(7, 7)>>>> tables[0].parsing_report{ 'accuracy': 99.02, 'whitespace': 12.24, 'order': 1, 'page': 1}>>> tables[0].to_csv('foo.csv') # to_json, to_excel, to_html, to_sqlite>>> tables[0].df # get a pandas DataFrame!
具体的操作文档见官方的手册,旅途如下:
https://camelot-py.readthedocs.io/en/master/
图片
事实阐发,camelot和pdfplumber王人有各自擅长的pdf默契边界.咱们不错在本色的神气中,同期使用这两个库,互为补充.当其中一个索求表格失败时,另一个库有可能不错很梦想的得到咱们想要的数据.
PS:使用camelot得到的库不错很浅陋转成pandas需要的DataFrame局势,并结合pandas功能,浅陋导出CSV或者xlsx局势的文献,进行后继处理!
速即入手试试吧!
图片
诈骗python第三方库索求PDF文献的表格内容的更多联系著作 诈骗Python将多个PDF文献合并from PyPDF2 import PdfFileMerger import os files = os.listdir()#列出目次中的通盘文献 merger = PdfFileMerger() ...
python第三方库——xlrd和xlwt操作Excel文献学习python第三方库——xlrd和xlwt操作Excel文献学习 1安设: C:\Users\Lenovo>pip install xlwtCollecting xlwt Downloadin ...
python文献翻开模式&time&python第三方库r:以只读方式翻开文献.文献的指针将会放在文献的滥觞.这是默许模式. w:翻开一个文献只用于写入.淌若该文献已存在则将其袒护.淌若该文献不存在,创建新文献. a:翻开一个文献用于追加.淌若该文献已存在 ...
python第三方库,你要的这里王人有Python的第三方库多的超出我的瞎想. python 第三方模块 转 https://github.com/masterpy/zwpy_lst Chardet,字符编码探伤器,不错自动检测文本. ...
真切学习python默契并读取PDF文献内容的方法这篇著作东要学习了python默契并读取PDF文献内容的方法,包括对学习库的应用,python2.7和python3.6中python默契PDF文献内容库的更新,包括对pdfminer库的详备解释和应 ...
Python第三方库资源[转载]Python第三方库资源 转自:https://weibo.com/ttarticle/p/show?id=2309404129469920071093 参考:https://github ...
Python使用Tabula索求PDF表格数据今天遭遇一个批量读取pdf文献中表格数据的需求,花式大体是以下这么: python读取PDF无非即是三种方式(我所了解的),pdfminer.pdf2htmlEX 和 Tabula.抽象探究后,聘用了 ...
真切学习Python默契并解密PDF文献内容的方法前边学习了默契PDF文档,并写入文档的学问,那篇著作的名字为真切学习Python默契并读取PDF文献内容的方法. 蚁集如下:https://www.cnblogs.com/wj-1314/p/9429 ...
【Python基础】安设python第三方库pip敕令行安设(保举) 翻开cmd敕令行 安设需要的第三方库如:pip install numpy 在安设python的联系模块和库时,咱们一般使用“pip install 模块名”或者“pyth ...
立地保举 ELK锻练1.ELK锻练 PUT s3/_doc/ { "mappings" : { "doc" : { "properties" : { " ...
header发送CookieCookie传达给客户端的旨趣 平时推行setcookie('key1', 'value1');这么的代码时,浏览器就会收到cookie并保存,但咱们并不成从echo出去的内容中看到cookie内容 ...
11-2 css盒模子和浮动以及矢量图用法一 盒模子 1属性 width:内容的宽度 height: 内容的高度 padding:内边距,边框到内容的距离 border: 边框,即是指的盒子的宽度 margin:外边距,盒子边框到近邻最近盒子 ...
H3C 专线伙同模子 H3C 积累层 js键盘按下移动元素著作地址 https://www.cnblogs.com/sandraryan/ 功能: 点击高下驾驭按钮,移动元素 <!DOCTYPE html> <html lang=" ...
lrj 9.4.1 最长高涨子序列 LISp275 d(i)是以Ai为完毕的最长高涨子序列的长度 <算法竞赛初学经典-教师指南>p62 问题6 提供了一种优化到 O(nlogn)的方法. 文本顶用g(i)暗意d值为i的最小景况编号 ...
4-10 items辩论1,items相等于dict,关联词又比字典好 2,parse.urljoin(response.url,post_url)方法,其中image_url是一个域名的话,其中确面前域名就不必再添加. yi ...
【9101】求n!的值Time Limit: 10 second Memory Limit: 2 MB 问题形色 用高精度的方法,求n!的精准值(n的值以一般整数输入). Input 文献输入仅一瞥,输入n. Output ...
SpringDataJPA+QueryDSL玩转态动条目/投影查询在本文之前,本应当特意有一篇博客教化SpringDataJPA使用自带的Specification+JpaSpecificationExecutor去证据怎么玩条目查询萝莉 sex,关联词看到新奇.编码更简陋易懂的 ...
本站仅提供存储劳动,通盘内容均由用户发布,如发现存害或侵权内容,请点击举报。