当前位置: 首页 > news >正文

创业做网站APP开发浙江网络推广

创业做网站APP开发,浙江网络推广,wordpress 建两个网站,网站制作与网站建设某天项目组来了个需求说需要提取 PDF 文件中数据作为数据沉淀使用,这是因为第三方系统不提供数据接口所以只能够出此下策。 就据我所知,PDF 文件内数据提取目前有 3 种解决方案: 第一种,资金足够的话可以直接通过人工智能对 PDF…

某天项目组来了个需求说需要提取 PDF 文件中数据作为数据沉淀使用,这是因为第三方系统不提供数据接口所以只能够出此下策。

就据我所知,PDF 文件内数据提取目前有 3 种解决方案:

第一种,资金足够的话可以直接通过人工智能对 PDF 内容进行解析,按照你需要的规格数据进行输出即可;

第二种,采用 OCR 识别技术对内容进行提取;

第三种,通过工具实现(也是我将为您呈现的)。在开源社区中 PDFbox 人气很高,文字的识别率也很不错,但是对于表格支持不太友好,涉及到表格数据提取的我选用了 Tabula 来实现;

Tabula 是什么?

Tabula是一个开源工具,用于从PDF文档中提取表格数据。它的主要技术包括:

  1. PDF 解析:Tabula 使用 Java 的 PDFBox 库来解析 PDF 文档的内容和布局。它可以定位到每个页的文本块和图像的坐标;
  2. 表格识别:Tabula 通过分析页面上的线条和文本块的布局来识别表格的结构。它会查找垂直和水平的线条作为列和行的分隔符;
  3. 单元格提取:在确定了表格的结构后,Tabula 会分析每个单元格对应的文本块,并提取出单元格中的文本内容;
  4. 数据整理:Tabula 会尝试自动整理从表格中提取的数据,例如:纵向和横向合并单元格,处理跨页的表格等。它也会执行一定的文本清理;
  5. 导出格式:Tabula 支持将提取出来的数据导出为 CSV 和 JSON 格式。用户可以导入到 Excel 等其他工具中进行后续分析。
  6. 优化算法:Tabula 在表格分析和数据提取方面使用了一些优化的算法和启发式规则,以提高正确率。同时它也提供了交互式的编辑接口供用户校正结果。

怎么用 Tabula?

首先肯定是引入 pom 文件依赖,如下图:

<dependency><groupId>technology.tabula</groupId><artifactId>tabula</artifactId><version>1.0.5</version>
</dependency>

接着就可以创建 PDF 工具类了(PdfUtil)

public class PdfUtil {...private static final SpreadsheetExtractionAlgorithm SPREADSHEEET_EXTRACTION_ALGORITHM = new SpreadsheetExtractionAlgorithm();private static final ThreadLocal<List<String>> THREAD_LOCAL = new ThreadLocal<>();.../*** @description: 解析pdf表格(私有方法)*               使用 tabula-java 的 sdk 基本上都是这样来解析 pdf 中的表格的,所以可以将程序提取出来,直到 cell*               单元格为止* @param {*} String pdf 路径* @param {*} int 自定义起始行* @param {*} PdfCellCallback 特殊回调处理* @return {*}*/private static JSONArray parsePdfTable(String pdfPath, int customStart, PdfCellCustomProcess callback) {JSONArray reJsonArr = new JSONArray(); // 存储解析后的JSON数组try (PDDocument document = PDDocument.load(new File(pdfPath))) {PageIterator pi = new ObjectExtractor(document).extract(); // 获取页面迭代器// 遍历所有页面while (pi.hasNext()) {Page page = pi.next(); // 获取当前页List<Table> tableList = SPREADSHEEET_EXTRACTION_ALGORITHM.extract(page); // 解析页面上的所有表格// 遍历所有表格for (Table table : tableList) {List<List<RectangularTextContainer>> rowList = table.getRows(); // 获取表格中的每一行// 遍历所有行并获取每个单元格信息for (int rowIndex = customStart; rowIndex < rowList.size(); rowIndex++) {List<RectangularTextContainer> cellList = rowList.get(rowIndex); // 获取行中的每个单元格callback.handler(cellList, rowIndex, reJsonArr);}}}} catch (IOException e) {LOGGER.error(MARKER,"function[PdfUtil.parsePdfTable] Exception [{} - {}] stackTrace[{}]",e.getCause(), e.getMessage(), e.getStackTrace());} finally {THREAD_LOCAL.remove();}return reJsonArr; // 返回解析后的JSON数组}...}

这里我们先按照官网样例代码来实现 pdf 表格解析先。大致的思路就是:

