用空单元格抓取 PDF 表格
Scraping PDF tables with empty Cells
我正在使用 R 从 PDF 中提取数据,到目前为止一切顺利。我刚刚打开了一批新的 PDF,发现我必须弄清楚如何计算空单元格。我还没有找到一种方法来执行此操作,而且我需要浏览数百页。
我包含了一些样本数据。我还没有找到在此处附加 PDF 的方法,而且这些文件并未在网络上的任何地方 post 编辑。我将 df
保存为 CSV,然后将其复制并粘贴到一个 word 文档中,我为此示例将其保存为 CSV。附上截图。
library(pdftools)
library(tidyverse)
# Example data
df <- data.frame("rows" = c("row1", "row2", "row3", "row4", "row5", "row6", "row7", "row8", "row9", "row10"),
"col1" = c(1, 2, "", 4, 5, 6, 7, 8, 9, 10),
"col2" = c(1, 2, 3, 4, "", "", 7, 8, 9, ""),
"col3" = c(1, 2, "", 4, 5, 6, 7, 8, 9, 10),
"col4" = c(1, 2, 3, 4, 5, 6, 7, "", 9, 10),
"col5" = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
"col6" = c(1, 2, "", "", 5, 6, 7, "", 9, 10),
"col7" = c(1, 2, 3, 4, 5, "", 7, 8, 9, 10),
"col8" = c(1, "", 3, 4, 5, 6, 7, "", 9, 10),
"col9" = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
)
# Save example data, then save as a PDF outside of R.
# write_csv(df, "sample_data.csv")
# read in the PDF
pdf_file <- pdf_text("sample_data.pdf")
data <- pdf_file[1]
data <- trimws(data)
data <- strsplit(data, "\r\n")
data <- data[[1]]
data <- str_split_fixed(data, " {2,}", 10) ## I think this is the step that needs to change
data <- data.frame(data, stringsAsFactors = FALSE)
# Print out outs of the data for reference.
> data
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1 rows col1 col2 col3 col4 col5 col6 col7 col8 col9
2 row1 1 1 1 1 1 1 1 1 1
3 row2 2 2 2 2 2 2 2 2
4 row3 3 3 3 3 3 3
5 row4 4 4 4 4 4 4 4 4
6 row5 5 5 5 5 5 5 5 5
7 row6 6 6 6 6 6 6 6
8 row7 7 7 7 7 7 7 7 7 7
9 row8 8 8 8 8 8 8
10 row9 9 9 9 9 9 9 9 9 9
11 row10 10 10 10 10 10 10 10 10
df
rows col1 col2 col3 col4 col5 col6 col7 col8 col9
1 row1 1 1 1 1 1 1 1 1 1
2 row2 2 2 2 2 2 2 2 2
3 row3 3 3 3 3 3 3
4 row4 4 4 4 4 4 4 4 4
5 row5 5 5 5 5 5 5 5 5
6 row6 6 6 6 6 6 6 6
7 row7 7 7 7 7 7 7 7 7 7
8 row8 8 8 8 8 8 8
9 row9 9 9 9 9 9 9 9 9 9
10 row10 10 10 10 10 10 10 10 10
更新:添加 dput(pdf_file)
> dput(pdf_file)
"rows col1 col2 col3 col4 col5 col6 col7 col8 col9\r\nrow1 1 1 1 1 1 1 1 1 1\r\nrow2 2 2 2 2 2 2 2 2\r\nrow3 3 3 3 3 3 3\r\nrow4 4 4 4 4 4 4 4 4\r\nrow5 5 5 5 5 5 5 5 5\r\nrow6 6 6 6 6 6 6 6\r\nrow7 7 7 7 7 7 7 7 7 7\r\nrow8 8 8 8 8 8 8\r\nrow9 9 9 9 9 9 9 9 9 9\r\nrow10 10 10 10 10 10 10 10 10\r\n"
可以看出df
和data
在这一点上是有区别的。我试过一些东西,但我无法使任何东西都能很好地工作到 post 这里。我尝试使用一些 if/else 逻辑来表示如果有 3 个或更多空格,则插入 NA,但这只会导致一堆错误,所以我放弃了这种方法。我的目标是让数据尽可能接近df。
这看起来是使用 tabulizer
包的好方案。当 PDF 中有像这样格式良好的表格时,它工作得很好。参见vignette。此处最适合您的函数是 tabulizer::extract_tables
。它还应该将空格识别为空值,假设 PDF 的格式都像这样。
尝试使用 read.fwf
作为固定宽度的文件。
data <- pdf_file[1]
data <- trimws(data)
data <- strsplit(data, "\r\n")
data <- data[[1]]
writeLines(data, 'temp.txt')
result <- read.fwf('temp.txt', c(11, 2, rep(8, 8)), skip = 1, strip.white = TRUE)
names(result) <- scan(text = readLines('temp.txt', n = 1), what = character())
result
# rows col1 col2 col3 col4 col5 col6 col7 col8 col9
#1 row1 1 1 1 1 1 1 1 1 1
#2 row2 2 2 2 2 2 2 2 NA 2
#3 row3 NA 3 NA 3 3 NA 3 3 3
#4 row4 4 4 4 4 4 NA 4 4 4
#5 row5 5 NA 5 5 5 5 5 5 5
#6 row6 6 NA 6 6 6 6 NA 6 6
#7 row7 7 7 7 7 7 7 7 7 7
#8 row8 8 8 8 NA 8 NA 8 NA 8
#9 row9 9 9 9 9 9 9 9 9 9
#10 row10 10 NA 10 10 10 10 10 10 10
我正在使用 R 从 PDF 中提取数据,到目前为止一切顺利。我刚刚打开了一批新的 PDF,发现我必须弄清楚如何计算空单元格。我还没有找到一种方法来执行此操作,而且我需要浏览数百页。
我包含了一些样本数据。我还没有找到在此处附加 PDF 的方法,而且这些文件并未在网络上的任何地方 post 编辑。我将 df
保存为 CSV,然后将其复制并粘贴到一个 word 文档中,我为此示例将其保存为 CSV。附上截图。
library(pdftools)
library(tidyverse)
# Example data
df <- data.frame("rows" = c("row1", "row2", "row3", "row4", "row5", "row6", "row7", "row8", "row9", "row10"),
"col1" = c(1, 2, "", 4, 5, 6, 7, 8, 9, 10),
"col2" = c(1, 2, 3, 4, "", "", 7, 8, 9, ""),
"col3" = c(1, 2, "", 4, 5, 6, 7, 8, 9, 10),
"col4" = c(1, 2, 3, 4, 5, 6, 7, "", 9, 10),
"col5" = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
"col6" = c(1, 2, "", "", 5, 6, 7, "", 9, 10),
"col7" = c(1, 2, 3, 4, 5, "", 7, 8, 9, 10),
"col8" = c(1, "", 3, 4, 5, 6, 7, "", 9, 10),
"col9" = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
)
# Save example data, then save as a PDF outside of R.
# write_csv(df, "sample_data.csv")
# read in the PDF
pdf_file <- pdf_text("sample_data.pdf")
data <- pdf_file[1]
data <- trimws(data)
data <- strsplit(data, "\r\n")
data <- data[[1]]
data <- str_split_fixed(data, " {2,}", 10) ## I think this is the step that needs to change
data <- data.frame(data, stringsAsFactors = FALSE)
# Print out outs of the data for reference.
> data
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1 rows col1 col2 col3 col4 col5 col6 col7 col8 col9
2 row1 1 1 1 1 1 1 1 1 1
3 row2 2 2 2 2 2 2 2 2
4 row3 3 3 3 3 3 3
5 row4 4 4 4 4 4 4 4 4
6 row5 5 5 5 5 5 5 5 5
7 row6 6 6 6 6 6 6 6
8 row7 7 7 7 7 7 7 7 7 7
9 row8 8 8 8 8 8 8
10 row9 9 9 9 9 9 9 9 9 9
11 row10 10 10 10 10 10 10 10 10
df
rows col1 col2 col3 col4 col5 col6 col7 col8 col9
1 row1 1 1 1 1 1 1 1 1 1
2 row2 2 2 2 2 2 2 2 2
3 row3 3 3 3 3 3 3
4 row4 4 4 4 4 4 4 4 4
5 row5 5 5 5 5 5 5 5 5
6 row6 6 6 6 6 6 6 6
7 row7 7 7 7 7 7 7 7 7 7
8 row8 8 8 8 8 8 8
9 row9 9 9 9 9 9 9 9 9 9
10 row10 10 10 10 10 10 10 10 10
更新:添加 dput(pdf_file)
> dput(pdf_file)
"rows col1 col2 col3 col4 col5 col6 col7 col8 col9\r\nrow1 1 1 1 1 1 1 1 1 1\r\nrow2 2 2 2 2 2 2 2 2\r\nrow3 3 3 3 3 3 3\r\nrow4 4 4 4 4 4 4 4 4\r\nrow5 5 5 5 5 5 5 5 5\r\nrow6 6 6 6 6 6 6 6\r\nrow7 7 7 7 7 7 7 7 7 7\r\nrow8 8 8 8 8 8 8\r\nrow9 9 9 9 9 9 9 9 9 9\r\nrow10 10 10 10 10 10 10 10 10\r\n"
可以看出df
和data
在这一点上是有区别的。我试过一些东西,但我无法使任何东西都能很好地工作到 post 这里。我尝试使用一些 if/else 逻辑来表示如果有 3 个或更多空格,则插入 NA,但这只会导致一堆错误,所以我放弃了这种方法。我的目标是让数据尽可能接近df。
这看起来是使用 tabulizer
包的好方案。当 PDF 中有像这样格式良好的表格时,它工作得很好。参见vignette。此处最适合您的函数是 tabulizer::extract_tables
。它还应该将空格识别为空值,假设 PDF 的格式都像这样。
尝试使用 read.fwf
作为固定宽度的文件。
data <- pdf_file[1]
data <- trimws(data)
data <- strsplit(data, "\r\n")
data <- data[[1]]
writeLines(data, 'temp.txt')
result <- read.fwf('temp.txt', c(11, 2, rep(8, 8)), skip = 1, strip.white = TRUE)
names(result) <- scan(text = readLines('temp.txt', n = 1), what = character())
result
# rows col1 col2 col3 col4 col5 col6 col7 col8 col9
#1 row1 1 1 1 1 1 1 1 1 1
#2 row2 2 2 2 2 2 2 2 NA 2
#3 row3 NA 3 NA 3 3 NA 3 3 3
#4 row4 4 4 4 4 4 NA 4 4 4
#5 row5 5 NA 5 5 5 5 5 5 5
#6 row6 6 NA 6 6 6 6 NA 6 6
#7 row7 7 7 7 7 7 7 7 7 7
#8 row8 8 8 8 NA 8 NA 8 NA 8
#9 row9 9 9 9 9 9 9 9 9 9
#10 row10 10 NA 10 10 10 10 10 10 10