Java多线程方式快速解析大量文本内容得到pdf链接转换为文本-学习笔记

Java多线程方式快速解析大量文本内容得到pdf链接转换为文本-学习笔记

解析流程:

1、一个目录里面包含大量多种格式文件;
2、从目录中提取txt为后缀的文件路径List;
3、根据服务器性能设定多线程处理文本数量;
4、txt文本中获取所有的链接;
5、通过正则提取后缀为.pdf链接;
6、下载pdf文件到本地;
7、使用开源工具把pdf转换为txt内容;


获取链接正则表达式

//URL正则
private static final Pattern WEB_URL = Pattern.compile(
            "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?((?:(?:[a-zA-Z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF][a-zA-Z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF\\-]{0,64}\\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?)(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?(?:\\b|$)");

解析PDF为txt需要用到工具添加到pom文件

<!-- PDF识别为txt内容pom -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>

PDF转换为txt工具类:

package com.utils;

import java.io.IOException;

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.SimpleTextExtractionStrategy;
import com.itextpdf.text.pdf.parser.TextExtractionStrategy;

public class PdfToTextFileUtil {
    /**
     * 将PDF文件分页解析为txt格式文件
     * 
     * @param fileName
     * @throws IOException
     */
    public static String getPdfFileText(String fileName) throws IOException {
        StringBuilder sf = new StringBuilder();
        PdfReader reader = new PdfReader(fileName);
        PdfReaderContentParser parser = new PdfReaderContentParser(reader);
        TextExtractionStrategy strategy = null;
        //PDF每页解析的内容,再追加
        for (int i = 0; i < reader.getNumberOfPages(); i++) {
            strategy = parser.processContent(i+1, new SimpleTextExtractionStrategy());
            sf.append(strategy.getResultantText().toString());
        }
        return sf.toString();
    }

    public static void main(String[] args) {
        String fileName = "C:/Users/13533/Desktop/image/1.pdf";
        System.out.println(getPdfFileText(fileName));
    }
}

用到的一些实体类

public class PrivacyPolicyTextInfo {
       public String fileName;
       public String content;

       public PrivacyPolicyTextInfo(String fileName, String content) {
            this.fileName = fileName;
            this.content = content;
       }
}

文件目录中获取为.txt后缀的文件路径代码

public class CommonUtil {
    /**
     * 获取目录下给定文件后缀的所有文件路径
     *
     * @param dir       需要搜索的目录
     * @param endkeys   需要搜索的文件后缀类型,若为null,则返回所有文件
     * @param recursion 是否递归搜索,false不递归搜索,true递归搜索
     * @return 返回所有搜索到的文件路径
     */
    public static List<String> listAllFilesInDir(String dir, String[] endkeys, boolean recursion) {
        List<String> result = new ArrayList<String>();
        File[] files = new File(dir).listFiles();
        if (null != files && files.length > 0) {
            for (File file : files) {
                if (file.isDirectory()) {
                    if (recursion)
                        result.addAll(listAllFilesInDir(file.getAbsolutePath(), endkeys, recursion));// 若为目录,则递归搜索
                } else if (null != endkeys) {
                    String temp = file.getName();
                    for (String endkey : endkeys)
                        if (temp.endsWith(endkey))
                            result.add(file.getAbsolutePath().replaceAll("\\\\", "/"));// 若为给定类型,则获取绝对路径并加入结果链表
                } else
                    result.add(file.getAbsolutePath().replaceAll("\\\\", "/"));// fileTypes为null,则将所有类型文件加入结果链表
            }
        }
        return result;// 返回结果
    }
}

并多线程方式从txt内容中通过正则表达式获取链接地址,判断是否是.pdf后缀链接

package com.utils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import com.entity.PrivacyPolicyTextInfo;

public class URLTokenizer {

    //获取URL正则
    private static final Pattern WEB_URL = Pattern.compile(
            "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?((?:(?:[a-zA-Z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF][a-zA-Z0-9\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF\\-]{0,64}\\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?)(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?(?:\\b|$)");

