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

引言

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

比如如下網站:

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

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

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

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

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

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

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

camelot可以讀取pdf文件中的數據,並且自動轉換成pandas庫(數據分析相關)裡的DataFrame類型,然後可以通過DataFrame轉為csv,json,html都行,我的目標要的就是轉為html格式,好,廢話不多說,開始搞。

開始解析

1.安裝camelot:

pip install camelot-py

pip install cv2 (因為camelot需要用到這個庫)

2.下載pdf:因為在線的pdf其實就是二進制流,所以得按照下載圖片和視頻的方式下載,然後存到本地的一個文件裡,這個步驟就不多說了

3.解析:

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

以上的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


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

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


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

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

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

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

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


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

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

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


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

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

然後我在從網上讀取到pdf之後的二進制部分用字符串的strip()方法,以為用strip可以去除那些null,結果發現還是如此


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

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


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

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

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


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

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

發現問題越來越嚴重了,我鼓搗了一番之後,又查了一堆資料,將utf-8改成gb18030還是報錯,我發現我小看這個問題了,接著查閱,然後發現github上camelot包的issues也有人提了這個報錯,

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

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


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

然後這裡有個人說可以修復下pdf文件:

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

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

mutool clean 舊的.pdf 新的.pdf

首先這並不是理想的解決方法,在python代碼中,是可以調用終端命令,用os和sys模塊就可以,但是萬一因為終端出問題還不好找原因,所以我並沒有去修復,之後我發現我這個決定是對的

接著看,發現issue裡很多人都在反饋這個問題,最後看到這個老哥說的

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

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

那隻能硬改源碼

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

注意:如果你不知道的情況下,千萬不要改源碼,這是一個大忌,除非你非常清楚你要做什麼

修改源碼:

1.format.py

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

由這樣:

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


改成這樣:

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

2.generic.py

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

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

3.utils.py

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

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

4.運行

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

但同時又有了一個新的錯

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


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

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

但是,我的目標是希望拿到pdf中的內容,然後轉成html格式,在之前,我已經由在線pdf->本地pdf->提取表格->表格轉html,這是第一種。

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

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

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

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

打開二進制源碼驗證:

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


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

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

第二個,它是表格:


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


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

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

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

部分代碼實現:

<code>fujian_data = requests.get(fujian_url, headers=headers).contentfujian_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:    # 是圖片跳過    passf = 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')  # 刪除本地的pdftables[0].df.to_html('foo.html', header=False, index=False)/<code>

至此完畢,當然,你也可以用camelot 的to_csv 和 to_json方法轉成你希望的,具體就自己研究了

最後,小編想說:我是一名python開發工程師,整理了一套最新的python系統學習教程,想要這些資料的可以關注私信小編“01”即可,希望能對你有所幫助。



分享到:


相關文章: