京橋のバイオインフォマティシャンの日常

データ分析、コマンドライン、プログラミングについての技術資料・自己アップデート・悩み事などをまとめています。最近、ディープラーニング関連のR言語の資料をまとめるべく注力してます。

R言語で、pdf2textを実行する

科学論文などは、通常、PDF形式のファイルで保管される。

このフォーマットは主に印刷用に設計されているため、検索や索引付けにはあまり適さない。

rOpenSci/pdftoolsパッケージを使えば、 PDFファイルから、テキストやメタデータを抽出できる。

今回、RでPDFファイルを読み込み、テキスト生成とかをやってみる。

#関連ページ
browseURL("https://github.com/ropensci/pdftools")
browseURL("https://cran.r-project.org/web/packages/pdftools/index.html")

#pdftoolsのインストール
install.packages("pdftools")

#事前にセットアップ For MacOSX
system("brew install poppler")
system("brew install wget")

#パッケージ・ロード
library(pdftools)

Getting started (1) 英語論文での事例

最も重要な関数は pdf_text という関数で、 pdfのページ数と同じ長さの文字ベクトルを返す。

ベクトル内の各文字列は、 そのページ内のプレーンテキストである。

#ダウンロード
download.file("http://arxiv.org/pdf/1403.2805.pdf", "1403.2805.pdf", mode = "wget")

#Check
#dir(pattern = ".pdf")

#変換
txt <- pdftools::pdf_text("1403.2805.pdf")

#1ページ目のテキスト
cat(txt[1])

#2ページ目のテキスト
cat(txt[2])

#簡単な前処理: 空白と改行記号を消す
#1ページ目を抜き出す
a <- txt[1]
for(n in 1:10){
a <- gsub("  ", " ", a)
a <- gsub("\n", " ", a)
}

#出力
a
#[1] " The jsonlite Package: A Practical and Consistent Mapping Between 
#JSON Data and R Objects Jeroen Ooms arXiv:1403.2805v1 [stat.CO] 12 Mar 
#2014 UCLA Department of Statistics Abstract A naive realization of JSON data 
#in R maps JSON arrays to an unnamed list, and JSON objects to a named list. 
#However, in practice a list is an awkward, inefficient type to store and manipulate
#data. Most statistical applications work with (homogeneous) vectors, matrices 
#or data frames. Therefore JSON packages in R typically define certain special 
#cases of JSON structures which map to simpler R types. Currently there
#.........

#書き出し・表示
readr::write_excel_csv(as.data.frame(a), "a.csv", col_names = F)
browseURL("./a.csv")

Getting started (2) 日本語資料での事例

#ダウンロード
download.file("http://www.tkd-pbl.com/files/mcmurry_seikagakuhannoukikou_2nd.pdf", "seikagaku_2nd.pdf", mode = "wget")

#変換
txtJpn <- pdftools::pdf_text("seikagaku_2nd.pdf")
txtJpn

#簡単な前処理: 空白と改行記号を消す
b <- txtJpn[1]
for(n in 1:10){
b <- gsub(" ", "", b)
b <- gsub("\n", " ", b)
b <- gsub(".", ".", b)
b <- gsub(",", ",", b)
}

b
#[1] "生化学と有機化学を相互につなぐ教科書マクマリー生化学反応機構―
#ケミカルバイオロジーによる理解―第2版J.McMurry,T.Begley著長野哲雄監
#訳A5判・井上英史,浦野泰照,小島宏建,496ページ鈴木紀行,平野智也訳
#定価:本体5400円+税東京化学同人「生命活動は化学反応によって成り学
#の世界として,頭に詰め込まれてい学問体系の相互的な理解が進むように工立
#っている.だから有機化学を学ぶことく.一方で生化学の教科書では,生体内夫
#されており,深い学びへと誘うアクは,生命を理解することにつながるのでひ
#き起こされる物質変換の様子が連続ティブラーニングが自然と達成できる教だ」私が
#....