    public static List<String> segment(String text) {
        List<String> termList = new LinkedList<String>();
        Matcher matcher = WEB_URL.matcher(text);
        while (matcher.find()) {
            String machUrl = matcher.group();
            if(machUrl==null){
                continue;
            }
            if(!machUrl.toLowerCase().startsWith("http") || !machUrl.toLowerCase().endsWith(".pdf")) {
                continue;
            }
            termList.add(machUrl);
        }
        return termList;
    }

    public static List<String> threadSegment(List<String> list) throws InterruptedException, ExecutionException{
        List<String> newList = new ArrayList<String>();
        // 每10条数据开启一条线程
        int threadSize = 10;
        // 总数据条数
        int dataSize = list.size();
        // 线程数
        int threadNum = dataSize / threadSize + 1;
        // 定义标记,过滤threadNum为整数
        boolean special = dataSize % threadSize == 0;

        // 创建一个线程池
        ExecutorService exec = Executors.newFixedThreadPool(threadNum);
        // 定义一个任务集合
        List<Callable<List<String>>> tasks = new ArrayList<Callable<List<String>>>();
        Callable<List<String>> task = null;
        List<String> cutList = null;

        // 确定每条线程的数据
        for (int i = 0; i < threadNum; i++) {
            if (i == threadNum - 1) {
                if (special) {
                    break;
                }
                cutList = list.subList(threadSize * i, dataSize);
            } else {
                cutList = list.subList(threadSize * i, threadSize * (i + 1));
            }

            final List<String> listStr = cutList;
            task = new Callable<List<String>>() {
                @Override
                public List<String> call() throws Exception {
//                    System.out.println(Thread.currentThread().getName() + "线程:" + listStr);
                    List<String> res = new ArrayList<>();
                    listStr.forEach(path->{
                        try {
                            List<String> termList = segment(Text2Pic.readTxtFile(path));
                            if(termList!=null && termList.size()>0) {
                                res.addAll(termList);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                    return res;
                }
            };
            tasks.add(task);
        }

        List<Future<List<String>>> results = exec.invokeAll(tasks);

        for (Future<List<String>> future : results) {
            newList.addAll(future.get());
        }
        // 关闭线程池
        exec.shutdown();
        return newList;
    }

    //解析是否存在PDF隐私政策链接
    private static void pdfPrivacyContent(String uncompress, List<PrivacyPolicyTextInfo> subPagePrivacyDetailList) throws IOException{
        List<String> filePaths = CommonUtil.listAllFilesInDir(uncompress  + File.separator + "capture_info", new String[]{".txt",".TXT"}, true);
        if(filePaths==null || filePaths.size()==0) {
            return;
        }
        long t1 = System.currentTimeMillis();
        List<String> list = null;
        try {
            //得到PDF链接地址
            list = URLTokenizer.threadSegment(filePaths);
            System.out.println(list);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        if(list==null || list.size()==0) {
            return ;
        }

        for (int i = 0; i < list.size(); i++) {
            //识别PDF内容
            String url = list.get(i);
            String fileName = url.substring(url.lastIndexOf("/")+1, url.length());
            String pdfLoalPath = uncompress  + File.separator + fileName;
            FileUtils.copyURLToFile(new URL(list.get(i)), new File(pdfLoalPath));
            if(!new File(pdfLoalPath).exists()) {
                continue;
            }
            String privacyContent = PdfToTextFileUtil.getPdfFileText(pdfLoalPath);
            if(StringUtils.isBlank(privacyContent)) {
                continue;
            }

            if (!privacyContent.contains("隐私政策") || privacyContent.length() < 200) {
                continue;
            }
            PrivacyPolicyTextInfo info = new PrivacyPolicyTextInfo(fileName,privacyContent);
            subPagePrivacyDetailList.add(info);
        }
        long t2 = System.currentTimeMillis();
        System.out.print("识别耗时:"+(t2-t1));
    }

    public static void main(String[] args) {
//      String txtPath = "C:/Users/13533/Downloads/且慢_20220422094601/205f0b6c85faa32e5bce73c24cfa1b77_26605_AUTO/capture_info/";
//      List<String> filePaths = CommonUtil.listAllFilesInDir(txtPath, new String[]{".txt",".TXT"}, true);
//      if(filePaths==null || filePaths.size()==0) {
//          return;
//      }
//      long t1 = System.currentTimeMillis();
//      try {
//          List<String> list = threadSegment(filePaths);
//          System.out.println(list);
//      } catch (InterruptedException e) {
//          e.printStackTrace();
//      } catch (ExecutionException e) {
//          e.printStackTrace();
//      }
//      
//      long t2 = System.currentTimeMillis();
//      System.out.println("识别耗时:"+(t2-t1));

        String txtPath = "C:/Users/13533/Downloads/且慢_20220422094601/205f0b6c85faa32e5bce73c24cfa1b77_26605_AUTO/";
        List<PrivacyPolicyTextInfo> list = new ArrayList<>();
        try {
            pdfPrivacyContent(txtPath, list);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(list!=null) {
            for (PrivacyPolicyTextInfo privacyPolicyTextInfo : list) {
                System.out.println(privacyPolicyTextInfo.content);
            }
        }
    }
}

执行后得到内容:

如果有什么好的建议,可以在下面留言评论,一起相互学习下。

发布者:小站,转转请注明出处:http://blog.gzcity.top/4176.html

(1)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年5月1日 20:53
下一篇 2022年5月3日 02:49

相关推荐

  • WIN10 控制台cmd乱码及永久修改编码的解决办法

    WIN10 cmd控制台本来的编码是ANSI的,所以要求执行的批处理脚本编码格式也是ANSI才行,要不就两边统一都改成UTF-8处理(作为一个程序员,一般我都会统一成UTF-8编码格式),下面就介绍如何统一改成UTF-8编码格式   一、修改控制台CMD编码格式为UTF-8 我本机的系统环境: OS Name: Microsoft Windows 10 企业…

    2022年12月6日
    652350
  • Apache Log4J2 远程代码执行漏洞处置手册

    1、漏洞概述 Apache Log4j2是一个基于Java的日志记录工具。该日志框架被大量用于业务系统开发,用来记录日志信息。此次爆发的0day漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。 漏洞细节 漏洞PoC 漏洞EXP 在野利用已公开 已公开 已公开 存在 参考链接:https://issues.apache.org/jira…

    2022年8月3日
    723920
  • Java操作SFTP工具类,文件上传下载删除,获取列表目录

    Java操作SFTP工具类,文件上传下载删除,获取列表目录 需要依赖的Maven包 <!– SFTP –> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>…

    2022年6月1日
    860800
  • Git clone代码报“fatal: Out of memory, malloc failed (tried to allocate xxxx bytes)”的解决办法

    问题描述: 之前clone代码的时候一直没问题,今天clone代码的时候突然报错“fatal: Out of memory, malloc failed (tried to allocate 1058576000 bytes)”。 按报错的理解就是本机的内存不足了,查看了本机运行的服务和进程,没有可以停掉的服务和进程,那该怎么办呢? 查询资料都说的是因为GI…

    2023年3月21日
    2.8K7190
  • Android版本 (1.0~12.0) 与API Level (SDK版本1~32) 对应表

    什么是 API 级别? API 级别是一个对 Android 平台版本提供的框架 API 修订版进行唯一标识的整数值。 Android 平台提供了一种框架 API,应用可利用它与底层 Android 系统进行交互。 该框架 API 由以下部分组成: 一组核心软件包和类 一组用于声明清单文件的 XML 元素和属性 一组用于声明和访问资源的 XML 元素和属性 …

    Java 2023年6月1日
    25.4K25260

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

评论列表(1,023条)