pdf文档解析

一 python解析pdf

  很多文件为了安全都会存成 PDF 格式,比如有的论文、技术文档、书籍等等,程序读取这些文档内容带来了很多麻烦。Python 目前解析 PDF 的扩展包有很多,这里将对比介绍 PyPDF2、pdfplumber、pdfminer3k 以及 Camelot,告诉你哪个是好用的 PDF 解析工具。

一 PyPDF2 解析 PDF 文档

import PyPDF2
path = r"****.pdf"
#使用open的‘rb’方法打开pdf文件(这里必须得使用二进制rb的读取方式)
mypdf = open(path,mode='rb')
#调用PdfFileReader函数
pdf_document = PyPDF2.PdfFileReader(mypdf)
#使用pdf_document变量,获取各个信息
#或者PDF文档的页数
pdf_document.numPages
#输出PDF文档的第一页内容
first_page = pdf_document.getPage(0)
print(first_page.extractText())

  输出文档第一页内容之后会发现,PyPDF2 方法对中文的支持不好,而对英文的支持会很好,所以如果处理中文文档的话,可以使用下面这个方法。

二 pdfplumber 解析 PDF 文档

  安装的话直接使用下面语句即可:pip install pdfplumber

1 读取PDF

  pdfplumber 提供了两种读取pdf的方式:

pdfplumber.open("path/to/file.pdf")
pdfplumber.load(file_like_object)

  这两种方法都返回pdfplumber.PDF类的实例(instance)。
  加载带密码的pdf需要传入参数password,例如:pdfplumber.open(“file.pdf”, password = “test”)

2 pdfplumber.PDF类

  处于最上层的pdfplumber.PDF类表示单个PDF,并且具有两个主要属性:

属性描述
.metadata从PDF的Info中获取元数据键 /值对字典。 通常包括“ CreationDate”,“ ModDate”,“ Producer”等。
.pages一个包含pdfplumber.Page实例的列表,每一个实例代表PDF每一页的信息。

3 pdfplumber.Page类

  pdfplumber.Page类是pdfplumber整个的核心,大多数操作都围绕这个类进行操作,它具有以下几个属性:

属性描述
.page_number页码顺序,从第一页的1开始,第二页为2,依此类推。
.width页面宽度
.height页面高度
.objects/.chars/.lines/.rects/
.curves/.figures/.images
这些属性中的每一个都是一个列表,并且每个列表针对嵌入面上的每个此类对象包含一个字典。 有关更多详细信息,请参见下面的"对象(Object)"。

  以及这些主要的方法(method):

方法描述
.crop(bounding_box)返回裁剪后的页面,该bouding_box应表示为具有值(x0, top, x1, bottom)的4元组。 裁剪后的页面保留了至少部分位于边界框内的对象。 如果对象仅部分落在该框内,则也会被涵盖。
.within_bbox(bounding_box)和.crop相似,但是只会包含完全在bounding_box内的部分。
.filter(test_function)返回仅包含.objects的页面版本,该对象的test_function(obj)返回True。
.extract_text(x_tolerance=0, y_tolerance=0)将页面的所有字符对象整理到一个字符串中。
若其中一个字符的x1与下一个字符的x0之差大于x_tolerance,则添加空格。
若其中一个字符的doctop与下一个字符的doctop之差大于y_tolerance,则添加换行符。
.extract_words(x_tolerance=0, y_tolerance=0, horizontal_ltr=True, vertical_ttb=True)返回所有单词外观及其边界框的列表。字词被认为是字符序列,其中(对于“直立”字符)一个字符的x1和下一个字符的x0之差小于或等于x_tolerance,并且一个字符的doctop和下一个字符的doctop小于或等于y_tolerance。对于非垂直字符也采用类似的方法,但是要测量它们之间的垂直距离,而不是水平距离。
参数horizontal_ltr和vertical_ttb指示是否应从左到右(对于水平单词)/从上到下(对于垂直单词)读取字词。
.extract_tables(table_settings)从页面中提取表格数据。 有关更多详细信息,请参见下面的“表格抽取”。
.to_image(**conversion_kwargs)返回PageImage类的实例。 有关更多详细信息,请参见下面的“可视化调试”。 有关conversion_kwargs,请参见此处

