python爬蟲處理在線預覽的pdf文檔

 

引言

 

 

最近在爬一個網站,而後爬到詳情頁的時候發現,目標內容是用pdf在線預覽的html

好比以下網站:python

 

https://camelot-py.readthedocs.io/en/master/_static/pdf/foo.pdfgit

 

 

 

 

 

根據個人分析發現,這樣的在線預覽pdf的採用了pdfjs加載預覽,用爬蟲的方法根本沒法直接拿到pdf內的內容的,對的,你注意到了我說的【根本沒法直接拿到】中的直接兩個字,確實直接沒法拿到,怎麼辦呢?只能把pdf先下載到本地,而後用工具轉了,通過我查閱大量的相關資料發現,工具仍是有不少:github

  1.借用第三方的pdf轉換網站轉出來json

  2.使用Python的包來轉:如:pyPdf,pyPdf2,pyPdf4,pdfrw等工具瀏覽器

這些工具在pypi社區一搜一大把:多線程

 

 可是效果怎麼樣就不知道了,只能一個一個去試了,到後面我終於找到個庫,很是符合個人需求的庫 ——camelot工具

 

camelot能夠讀取pdf文件中的數據,而且自動轉換成pandas庫(數據分析相關)裏的DataFrame類型,而後能夠經過DataFrame轉爲csv,json,html都行,個人目標要的就是轉爲html格式,好,廢話很少說,開始搞網站

 

開始解析

  

1.安裝camelot:編碼

 

pip install camelot-py

pip install cv2  (由於camelot須要用到這個庫)

 

2.下載pdf:由於在線的pdf其實就是二進制流,因此得按照下載圖片和視頻的方式下載,而後存到本地的一個文件裏,這個步驟就很少說了   

 

3.解析:

 

import camelot file = 'temp.pdf' table = camelot.read_pdf(file,flavor='stream') table[0].df.to_html('temp.html')

 

以上的temp.html就是我但願獲得的數據了,而後根據個人分析發現,在read_pdf方法裏必定帶上參數  【flavor='stream'】,否則的話就報這個錯:

 

RuntimeError: Please make sure that Ghostscript is installed

 

緣由就是,read_pdf默認的flavor參數是lattice,這個模式的話須要安裝ghostscript庫,而後你須要去下載Python的ghostscript包和ghostscript驅動(跟使用selenium須要下載瀏覽器驅動一個原理),而默認咱們的電腦確定是沒有安裝這個驅動的,因此就會報上面那個錯。我試着去裝了這個驅動和這個包,去read_pdf時其實感受沒有本質區別,是同樣的,因此帶上參數flavor='stream'便可,固然若是你硬要用lattice模式的話,安裝完ghostscript包和ghostscript驅動以後,記得在當前py文件用  【import ghostscript】導入下這個包,否則仍是會報如上錯誤

 

繼續走,發現能拿到我想要的數據了,很是nice,而後忽然的,報了以下錯誤:

PyPDF2.utils.PdfReadError: EOF marker not found

 

 

 當時就是臥槽,這什麼狀況,我開始去研究EOF marker是什麼意思,可是我直接打開這個pdf文件又是正常的

 

 

 

很是詭異,網上查閱了一堆,大概意思就是說,沒有EOF結束符,這個東西在以前我作js開發的時候遇到過,js的語句體{},少了最後的【}】,

我又去了解了下EOF到底在二進制文件指的什麼,而後看到老外的這個帖子:

 

 我用一樣的方法查看數據的前五個字符和後五個字符:

 

 

 

 

 

 

 

 

好像有了眉目,我以文本的方式打開了我下載到本地的一個pdf,在%%EOF結尾以後還有不少的null

 

 

 

難道是NULL的問題?我手動刪掉null以後,單獨對這個修改過的pdf用pdf查看器打開,正常打開,沒有問題,我接着用代碼針對這個文件執行read_pdf,發現很是神奇的不會報錯了,那還真是結尾的NULL元素了。

而後我在從網上讀取到pdf以後的二進制部分用字符串的strip()方法,覺得用strip能夠去除那些null,結果發現仍是如此

 

 

 

 -------------------------------------

那就只有先鎖定  %%EOF 所在位置,而後切片操做了,部分代碼以下,果真問題解決,但同時又報了一個新的錯,這個就是個編碼問題了,相信搞爬蟲的朋友們對這個問題很是熟悉了

 

 

 

先暫時無論這個問題,我又改了下目標網站的指定頁碼

 

 

 

pdfminer.psparser.SyntaxError: Invalid dictionary construct: [/'Type', /'Font', /'Subtype', /'Type0', /'BaseFont', /b"b'", /"ABCDEE+\\xcb\\xce\\xcc\\xe5'", /'Encoding', /'Identity-H', /'DescendantFonts', <PDFObjRef:11>, /'ToUnicode', <PDFObjRef:19>]

 

 