  1. 创建一个空的 JSONArray 对象 reJsonArr ,用于存储解析后的表格数据;
  2. 使用 PDDocument.load 方法加载指定路径的 PDF 文件,并使用 try-with-resources 语句创建一个 PDDocument 对象 document ;
  3. 使用 ObjectExtractor 从 document 中提取页面迭代器 pi ;
  4. 使用 while 循环遍历每个页面,使用 pi.hasNext 方法判断是否还有下一个页面,如果有则进入循环;
  5. 使用 pi.next 方法获取当前页面对象 page ;
  6. 使用 SPREADSHEEET_EXTRACTION_ALGORITHM 解析 page 中的所有表格,并将结果存储在 tableList 中;
  7. 使用 for 循环遍历 tableList 中的每个表格,对于每个表格执行以下操作:
    a. 使用 table.getRows 方法获取表格中的每一行,并将结果存储在 rowList 中;
    b. 使用 for 循环遍历 rowList 中的每一行,从 customStart 位置开始,对于每一行执行以下操作:
    i. 使用 rowList.get 方法获取行中的每个单元格,并将结果存储在 cellList 中;
    ii. 将 cellList 、 rowIndex 和 reJsonArr 作为参数传递给回调函数 callback 的 handler 方法进行处理;
  8. 使用 try-catch 语句捕获可能发生的 IOException 异常,并记录错误信息;
  9. 使用 finally 语句移除 THREAD_LOCAL 中的数据;
  10. 返回解析后的 JSONArray 对象 reJsonArr ;

这里要加上一个 callback.handler 回调函数主要的目的是为了将“单元格操作”跟 pdf 解析两部分代码进行解耦,那么这个回调接口的接口定义如下:

@FunctionalInterface
public interface PdfCellCustomProcess {/*** @description: 自定义单元格回调处理* @return {*}*/void handler(List<RectangularTextContainer> cellList, int rowIndex, JSONArray reJsonArr);
}

其中 cellList 传入的是这一行的所有单元格的集合,rowIndex 传入的是当前行码,reJsonArr 是返回值。具体的实现代码如下:

public class PdfUtil {.../*** @description: 解析 pdf 中简单的表格并返回 json 数组* @param {*} String PDF文件路径* @param {*} int 自定义起始行* @return {*}*/public static JSONArray parsePdfSimpleTable(String pdfPath, int customStart) {return parsePdfTable(pdfPath, customStart, (cellList, rowIndex, reArr) -> {JSONObject jsonObj = new JSONObject();// 遍历单元格获取每个单元格内字段内容List<String> headList = ObjectUtil.isNullObj(THREAD_LOCAL.get()) ? new ArrayList<>(): THREAD_LOCAL.get();for (int colIndex = 0; colIndex < cellList.size(); colIndex++) {String text = cellList.get(colIndex).getText().replace("\r", " ");if (rowIndex == customStart) {headList.add(text);} else {jsonObj.put(headList.get(colIndex), text);}}if (rowIndex == customStart) {THREAD_LOCAL.set(headList);}if (!jsonObj.isEmpty()) {reArr.add(jsonObj);}});}...}

代码的主要部分是一个 Lambda 表达式,它作为参数传递给 parsePdfTable 方法。Lambda 表达式做了PdfCellCustomProcess 接口的实现。Lambda 表达式的代码块首先创建一个 JSONObject 对象,然后遍历单元格列表,获取每个单元格的文本内容。

如果当前行索引等于自定义起始行索引,将文本内容添加到 headList 列表中;否则,将文本内容作为键值对添加到jsonObj 对象中。最后,如果 jsonObj 对象不为空,则将其添加到 reArr 数组中。 代码还包含了一些其他操作。如果当前行索引等于自定义起始行索引,将 headList 列表设置为 THREAD_LOCAL 线程局部变量。最后,返回 reArr数组作为方法的结果。

最后只需要补上 main 方法调用即可获取到解析后的 JsonArray 集合。但是直接输出 JsonArray 数据并不直观,于是我又写了一个解析 JsonArray 数据的方法,并将里面的数据转换为 Markdown 格式,如下图:

private static String outputMdFormatForVerify(JSONArray jsonArr) {StringBuilder mdStrBld = new StringBuilder();StringBuilder headerStrBld = new StringBuilder("|");StringBuilder segmentStrBld = new StringBuilder("|");for (int row = 0; row < jsonArr.size(); row++) {StringBuilder bodyStrBld = new StringBuilder("|");JSONObject rowObj = (JSONObject) jsonArr.get(row);if (row == 0) {rowObj.forEach((k, v) -> {headerStrBld.append(" ").append(k).append(" |");segmentStrBld.append(" ").append("---").append(" |");});headerStrBld.append("\n");segmentStrBld.append("\n");mdStrBld.append(headerStrBld).append(segmentStrBld);}rowObj.forEach((k, v) -> bodyStrBld.append("").append(v).append("|"));bodyStrBld.append("\n");mdStrBld.append(bodyStrBld);}return mdStrBld.toString();
}

这个应该比较好理解吧,这里就不再详述了。

以上的代码对于一般的 PDF 表格解析是基本没有问题的,但是对于带有合并单元格的解析就不能满足了。合并单元格需要考虑横向合并、纵向合并和混合合并三种合并模式,不是说 tabula-java 的 sdk 不能做只是比较麻烦,在 tabula-java 方案中我们可以获取到单元格的高和宽,那么先做一次全遍历获取二维数组对于单元格定位后,根据高和宽进行虚拟表格的建设,最后根据二维数组对数据进行回填即可。这也是用回调将单元格操作分离的原因之一,为了后面做合并单元格解析做准备的。

但其实上面说这么多,合并单元格解析的代码我还没写呢(以上都是我吹的),等完成后再给大家分享。

http://www.ocqcb.cn/news/668.html

相关文章:

  • 怎么做博彩网站推广爱站网长尾挖掘工具
  • 在线做简历的网站武汉企业网站推广
  • 如何用vs的c 做网站电脑培训学校能学什么
  • wordpress默认的固定链接广州抖音seo公司
  • 一个网站能多个域名做不同站点软文新闻发稿平台
  • 重点建设学科网站做品牌推广应该怎么做
  • 名气特别高的手表网站数据分析报告
  • 做网站编程用什么语言好网络营销公司有哪些
  • 安阳县政府官网seo自动优化软件
  • pageadmin怎么样优化大师怎么样
  • 做旅游网站的毕业论文尚硅谷培训机构官网
  • 固定链接 wordpress 不起作用青岛网站seo诊断
  • 企业型网站建设怎样收费cpa推广联盟平台
  • 手机怎么生成网站怎么做网址
  • 响应式网站模板 开源交换链接营销的经典案例
  • 直销软件直销系统东莞seo优化推广
  • 做网站加班电商的运营模式有几种
  • 湛江网站建设招聘百度指数查询
  • 网站如何做实名验证码seo优化轻松seo优化排名
  • 成品网站建设哪家好今天国际新闻最新消息
  • 网站的链接结构包括seo咨询师招聘
  • 网站建设有什么意见seo工作室
  • 商丘做微信网站sqwyy轻饮食网络推广方案
  • 小程序开发哪个公司好百度seo免费推广教程
  • 织梦后台怎么建设网站专业北京seo公司
  • 洛龙区网站制作建设费用爱站网域名查询
  • 怀化公司网站建设什么是seo?
  • xml网站地图格式杭州最好的seo公司
  • 山西企业网站建设优化网站广告优化
  • 网站的搭建需要多少钱违禁网站用什么浏览器