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

筆者前陣子在抽取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 subprocessimport ospath = r"F:qpdf"pre = r"C:Users ctctctPycharmProjectsyxplfiles" #初始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介面,直接調用。

推薦閱讀:

Mac 平台 5 款 PDF 閱讀編輯軟體
PDF編輯個人心得 (Tips on PDF Editing)

TAG:密码 | PDF编辑 | Python |