發現問題愈來愈嚴重了,我鼓搗了一番以後,又查了一堆資料,將utf-8改爲gb18030仍是報錯,我發現我小看這個問題了,接着查閱,而後發現github上camelot包的issues也有人提了這個報錯,

https://github.com/atlanhq/camelot/issues/161

 

 

 

 

 

 

 

而後這裏有我的說能夠修復下pdf文件:

 

 

我查了下,須要安裝一個軟件mupdf,而後在終端用命令 修復  

mutool clean 舊的.pdf 新的.pdf

 

首先這並非理想的解決方法,在python代碼中,是能夠調用終端命令,用os和sys模塊就能夠,可是萬一由於終端出問題還很差找緣由,因此我並無去修復,以後我發現我這個決定是對的 

 

接着看,發現issue裏不少人都在反饋這個問題,最後看到這個老哥說的

 

 

 

 

 

大概意思就是說pypdf2沒法完美的處理中文文檔的pdf,而camelot對pdf操做就基於pypdf2,臥槽,這個就難了。

 

 

而後我又查到這篇文章有說到這個問題:https://blog.csdn.net/kmesky/article/details/102695520

 

 

那隻能硬改源碼了,改就改吧,畢竟這也不是我第一次改源碼了

 

注意:若是你不知道的狀況下,千萬不要改源碼,這是一個大忌,除非你很是清楚你要作什麼

 

修改源碼:

1.format.py

C:\Program Files\Python37\Lib\site-packages\pandas\io\formats\format.py該文件的第846行

 

由這樣:

 

 

 

改爲這樣:

 

  

 

2.generic.py

 

File "D:\projects\myproject\venv\lib\site-packages\PyPDF2\generic.py", 該文件的第484行

 

 

 

 

3.utils.py

Lib/site-packages/PyPDF2/utils.py 第238行

 

 

4.運行

 

再運行:以前那些錯誤已經沒有了

 

但同時又有了一個新的錯

 

其實這個超出索引範圍的報錯的根本是上面的警告:UserWarning:page-1 is image-based,camelot only works on text-based pages. [streams.py:443]

 

 

 

由於源數據pdf的內容是個圖片,再也不是文字,而camelot只能以文本形式提取數據,因此數據爲空,因此 table[0]會報索引超出範圍

 

針對圖片的處理,我網上查閱了一些資料,以爲這篇文章寫的不錯,能夠提取pdf中的圖片

http://www.javashuo.com/article/p-sxccfttj-ho.html 

 

可是,個人目標是但願拿到pdf中的內容,而後轉成html格式,在以前,我已經由在線pdf->本地pdf->提取表格->表格轉html,這是第一種。

若是要提取圖片的話,那步驟就是第二種:在線pdf->本地pdf->提取圖片->ocr提取表格->驗證對錯->表格轉html,這樣就會多些步驟,想一想,我爲了拿到一個網站的數據,每一個網頁就要作這些操做,並且還要判斷是圖片就用用第二種,是表格就用第一種,兩個方法加起來的話,爬一個網站的數據要作的操做的就多了,雖然這些都屬於IO操做型,可是到後期開啓多線程,多進程時,與那些直接就能從源網頁提取的相比就太耗時間了。

這樣不是不行,是真的耗時間,因此我暫時放棄對圖片的提取了,只提取table,先對pdf二進制數據判斷是不是圖片,是圖片就跳過了

 

原理就是,根據上面那片博客裏的:

 

 

 

 

 

打開二進制源碼驗證:

 

 

第一個,它確實是圖片的:

 

 

 

 

 

 

第二個,它是表格:

 

 

 

 

 

 

不過通過個人驗證,發現這個方法正確率不能百分之百,少部分的即便是表格仍是有/Image和/XObject相關的字符串

 

 

那沒辦法了,有多少是多少吧

 

部分代碼實現:

fujian_data = requests.get(fujian_url, headers=headers).content
fujian_index = fujian_data.index(b'%%EOF')
fujian_data = fujian_data[:fujian_index + len(b'%%EOF')]
checkXO = rb"/Type(?= */XObject)"
checkIM = rb"/Subtype(?= */Image)"
isXObject = re.search(checkXO, fujian_data)
isImage = re.search(checkIM, fujian_data)
if isXObject and isImage:
    # 是圖片跳過
    pass
f = open('temp.pdf', 'wb')
f.write(fujian_data)
f.close()
tables = camelot.read_pdf('temp.pdf', flavor='stream')
if os.path.exists('temp.pdf'):
    os.remove('temp.pdf')  # 刪除本地的pdf
tables[0].df.to_html('foo.html', header=False, index=False)

 

 

 

 

至此完畢,固然,你也能夠用camelot 的to_csv 和 to_json方法轉成你但願的,具體就本身研究了

 

以上就是Python處理在線pdf的全部內容

相關文章
相關標籤/搜索