使用空单元格抓取 PDF 表格

时间:2021-04-01 00:34:24

标签: r pdf pdftools

我正在使用 R 从 PDF 中提取数据,到目前为止一切顺利。我刚刚打开了一批新的 PDF,发现我必须弄清楚如何计算空单元格。我还没有找到一种方法来做到这一点,而且我有数百页需要阅读。

我已经包含了一些示例数据。我还没有找到在此处附加 PDF 的方法,而且这些也没有发布在网络上的任何地方。我将 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"

此时您可以看到 dfdata 之间存在差异。我试过玩一些东西,但我一直无法让任何东西工作得足够好,无法在这里发布。我尝试使用一些 if/else 逻辑来说明如果有 3 个或更多空格,则插入 NA,但这只会导致一堆错误,所以我放弃了这种方法。我的目标是让数据尽可能接近 df。

image of sample_data in pdf format

2 个答案:

答案 0 :(得分:0)

这看起来是使用 tabulizer 包的好方法。当 PDF 中有像这样格式良好的表格时,它的效果非常好。请参阅vignette。最适合您的函数是 tabulizer::extract_tables。假设 PDF 都像这样格式化,它还应该将空格识别为空值。

答案 1 :(得分:0)

尝试使用 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