#書き出し・表示
readr::write_excel_csv(as.data.frame(b), "b.csv", col_names = F)
browseURL("./b.csv")

PDF error: Invalid Font Weightというエラーが出てるが、特に問題なさそうである。

他のユーティリティについて

加えて、このパッケージには、PDFファイルから他のデータを抽出するためのユーティリティがいくつかある。

pdf_toc関数は、目次(ToC)を取得・表示する。 つまり、PDFリーダーが通常、左側のメニューパネルに表示するセクションヘッダーを意味する。

JSON形式だと、うまく表示されるらしい。

# 目次の取得
toc <- pdftools::pdf_toc("1403.2805.pdf")

toc
#$title
#[1] ""
#
#$children
#$children[[1]]
#$children[[1]]$title
#[1] "1 Introduction"
#
#$children[[1]]$children
#$children[[1]]$children[[1]]
#$children[[1]]$children[[1]]$title
#[1] "1.1 Parsing and type safety"
#...

#JSON形式での表示
jsonlite::toJSON(toc, auto_unbox = TRUE, pretty = TRUE)
#{
#  "title": "",
#  "children": [
#    {
#      "title": "1 Introduction",
#      "children": [
#        {
#          "title": "1.1 Parsing and type safety",
#          "children": []
#        },
#        {
#          "title": "1.2 Reference implementation: the jsonlite package",
#          "children": []
#        },
#        {
#          "title": "1.3 Class-based versus type-based encoding",
#          "children": []
#        },
#....

また、その他の機能では、 フォントや添付ファイル、作者や作成日、タグなどのメタデータに関する情報を取得できる。

# Author, version, etc
info <- pdftools::pdf_info("1403.2805.pdf")
info
#$version
#[1] "1.4"
#$pages
#[1] 29
#$encrypted
#[1] FALSE
#$linearized
#[1] FALSE
#$keys
#$keys$Producer
#[1] "dvips + GPL Ghostscript GIT PRERELEASE 9.08"
#......

# Table with fonts
fonts <- pdftools::pdf_fonts("1403.2805.pdf")
fonts
#              name   type embedded                            file
#1      Times-Roman  type1    FALSE /System/Library/Fonts/Times.ttc
#2    UWJIZQ+CMTT10 type1c     TRUE                                
#3     OYDUEZ+CMR10 type1c     TRUE                                
#4    EBLJKS+CMTI10 type1c     TRUE                                
#5    APBPVY+CMBX12 type1c     TRUE                                
#6     FBFBNT+CMTI9 type1c     TRUE                                
#......

#Table with attachments
files <- pdftools::pdf_attachments("1403.2805.pdf")
files
#list()

#Table with data
Dat <- pdftools::pdf_data("1403.2805.pdf")
head(Dat[[1]])
#  width height   x   y space      text
#1    27     15  92 115  TRUE       The
#2    71     14 124 117  TRUE  jsonlite
#3    59     15 200 115  TRUE  Package:
#4    11     15 266 115  TRUE         A
#5    61     15 284 115  TRUE Practical
#6    25     15 350 115  TRUE       and

また、PDFファイルをビットマップ配列にレンダリングする機能もある*1

R上では、pdf_render_page関数を使って、PDFの1ページをビットマップにレンダリングできる。

# pdf から bitmap へのレンダー
bitmap <- pdftools::pdf_render_page("1403.2805.pdf", page = 1)

# bitmap 画像の保存
png::writePNG(bitmap, "page.png", dpi = 100)
jpeg::writeJPEG(bitmap, "page.jpg", quality = 0.7, bg = "white")
#install.packages("webp"); library(webp)
#webp::write_webp(bitmap, "page.webp")

#ファイルを開く
browseURL("./page.png")
browseURL("./page.jpg")

まとめ

一通り、pdftoolsを使ってみた。

結構、便利そうに思うけど。

*1:popplerライブラリの事前インストールが必要