4 对象(Object)

  对于每一个pdfplumber.PDF和pdfplumber.Page的实例都提供了对4种对象操作的方法。以下属性均返回所对应对象的Python列表:

  • .chars 代表每一个独立的字符;
  • .annos 代表注释里的每一个独立的字符;
  • .lines 代表一个独立的一维的线;
  • .rects 代表一个独立的二位的矩形;
  • .curves 代表一系列连接的点;
  • .images 代表一个图像;

  每一个对象用一个Python词典dict进行表示,具有以下属性:

5 chars / annos 属性

属性描述
page_number找到此字符的页码。
text字符文本,如"z"、“Z"或者"你”。
fontname字符的字体。
size字号。
adv等于文本宽度字体大小缩放因子。
upright字符是否是直立的。
height字符高度。
width字符宽度。
x0字符左侧到页面左侧的距离。
y0字符底部到页面底部的距离。
x1字符右侧到页面左侧的距离。
y1字符顶部到页面底部的距离。
top字符顶部到页面顶部的距离。
bottom字符底部到页面顶部的距离。
doctop字符顶部到文档顶部的距离。
obj_type"char""anno"

6 line 属性

属性描述
page_number找到此线的页码。
height线的高度。
width线的宽度。
x0线的最左侧到页面左侧的距离。
y0线的底部到页面底部的距离。
x1线的最右侧到页面左侧的距离。
y1线的顶部到页面底部的距离。
top线的顶部到页面顶部的距离。
bottom线的底部到页面顶部的距离。
doctop线的顶部到文档顶部的距离。
linewidth线的粗度。
obj_type“line”

7 rect 属性

属性描述
page_number找到此矩形的页码。
height矩形的高度。
width矩形的宽度。
x0矩形的最左侧到页面左侧的距离。
y0矩形的底部到页面底部的距离。
x1矩形的最右侧到页面左侧的距离。
y1矩形的顶部到页面底部的距离。
top矩形的顶部到页面顶部的距离。
bottom矩形的底部到页面顶部的距离。
doctop矩形的顶部到文档顶部的距离。
linewidth矩形边框的粗度。
obj_type“rect”

8 curve 属性

属性描述
page_number找到此曲线的页码。
points点,作为(x,top)元组的列表,用以描述曲线。
height曲线bounding_box的高度。
width曲线bounding_box的宽度。
x0曲线的最左侧点到页面左侧的距离。
y0曲线最底部点到页面底部的距离。
x1曲线的最右侧点到页面左侧的距离。
y1曲线最顶部点到页面底部的距离。
top曲线最顶部的点到页面顶部的距离。
bottom曲线最底部点到页面顶部的距离。
doctop曲线最顶部点到文档顶部的距离。
linewidth连线的粗度。
obj_type“curve”

  此外,pdfplumber.PDFpdfplumber.Page都提供对两个派生对象列表的访问:.rect_edges(将每个矩形分解成四行)和.edges(将.rect_edges.lines组合)。

1 解析文本内容

  pdfplumber 中的 extract_text 函数是可以直接识别 PDF 中的文本内容。
  首先读取整个 PDF 文档文本内容

import pdfplumber
import pandas as pd

with pdfplumber.open(path) as pdf: 
    content = ''
    #len(pdf.pages)为PDF文档页数
    for i in range(len(pdf.pages)):
      #pdf.pages[i] 是读取PDF文档第i+1页
        page = pdf.pages[i]
        #page.extract_text()函数即读取文本内容,下面这步是去掉文档最下面的页码
        page_content = '\n'.join(page.extract_text().split('\n')[:-1])
        content = content + page_content
    print(content)

  解析文本内容,取出 PDF 的售后解决方案中的故障代码内容,可以看到故障代码内容,如下图所示,故障代码在两页里面。
