[R語言應用] 利用R語言處理PDF檔案
0Last Updated on 2023-10-05
你有沒有時常遇到PDF的檔案,需要把裡面的文字複製出來再貼上到其他地方,但又覺得麻煩?這篇文章告訴你解決方法
平常工作上會用到很多PDF格式的檔案,常常會用到當中的文字,或是需要裁切與合併PDF檔案,又或者要把PDF轉成txt、jpeg,但是用起來很麻煩嗎?
我整理了在R語言當中,如何利用套件處理PDF檔案的方法,讓你不用再打開線上的PDF處理工具啦,而且確保資料都留在自己的電腦裡。
R語言中PDF相關套件介紹
在R語言中,如果想要處理PDF(Portable Document
Format)格式的檔案,依照使用者需求,最常用的有3個套件。
pdftools
: 最實用,可以讀取PDF文件,提取裡面的文字、轉換成圖像、裁切與合併等。tabulizer
: 在看政府公告或研究報告的時候常常會需要提取表格,但直接複製貼上格式會跑掉,這個套件就是專門拿來提取表格用的。tesseract
: 如果檔案根本就是圖檔怎麼辦?有很多偽PDF其實是圖像,這時候需要光學字元識別(Optical Character Recognition, OCR),把圖像轉文字,這個套件就可以派上用場。
怎麼利用R語言套件處理PDF
底下會分別介紹上面提到的3個在R語言中處理PDF(Portable Document Format)檔案的套件。
pdftools:提取文字
這個套件由 R Open Science(簡稱為rOpenSci,是一個提倡開放科學研究的專案)開發,如前所述,它能夠幫上我們日常生活的工作,不過,其實套件中有好幾個函數都是來自於另一個套件 qpdf
當中,所以它算是站在前人的肩膀上!
底下介紹幾個常用函數:
– pdf_length()
: 計算 PDF 檔案的頁數,平常其實打開檔案就看得到頁數,但如果處理大量檔案的時候就能派上用場。
– pdf_info()
: 取得 PDF 的 metadata,不確定要翻成元資料還是後設資料,總之就是這份資料的相關資訊。
– pdf_length()
: 計算 PDF 檔案的頁數。
– pdf_convert()
: 把 PDF 檔案轉換成圖像,選項有 png, jpeg, jpg, tiff, pnm 等,如果想輸出成 txt 不能用這個函數喔。
– pdf_text()
: 把 PDF 檔案中的文字提取出來,但成功的前提是,本來就可以用滑鼠選取文字!如果本來就是圖檔,那什麼都抓不到。pdf_subset()
: 裁切 PDF ,要提供它開始跟結束的頁數。
– pdf_combine()
: 拼接 PDF ,要提供它想要合併的 PDF 檔案名稱。
底下我們就來看要怎麼活用 pdftools
套件吧,我使用台北市媒體服務代理商協會的2021年媒體白皮書作為案例,你可以到這裡下載。
library(pdftools)
### 長度
pdf_length("2021年媒體白皮書.pdf")
#> [1] 81
### metadata
pdf_info("2021年媒體白皮書.pdf")
#> $version
#> [1] "1.7"
#>
#> $pages
#> [1] 81
#>
#> $encrypted
#> [1] FALSE
#>
#> $linearized
#> [1] FALSE
#>
#> $keys
#> $keys$Title
#> [1] "貳、領隊實務(一)"
#>
#> $keys$Author
#> [1] "user"
#>
#> $keys$Creator
#> [1] "適用於 Microsoft 365 的 Microsoft® Word"
#>
#> $keys$Producer
#> [1] "適用於 Microsoft 365 的 Microsoft® Word"
#>
#>
#> $created
#> [1] "2021-08-25 16:22:29 CST"
#>
#> $modified
#> [1] "2021-08-25 16:22:29 CST"
#>
#> $metadata
#> [1] "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?><x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"3.1-701\">\n<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n<rdf:Description rdf:about=\"\" xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n<pdf:Producer>é\u0081©ç\u0094¨æ\u0096¼ Microsoft 365 ç\u009a\u0084 Microsoft® Word</pdf:Producer></rdf:Description>\n<rdf:Description rdf:about=\"\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">è²³ã\u0080\u0081é \u0098é\u009a\u008a實å\u008b\u0099ï¼\u0088ä¸\u0080ï¼\u0089</rdf:li></rdf:Alt></dc:title><dc:creator><rdf:Seq><rdf:li>user</rdf:li></rdf:Seq></dc:creator></rdf:Description>\n<rdf:Description rdf:about=\"\" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n<xmp:CreatorTool>é\u0081©ç\u0094¨æ\u0096¼ Microsoft 365 ç\u009a\u0084 Microsoft® Word</xmp:CreatorTool><xmp:CreateDate>2021-08-25T16:22:29+08:00</xmp:CreateDate><xmp:ModifyDate>2021-08-25T16:22:29+08:00</xmp:ModifyDate></rdf:Description>\n<rdf:Description rdf:about=\"\" xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\">\n<xmpMM:DocumentID>uuid:E812F000-7269-4A87-ABCF-462F611E126B</xmpMM:DocumentID><xmpMM:InstanceID>uuid:E812F000-7269-4A87-ABCF-462F611E126B</xmpMM:InstanceID></rdf:Description>\n \n</rdf:RDF></x:xmpmeta><?xpacket end=\"w\"?>"
#>
#> $locked
#> [1] FALSE
#>
#> $attachments
#> [1] FALSE
#>
#> $layout
#> [1] "no_layout"
### 轉圖檔
pdf_convert("2021年媒體白皮書_前10頁.pdf", page = 10, format = "png")
#> Converting page 10 to 2021年媒體白皮書_前10頁_10.png... done!
#> [1] "2021年媒體白皮書_前10頁_10.png"
### 裁切
pdf_subset(input = "2021年媒體白皮書.pdf", pages = c(1:10), output = "2021年媒體白皮書_前10頁.pdf")
#> [1] "/Users/dennistseng/Documents/GitHub/r-lover/2023-05-15-tutorial-material-r-import-pdf/2021年媒體白皮書_前10頁.pdf"
pdf_subset(input = "2021年媒體白皮書.pdf", pages = c(11), output = "2021年媒體白皮書_11頁.pdf")
#> [1] "/Users/dennistseng/Documents/GitHub/r-lover/2023-05-15-tutorial-material-r-import-pdf/2021年媒體白皮書_11頁.pdf"
### 拼接
pdf_combine(input = c("2021年媒體白皮書_前10頁.pdf","2021年媒體白皮書_11頁.pdf"), output = "2021年媒體白皮書_前11頁.pdf")
#> [1] "/Users/dennistseng/Documents/GitHub/r-lover/2023-05-15-tutorial-material-r-import-pdf/2021年媒體白皮書_前11頁.pdf"
### 檢查長度
pdf_length("2021年媒體白皮書_前11頁.pdf")
#> [1] 11
### 提取文字
text <- pdf_text("2021年媒體白皮書_前10頁.pdf")
text[5]
#> [1] "MAA 簡介 © 2021 年 MAA 台灣媒體白皮書\n MAA 簡介\n台北市媒體服務代理商協會(Media Agency Association,簡稱MAA),乃集\n合以”媒體整合企劃與購買”為核心服務之代理商,共同推動一流的媒體專業\n服務於廣告主、廣告服務與媒體產業。\n本會之任務如下:\n一、 提供一個便利會員及媒體服務代理同業互相交換意見及溝通之場所。\n二、 與會員有關之立法通知,並就會員之共同利益協助提供立法建議。\n三、 代表會員之意見,並協助會員進行與媒體、政府之洽商。\n四、 定期舉辦各類座談會、演講等活動。\n五、 促使本會會員在與客戶交易或與同業往來時,皆遵守最高之商業道德\n 標準。\n六、 制定會員共同遵守之執業標準。\n七、 向社會大眾及政府機關推廣廣告之重要性及促進大眾對媒體、廣告行\n 銷之暸解。\n八、 對影響本會會員權益之事,代表會員與有關單位洽詢並提供改革計劃。\n九、 保障本會會員及廣告公司之共同利益。\n十、 促進會員製作廣告之合法性、誠實性、淨化和真實,並保障一般大眾\n 之利益。\n 1\n"
text[10]
#> [1] "台灣地區整體概況 © 2021 年 MAA 台灣媒體白皮書\n2018年:無線:0.056, 有線:0.053, 報紙:0.324, 雜誌:0.349, 廣播:0.226, 戶外:0.85\n2019年:無線:0.053, 有線:0.052, 報紙:0.320, 雜誌:0.335, 廣播:0.223, 戶外:0.81\n2020年:無線:0.050, 有線:0.046, 報紙:0.230, 雜誌:0.280, 廣播:0.190, 戶外:0.70\n 年度前十大品類與廣告主\n廣告量前十大品類 (不含網路廣告量)\n 排名 品類 金額(千元)\n 1 醫藥美容類 5,975,986\n 2 電腦網路資訊類 2,275,789\n 3 其他類 1,805,137\n 4 建築類 1,485,144\n 5 交通工具 1,369,904\n 6 影劇媒體類 1,243,139\n 7 食品類 1,129,679\n 8 服務類 1,111,289\n 9 家用品類 1,005,668\n 10 文康類 998,639\n附註: 報紙專業綜合廣告不計入排名之列\n廣告量前十大廣告主 (不含網路廣告量)\n 排名 廣告主 金額(千元)\n 1 民視電視(股) 639,932\n 2 荷商葛蘭素史克藥廠 587,597\n 3 東森得意購(股) 555,687\n 4 寶僑家品公司 540,010\n 5 三得利健益(股) 539,592\n 6 佳格食品(股) 499,067\n 7 統一企業(股) 348,595\n 8 輝瑞生技(股) 302,267\n 9 白蘭氏三得利 295,610\n 10 台灣松下電器(股) 272,598\n資料來源:Nielsen 廣告監播服務,2020年\n廣告量依MAA調整率調整:無線0.050,有線0.046,報紙0.230,雜誌0.280,廣播0.190,\n戶外0.700\n 6\n"
上面最後提取文字部分,我抓了第五頁跟第十頁,我們來看一下原本長什麼樣子。
要轉換的圖像 – 第5頁,是一段文字
要轉換的圖像 – 第10頁,是一張表格
這樣看起來轉換的結果還不錯吧!不過,對照第5頁還好,對照第10頁就會發現,表格怎麼變成不是表格了?
雖然 pdftools
很好,但它並非萬能,上面的表格就是它的限制之一。在官方介紹中,就提到 pdftools
無法處理設有密碼的 PDF,也沒辦法處理非文字的 PDF,而且處理表格的時候問題更大。幸好,R語言當中還有其他套件可以應對。
tabulizer:提取表格
在這邊要先說聲抱歉,我寫部落格文章的電腦有缺某個 JAVA 元件,但使用tabulizer
套件必須要該元件才能執行,所以底下只能用說明而無法實作,我放上之前用其他電腦的程式碼供參考。
這個套件又是 R Open Science 開發,它裡面有好幾個函數,但最常用也最關鍵的函數就是 extract_tables()
,因為 pdftools
就能夠處理其他任務了。使用這個函數後,它會提取 PDF 檔案中的所有表格,因此得到的 table 會是一個大型的 list,每個 list 當中的元素都會是一張表格,我習慣把它變成 tibble,再後續處理。
不過,它提取出的表格也會有點髒,這邊附上因為上述問題無法實際執行的程式碼供參考,你可以看到我要另外花心思整理表格,若只有1個表格,可以考慮用 word 打開,然後把表格複製貼上到 excel 裡面,量夠少的話也可以直接手寫轉錄出來,我的這個 case 是因為有大量格式一致的檔案,所以還能替自己省下時間。
library(tabulizer)
table_all <- extract_tables("報紙發行量稽核報告.pdf")
table_all[[1]] %>% as_tibble()
### 讀進來之後一些處理步驟,展示一段清理過程
table_channel_13 <-
table_channel_compact[vector_channel_13] %>% map(~filter(., str_detect(V1, "年"))) %>%
map(~select(., -V9)) %>% bind_rows() %>% `colnames<-`(
c("月份","訂戶_報社訂戶","訂戶_經銷商訂戶","訂戶_小計","分銷承攬_派報","分銷承攬_批報","分銷承攬_小計",
"零售通路","大宗銷售","其他","月發行量","日發行量")
)
tesseract:光學字元辨識
這篇文章的架構是按照處理 PDF 任務的難度由簡至難,從PDF提取文字最簡單,從PDF提取抓表格次之,從從PDF將圖像轉成文字是最難的了。
這個套件同樣由人很好的 R Open Science 開發,如前面的介紹所說,tesseract
做的就是 OCR 的工,雖然它號稱可以識別包含中、英文、法、德等多種語言,而且函數也很單一,就是直接用 ocr()
,但成功率常常要看你的檔案狀況。
趕快補充一下,使用前要先下載你想辨識語言的引擎,例如繁體中文就是
“chi_tra”。你可以到這個頁面確認你想下載的語言名稱。
我們先來看一下要轉換的圖像長什麼樣子。雖然它是 PNG 格式,但其實原本是 PDF 喔,我就是用上面 pdftools
的裁切跟轉換,先取第一頁,接著轉成 PNG,得到這張圖像的。
要轉換的圖像 – 封面圖案
library(tesseract)
### 檢查你安裝了哪些語言引擎
tesseract_info()
#> $datapath
#> [1] "/Users/dennistseng/Library/Application Support/tesseract4/tessdata/"
#>
#> $available
#> [1] "chi_tra" "eng" "osd"
#>
#> $version
#> [1] "4.1.0"
#>
#> $configs
#> [1] "alto" "ambigs.train" "api_config" "bigram"
#> [5] "box.train" "box.train.stderr" "digits" "get.images"
#> [9] "hocr" "inter" "kannada" "linebox"
#> [13] "logfile" "lstm.train" "lstmbox" "lstmdebug"
#> [17] "makebox" "pdf" "quiet" "rebox"
#> [21] "strokewidth" "tsv" "txt" "unlv"
#> [25] "wordstrbox"
### 使用前要先下載,因為我下載過了所以註解掉
# tesseract_download("chi_tra")
# tesseract_download("eng")
### 載入引擎
eng <- tesseract("eng")
chi <- tesseract("chi_tra")
### OCR
text <- tesseract::ocr("/Users/dennistseng/Documents/GitHub/r-lover/2021年媒體白皮書_第1頁_1.png", engine = eng)
text2 <- tesseract::ocr("/Users/dennistseng/Documents/GitHub/r-lover/2021年媒體白皮書_第1頁_1.png", engine = chi)
### 來看結果
text
#> [1] "QQ» 2021 sseKBALe\n~» Media Book\nMedia Agency Association\nMé@ithsaaBte eae\nAA ©2021% MAAS RRR OR\n—_—__\n"
text2
#> [1] "全說、2021 年台灣媒體白皮書\n“有 Media Book\nMedia Agency Association\nPI台北市媒體服務代理商和佃會\n為吃 @2021年 MAA台灣疑馨白皮書\n還\n"
從這個結果我們看出什麼重點?英文引擎無法辨識中文,中文引擎則可以,我自己很滿意辨識成果,因為原始圖像頗為模糊,至少中文辨識結果正確率大概還有 8 成左右,只是這個結果能「用」嗎?假設要辨識整整一百頁的內容,但需要大修特修,可能就要尋求其他解法,除了請工讀生以外,也可以去研究其他更強大的辨識引擎。
當然,你可以提高原本圖檔的清晰程度與檔案大小,這些是語言印情以外,會影響識別結果的關鍵喔!
小結
這篇文章中,介紹了三個在R語言當中處理PDF檔案的套件,分別是pdftools
, tabulizer
, tesseract
,它們各擅勝場,分別可以負責提取文字裁切合併的一般用途、提取表格、光學字元辨識三種不同任務。希望像這篇一樣的R語言應用對你有幫助也希望你喜歡這篇文章。
關於用R語言處理PDF檔案的常見問題
可以的,R語言中有不同套件可以從PDF檔案中提取內容。
你可以利用 pdftools 套件裡面的 pdf_text() 提取文字。
你可以利用 tabulizer 套件裡面的 extract_tables() 提取表格。
你可以利用 tesseract 套件裡面的 ocr() 提取表格。
No Comments