社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

他山之石,可以攻玉--python调用exe文件批量移除pdf密码

一个普普通通简简单单平平凡凡的神 • 8 年前 • 440 次点击  

笔者前阵子在抽取pdf文字时,碰到了一个棘手的问题:无法直接编辑加密的pdf文本。

带密码保护的pdf案例

什么是加密的pdf?加密的pdf 分为两类:第一种为pdf在打开需要密码;第二种是在pdf的操作受到了限制,需要密码才能解除限制。本文讨论第二种情况。

来看看一篇加密的pdf文档有哪些权利受到了限制(访问文档属性-->安全信息)。

连打印都不允许……这,有点过了,毕竟招股书是公开的文档。

那么究竟如何去除加密的pdf文档的密码?注意,这里是去除,而不是破解。文章讨论将带有密码保护的pdf转化为没有密码保护的pdf,而不是如何获取密码。

--方案1--

推介一个网站【I LOVE PDF】

I LOVE PDF页面截图

利用这个网站,你只需要上传文件,就能对pdf进行切割、合并、破解、转化为word等操作……挺棒的,免费,无需注册!

但是,如果有超过10M的文件,网站是不受理的;如果你有100份文件,那么就得上传100次……尺有所长,尺有所短,网站已经尽力了,毕竟设计初衷不是为了大批量处理文件。涉及机密文件,建议不要上传……

--方案2--

对于切割合并等基础操作,使用库pypdf操作即可--详情可查看笔者之前的文章《利用python处理PDF文本》。

对于密码解除,笔者尝试了诸多方案。这里就不废话了,直接上干货--qpdf。

以上是官网对于QPDF介绍。简言之,qpdf是一款可以移除密码的在命令行终端操作的软件。

qpdf 的优势:

  • 破除 256-bit encryption keys and AES
  • 破除 default RC4 with 40, 128 or 256 bit key lengths

命令行语法如下:

基本语法

其中:

  1. infilename 是指导入的文件的名字,也就是需要移除密码的文件
  2. outfilename:经过处理之后的需要导出的文件的名字,也就是最终你要的文件的名字
  3. options:需要使用的命令。下图是可以使用的命令的一小部分,其中黄色标注的的--decrypt 是我们需要的命令。这里很明显的提到:如果PDF打开时需要密码,则需要提供密码,这里仅仅移除文档的权限加密。
option选项

因此,在转到qpdf的安装目录下,你只需要在命令行终端收入一下命令:

qpdf --decrypt infilename outfilename

命令行终端示意图

好了,对于单个文件确实可以这么处理。那么对于100个文件该如何处理?只需要在命令行终端输入100遍即可?嗯,是的,如果你不嫌麻烦。但是,重复的劳动,应该交给机器来完成。实际上,写个批处理就可以轻松搞定这个任务。

if 你会批处理:

-----文章到此结束----

else:

-----请继续阅读----

--------------------不会的批处理的朋友请往下看-------------------

好了,当你在使用命令行进行pdf解密时,你实际上在打开一个进程。

接下来要做的事情已经很明了,就是利用python调用命令行终端,建立多进程直接同时对多个文件进行处理。

python调用命令行终端库主要有os、subprocess

python打开命令行终端的库及其关系

官网推荐,尽量不使用os.system;同时,o.popen也是调用subprocess.Popen,因此,推荐直接使用subprocess.Popen。subprocess.Popen语法如下:

class Popen(object):
    """ Execute a child program in a new process.

    For a complete description of the arguments see the Python documentation.

    Arguments:
      args: A string, or a sequence of program arguments.

      bufsize: supplied as the buffering argument to the open() function when
          creating the stdin/stdout/stderr pipe file objects

      executable: A replacement program to execute.

      stdin, stdout and stderr: These specify the executed programs' standard
          input, standard output and standard error file handles, respectively.

      preexec_fn: (POSIX only) An object to be called in the child process
          just before the child is executed.

      close_fds: Controls closing or inheriting of file descriptors.

      shell: If true, the command will be executed through the shell.

      cwd: Sets the current directory before the child is executed.

      env: Defines the environment variables for the new process.

      universal_newlines: If true, use universal line endings for file
          objects stdin, stdout and stderr.

      startupinfo and creationflags (Windows only)

      restore_signals (POSIX only)

      start_new_session (POSIX only)

      pass_fds (POSIX only)

      encoding and errors: Text mode encoding and error handling to use for
          file objects stdin, stdout and stderr.

    Attributes:
        stdin, stdout, stderr, pid, returncode
    """
    _child_created = False  # Set here since __del__ checks it

    def __init__(self, args, bufsize=-1, executable=None,
                 stdin=None, stdout=None, stderr=None,
                 preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0,
                 restore_signals=True, start_new_session=False,
                 pass_fds=(), *, encoding=None, errors=None):
        """Create new Popen instance."""
        _cleanup()
        # Held while anything is calling waitpid before returncode has been
        # updated to prevent clobbering returncode if wait() or poll() are
        # called from multiple threads at once.  After acquiring the lock,
        # code must re-check self.returncode to see if another thread just
        # finished a waitpid() call.
        self._waitpid_lock = threading.Lock()

        self._input = None
        self._communication_started = False

#------------------------丑陋的界面--------------------

我们分步来分析subprocess.Popen

首先,Popen是一个类

其自带一个初始化函数

初始化参数里面有若干个参数,我们逐一展示

参数1
参数2

重点来看看shell参数。

如果直接通过命令行来执行,那么shell = True

官网对于shell的解释

简单来说,如果你的程序依赖于其他命令行输入,那么使用shell相当危险!由于我们不需要在命令行直接输入命令,因此这里并无风险。

为何我们要关注shell这个参数?好吧,如果shell= False,将直接导致程序错误,找不到文件([Errno 2] No such file or directory)!

好了,函数解析完毕,直接上代码

#批量破解pdf密码
import subprocess
import  os
path = r"F:\qpdf"
pre = r"C:\Users\tctctct\PycharmProjects\yxpl\files"  #初始pdf文件夹
final = r"D:\yxpl"     #存放破解的pdf的文件夹
files = os.listdir(pre)
exit_files = os.listdir(final)
for j  in files:
    if j not in exit_files:
        abs_file = os.path.join(pre,j)
        out_file = os.path.join(final,j)
        cmd = ["qpdf","--decrypt",abs_file,out_file]  #命令行终端命令
        sub = subprocess.Popen(args=cmd,cwd=path,shell=True)  #不要忘记cwd
        sub.wait()   #最好加上,否则可能由于多个进程同时执行带来机器瘫痪

后续:

  • 有兴趣朋友可以借助tkinter或者pyqt做一个用户界面,方便python用户使用。如果懂点pyinstaller,也可以将程序打包成exe文件,方便完全不懂python的小白使用。
  • pdf 文章有了,如何抽取里面的文字?请看《利用python处理PDF文本》
  • 文字也有了, 如何识别出你要的内容或者进行转化?请学习自然语言处理+正则表达式
  • 拓展思路,命令行可以做的事,python可以直接做。再进一步,其他语言做好的事情,python来调用。例如,java库pdfbpox擅长处理pdf ,那么就写个pdfbox python接口,直接调用。

今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/5DV4RCemxm
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/6302