在这里插入图片描述
  根据这类文档的规律可以知道,故障代码内容都是在文本故障代码列举如下:和 2.之间,因此解析 PDF 之后取出这部分内容还是比较容易的:print(content.split('故障代码列举如下:')[1].split('2.')[0])
  运行结果如下,可以看出来很好的取出来这部分内容了。
在这里插入图片描述

2 解析表格内容

  上面介绍了 pdfplumber 解析文本内容的方法,这里介绍一下解析表格内容的方法,和上面十分类似,pdfplumber 中的 extract_tables 函数是可以直接识别 PDF 中的表格的。
  这里展示解析 PDF 文档中第一页表格的方法,可以看出案例 PDF 中第一页的开头就是一个表格:
在这里插入图片描述
  由于使用 extract_tables 函数得到的是 Table 一个嵌套的 List 类型,转化成 DataFrame 会更方便查看和分析。

import pdfplumber
import pandas as pd

with pdfplumber.open(path) as pdf:      
    first_page = pdf.pages[0]
    for table in first_page.extract_tables(): 
        df = pd.DataFrame(table)
df

  可以看出这个函数非常容易的将 PDF 文档中的表格提取出来了。
在这里插入图片描述
  看完上面的可以知道 pdfplumber 扩展包可以非常好的解析 PDF 的文本内容和表格内容,并且对中文有很好的支持,十分推荐使用该方法。

三 pdfminer3k 解析 PDF 文档

  pdfminer3k 是 pdfminer 的 python3 版本,主要用于读取 pdf 中的文本。如果直接搜索 pdfminer3k 的话会发现网上有非常多的教程,但是看了之后,你可能就想吐槽这些教程太繁琐了,看着头疼。

1 安装

  在python3.6中就需要安装:pip install pdfminer3k

只存在文字的PDF此程序会全部读取出文字
只存在图片的PDF此程序不会读取出任何东西
存在图片和文字此程序只会读出文字,不会识别图片

2 参考链接

  深入学习python解析并读取PDF文件内容的方法:https://www.cnblogs.com/wj-1314/p/9429816.html
  下面这个是 pdfminer 解析 PDF 文档的流向图。
在这里插入图片描述
  pdfminer 方法解析 PDF 可以很好的提取文本内容,但是对于表格数据,能提取出文字,但是没有格式,会很不友好。因此你如果只需要提取文本内容的话,可以使用 pdfminer 扩展包,这个包也能很好的支持中文。中文需要考虑编码和全角半角问题。

四 Camelot 解析 PDF 文档

  Camelot 先使用 pip install camelot-py 语句安装,如果报错,参考安装 Camelot 教程。
  另外,使用 camelot 需要安装 cv2 包,上面这个安装教程中也有。

import camelot
import pandas as pd
tables = camelot.read_pdf(filepath=path,pages='1',flavor='stream')
df = pd.DataFrame(tables[0].data)

  Camelot 读取 PDF 文件中的表格数据很好用,并且能够很好的支持中文,但是 Camelot 有很多局限性。
  首先,使用 stream 时,表格无法被自动侦测到,stream 把整个页面当成一个 table。
  其次,camelot 只用使用基于文本的 PDF 文件而不能使用扫描文档。
  综上所述,建议使用 pdfplumber 扩展包来解析 PDF 文档的文本和表格,如果只解析文本内容,也可以使用 pdfminer ,而解析英文文档内容,可以使用 PyPDF2 。

五 pymupdf

1 读取pdf中的图片

2 参考链接

  使用PyMuPdf库来实现PDF图片的提取:https://blog.csdn.net/jylonger/article/details/106586559
  注:将整个图片提取为一页了。
  Python提取PDF中的图片:https://blog.csdn.net/qq_15969343/article/details/81673302
  注:上面链接中的方法及其评论区中的一种方法都没法提取出 pdf 中所有的图片,getObjectString 读取的对象不一定准确。

