网页版程序使用地址:[在线使用](https://www.yooongchun.com/apps)
摘要
本文介绍如何提取PDF版电子发票的内容。
1. 加载内容
首先使用Python的pdfplumber库读入内容。
```python
FILE=r"data/test-2.pdf"
pdf=pb.open(FILE)
page=pdf.pages[0]
```
接着读取内容并提取线段。
```python
words=page.extract_words(x_tolerance=5)
lines=page.lines # 获取线段(不包括边框线)
for word in words:
print(word)
# 坐标换算
for index,word in enumerate(words):
words[index]["y0"]=word["top"]
words[index]["y1"]=word["bottom"]
for index,line in enumerate(lines):
lines[index]["x1"]=line["x0"]+line["width"]
lines[index]["y0"]=line["top"]
lines[index]["y1"]=line["bottom"]
```
2. 还原表格
为了将内容划分到合理的位置,需要还原出表格。
首先,把线段分类为横线和竖线,并且剔除较短的两根。
```python
hlines=[line for line in lines if line["width"]>0] # 筛选横线
hlines=sorted(hlines,key=lambda h:h["width"],reverse=True)[:-2] #剔除较短的两根
vlines=[line for line in lines if line["height"]>0] #筛选竖线
vlines=sorted(vlines,key=lambda v:v["y0"]) #按照坐标排列
```
将线段展示出来如下图。
此时的线段是不闭合的,将缺少的线段补齐得到表格如下。
# 查找边框顶点
hx0=hlines[0]["x0"] # 左侧
hx1=hlines[0]["x1"] # 右侧
vy0=vlines[0]["y0"] # 顶部
vy1=vlines[-1]["y1"] # 底部
thline={"x0":hx0,"y0":vy0,"x1":hx1,"y1":vy0} # 顶部横线
bhline={"x0":hx0,"y0":vy1,"x1":hx1,"y1":vy1} # 底部横线
lvline={"x0":hx0,"y0":vy0,"x1":hx0,"y1":vy1} # 左侧竖线
rvline={"x0":hx1,"y0":vy0,"x1":hx1,"y1":vy1} # 右侧竖线
hlines.insert(0,thline)
hlines.append(bhline)
vlines.insert(0,lvline)
vlines.append(rvline)
接下来,查找所有线段的交点:
# 查找所有交点
points=[]
delta=1
for vline in vlines:
vx0=vline["x0"]
vy0=vline["y0"]
vx1=vline["x1"]
vy1=vline["y1"]
for hline in hlines:
hx0=hline["x0"]
hy0=hline["y0"]
hx1=hline["x1"]
hy1=hline["y1"]
if (hx0-delta)<=vx0<=(hx1+delta) and (vy0-delta)<=hy0<=(vy1+delta):
points.append((int(vx0),int(hy0)))
print('所有交点:',points)
print('交点总计:',len(points))
最后,根据交点构建矩形块
# 构造矩阵
X=sorted(set([int(p[0]) for p in points]))
Y=sorted(set([int(p[1]) for p in points]))
df=pd.DataFrame(index=Y,columns=X)
for p in points:
x,y=int(p[0]),int(p[1])
df.loc[y,x]=1
df=df.fillna(0)
# 寻找矩形
rects=[]
COLS=len(df.columns)-1
ROWS=len(df.index)-1
for row in range(ROWS):
for col in range(COLS):
p0=df.iat[row,col] # 主点:必能构造一个矩阵
cnt=col+1
while cnt<=COLS:
p1=df.iat[row,cnt]
p2=df.iat[row+1,col]
p3=df.iat[row+1,cnt]
if p0 and p1 and p2 and p3:
rects.append(((df.columns[col],df.index[row]),(df.columns[cnt],df.index[row]),(df.columns[col],df.index[row+1]),(df.c