六 链接

  PDF解析与结构化提取:https://www.cnblogs.com/HaifengCai/p/3959573.html
  使用Python第三方库pdfminer提取PDF内容,并解决中文编码不支持的问题:https://zhuanlan.zhihu.com/p/29410051
  三大神器助力Python提取pdf文档信息:https://cloud.tencent.com/developer/article/1395339
  https://xueqiu.com/7967593043/145833647:https://xueqiu.com/7967593043/145833647
  PDF分析:https://blog.csdn.net/steve_cui/category_7978733.html

二 C#解析pdf

一 sumatrapdf编译

  本节内容来自这里
  本人在开源代码sumatrapdf里面下载最新的代码进行编译,本机下载最先专业版VS2017进行运行,不过老是编译运行报错,我在开源网站想作者咨询。
  版本:https://github.com/sumatrapdfreader/sumatrapdf
  问题:https://github.com/sumatrapdfreader/sumatrapdf/issues/1031

Please help me. When I download the latest version(sumatrapdf-master.zip), I use VS2017 to run the wrong report.My laptop win10 64 bit,When I unzip the file, open vs2017/SumatraPDF.sln, compile and run error.
----------------------------------ERROR-----------------------------------------------------------
Severity code indicates that item file rows are forbidden to display state.
Error MSB8020 could not find the v141_xp generation tool (platform toolset = “v141_xp”). If you want to use the v141_xp generation tool to generate, install the v141_xp generation tool. Or, you can upgrade to the current Visual Studio tool by selecting the “project” menu or right-click the solution, and then selecting the “redefine solution target”. Cmapdump D:\Program\VisualStudio2017\Community\Common7\IDE\VC\VCTargets\Microsoft.Cpp.Platform.targets 57
I hope you can teach me how to run it, compile those files, and guide me according to your successful compilation. Thank you.
kjk回答:您很可能需要重新运行Visual Studio安装程序,并确保安装XP工具链组件。

当我重新安装VS2017把XP的安装上,重新运行,不过还是有报错:

Today,when i re-run Visual Studio installer and make sure to install XP toolchain component.
----------------------------------ERROR-----------------------------------------------------------
1>------ Build started: Project: synctex, Configuration: Debug x64 ------
2>------ Build started: Project: mupdf, Configuration: Debug x64 ------
1>synctex_parser.c
1>d:\sumatrapdf-master\ext\synctex\synctex_parser.c(715): error C2220: warning treated as error - no ‘object’ file generated
1>d:\sumatrapdf-master\ext\synctex\synctex_parser.c(715): warning C4819: The file contains a character that cannot be represented in the current code page (936). Save the file in Unicode format to prevent data loss
1>Done building project “synctex.vcxproj” – FAILED.
2>pdf-write.c
2>d:\sumatrapdf-master\mupdf\source\pdf\pdf-write.c(2075): error C2220: warning treated as error - no ‘object’ file generated
2>d:\sumatrapdf-master\mupdf\source\pdf\pdf-write.c(2075): warning C4819: The file contains a character that cannot be represented in the current code page (0). Save the file in Unicode format to prevent data loss
2>Done building project “mupdf.vcxproj” – FAILED.
3>------ Build started: Project: SumatraPDF, Configuration: Debug x64 ------
3>LINK : fatal error LNK1104: cannot open file ‘D:\sumatrapdf-master\dbg64\mupdf.lib’
3>Done building project “SumatraPDF.vcxproj” – FAILED.
========== Build: 0 succeeded, 3 failed, 16 up-to-date, 0 skipped ==========
How is this going?
kjk回答:修改pdf-write.c第2075行的代码,然后synctex_parser.c从新保存一下文件就可以了
pdf-write.c
row 2075
//fprintf(opts->out, “%%\316\274\341\277\246\n\n”); //wrong
fprintf(opts->out, “%%\xC2\xB5\xC2\xB6\n\n”); //ok—come from mupdf-1.12.0-source
You can disable that warning. It’s caused by using non-english OS.

  重新运行,终于可以了,最新本部3.2
在这里插入图片描述

二 C#获取pdf页数

int get_count(string filePath)
{
	int count = -1;
	using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
	{
	    StreamReader reader = new StreamReader(fs);
	    //从流的当前位置到末尾读取流
	    string pdfText = reader.ReadToEnd();
	    Regex rgx = new Regex(@"/Type\s*/Page[^s]");
	    MatchCollection matches = rgx.Matches(pdfText);
	    count = matches.Count;
	}
	Log.Information("cout page: " + count.ToString());
	return count;
}

三 基于MuPDF库实现PDF文件转换成PNG格式图片

  地址:https://www.mupdf.com/downloads/index.html
  本节内容来自这里
  本节内容来自这里

四 C# pdf转成图片(可转成jpg、png等格式)

  本节内容来自这里
在这里插入图片描述

using PdfiumViewer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PDFtoJPG
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// PDF的textbox后面对应的按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butPDF_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                //FileName:显示文件路径+名字
                this.txtPDF.Text = dialog.FileName;

        }
    }

    /// <summary>
    /// 图片的textbox后面对应的按钮
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void butTUPIAN_Click(object sender, EventArgs e)
    {
        #region 测试SafeFileName,不用关
        //OpenFileDialog dialog = new OpenFileDialog();
        //if (dialog.ShowDialog() == DialogResult.OK)
        //{
        //    //SafeFileName:只显示文件名字
        //    this.txtJPG.SelectedText = dialog.SafeFileName;

        //}
        #endregion

        System.Windows.Forms.FolderBrowserDialog folder = new System.Windows.Forms.FolderBrowserDialog();
        if (folder.ShowDialog() == DialogResult.OK)
        {

            //SelectedPath:获取文件夹绝对路径,显示在textbox里面
            this.txtJPG.Text = folder.SelectedPath;

        }
    }

    /// <summary>
    /// PDF转图片格式的button按钮
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void butPDFtoTUPIAN_Click(object sender, EventArgs e)
    {
        string strpdfPath = txtPDF.Text.ToString();
        var pdf = PdfiumViewer.PdfDocument.Load(strpdfPath);
        var pdfpage = pdf.PageCount;
        var pagesizes = pdf.PageSizes;

        for (int i = 1; i <= pdfpage; i++)
        {
            Size size = new Size();
            size.Height = (int)pagesizes[(i - 1)].Height;
            size.Width = (int)pagesizes[(i - 1)].Width;
            //可以把".jpg"写成其他形式
            RenderPage(strpdfPath, i, size, txtJPG.Text.ToString() + "\\"+ txtName.Text.ToString() + @".jpg");
        }

        MessageBox.Show("转换成功!");
    }
    public void RenderPage(string pdfPath, int pageNumber, System.Drawing.Size size, string outputPath, int dpi = 300)
    {
        using (var document = PdfiumViewer.PdfDocument.Load(pdfPath))
        using (var stream = new FileStream(outputPath, FileMode.Create))
        using (var image = GetPageImage(pageNumber, size, document, dpi))
        {
            image.Save(stream, ImageFormat.Jpeg);
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="pageNumber">pdf文件张数</param>
    /// <param name="size">pdf文件尺寸</param>
    /// <param name="document">pdf文件位置</param>
    /// <param name="dpi"></param>
    /// <returns></returns>
    private static System.Drawing.Image GetPageImage(int pageNumber, Size size, PdfiumViewer.PdfDocument document, int dpi)
    {
        return document.Render(pageNumber - 1, size.Width, size.Height, dpi, dpi, PdfRenderFlags.Annotations);
    }
  }
}

参考文章

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值