之前也给大家介绍过其他的一些 OCR 方法:
Stata 版本:如何整理 2022 年县域统计年鉴:caj 文件转 pdf、文本识别与数据清洗:https://rstata.duanshu.com/#/brief/course/59fbd94072c844d985f0f4fcdbd4c40e
R 语言版本:如何整理 2022 年县域统计年鉴:caj 文件转 pdf、文本识别与数据清洗:https://rstata.duanshu.com/#/brief/course/c9cb314ab48e496da9761445ab4a28de
里面使用的方法准确性也不错,不过最近在处理《2009全国地市县财政统计资料》时感觉还不是非常好用,因此我又更换了新方法。
使用百度大脑的 OCR 接口解析的效果感觉更好,本次课我们将介绍如何在 Stata 中调用该接口从扫描文档中提取表格。
附件中的 一般预算1-4.pdf 文件是《2009全国地市县财政统计资料》书中一般预算部分的前 4 页。

这个文档是拍的照片,堪称是最难识别的了。
表格文字识别 V2 接口
该接口的介绍文档在这里:https://ai.baidu.com/ai-doc/OCR/Al1zvpylt 。
和之前介绍的情感倾向分析接口一样,该接口的使用也分为两步:
- 获取 access_token;
- 调用该接口。
创建应用
首先我们领取点免费的额度:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index

每个月是有 1000 次的免费额度。如果觉得免费额度不够用,可以点击开通付费使用。
然后需要在控制台创建一个应用 :

创建后就可以看到这个应用了:

API Key 和 Secret Key 就是我们需要在代码中调用的东西,大家需要替换成自己的。
获取 accsee_token
根据接口的文档介绍,我们需要先根据 API Key 和 Secret Key 请求获取 access_token。
access_token 的获取方法可以参考这个文档:https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu
这个接口返回的是 json 格式的数据:
library(tidyverse) library(jsonlite) library(httr)
fromJSON("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=RLNEhRcWNZRrtuFP73I4XNJj&client_secret=kskm3ApVkV310o7AHjiRB1wONyxPTMG7") -> lst
lst$access_token
|
#> [1] "24.ba839bb84ef479e05be193415c554cb5.2592000.1724941738.282335-85431137"
|
链接里面的 client_id= 后面跟的就是 API key, client_secret= 后面跟的就是 Secret Key。
调用表格文字识别接口
然后就可以使用这个 access_token 调用表格文字识别接口了。不过在此之前,我们需要把 pdf 文件处理下。
按照文档的介绍,如果我们解析的是 PDF 文件:
PDF 文件,base64 编码后进行 urlencode,要求 base64 编码和 urlencode 后大小不超过 8M,最短边至少 15px,最长边最大 4096px
为了避免中文乱码的问题,我把 一般预算1-4.pdf 重命名为 rawpdf.pdf。另外为了避免 pdf 文档过大的问题,我们还是先把 pdf 文件拆分成一页页的:
library(pdftools) dir.create("pdf") pdf_split("rawpdf.pdf", output = "pdf/pdf")
|
#> [1] "pdf/pdf_1.pdf" "pdf/pdf_2.pdf" "pdf/pdf_3.pdf" "pdf/pdf_4.pdf"
|
base64 编码后进行 urlencode 操作可以通过下面的代码实现:
pdf_file_path <- "pdf/pdf_1.pdf" binary_data <- readBin(pdf_file_path, "raw", file.info(pdf_file_path)$size)
base64_string <- URLencode(base64enc::base64encode(binary_data))
|
然后就可以调用百度接口进行 OCR 了:
POST(paste0("https://aip.baidubce.com/rest/2.0/ocr/v1/table?return_excel=true&access_token=", lst$access_token), httr::add_headers(.headers = c( 'Content-Type' = 'application/x-www-form-urlencoded' )), body = list(pdf_file = base64_string)) -> res content(res) %>% listviewer::jsonedit()
|

得到的 excel 文件也是以加密字符串的形式,使用下面的代码就可以转换了:
content(res) -> excellst
excellst$excel_file %>% base64_dec() %>% writeBin("temp.xlsx")
|
然后就可以循环处理所有的 pdf 文件了:
fs::dir_ls("pdf") -> fls dir.create("xlsx") for (f in fls) { print(f) y <- str_replace_all(f, "pdf", "xlsx") pdf_file_path <- f binary_data <- readBin(pdf_file_path, "raw", file.info(pdf_file_path)$size) base64_string <- URLencode(base64enc::base64encode(binary_data))
POST(paste0("https://aip.baidubce.com/rest/2.0/ocr/v1/table?return_excel=true&access_token=", lst$access_token), httr::add_headers(.headers = c( 'Content-Type' = 'application/x-www-form-urlencoded' )), body = list(pdf_file = base64_string)) -> res
content(res) -> excellst
excellst$excel_file %>% base64_dec() %>% writeBin(y) }
|
#> [1] "pdf/pdf_1.pdf" #> [1] "pdf/pdf_2.pdf" #> [1] "pdf/pdf_3.pdf" #> [1] "pdf/pdf_4.pdf"
|
得到的 xlsx 文件较乱,还需要再手动整理下。
合并提取结果
xlsx2 文件夹中存放的就是我手工整理后的结果。数据分为两类,一类是收入表,一类是支出表。所以我们可以合并得到两个表:
fs::dir_ls("xlsx2") -> fls
readxl::read_xlsx(fls[1]) %>% mutate_all(as.character)
|
#> # A tibble: 19 × 9 #> 地区 收入总计 本年收入 返还性收入 一般性转移支付收入 专项转移支付收入 #> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 区县合计 16205016 9030452 <NA> 4029832 2304235 #> 2 东城区 971460 729028 <NA> 98333 78198 #> 3 西城区 1795342 1468452 <NA> 84363 158129 #> 4 崇文区 540236 204271 <NA> 186131 66072 #> 5 宣武区 773193 456529 <NA> 157352 67875 #> 6 朝阳区 2148283 1883143 <NA> 131284 117391 #> 7 海淀区 2047327 1622426 <NA> 118242 219096 #> 8 石景山区 364908 179832 <NA> 123644 39254 #> 9 丰台区 841183 391719 <NA> 244972 193272 #> 10 门头沟区 405083 92666 <NA> 221442 83875 #> 11 房山区 787915 233367 <NA> 388009 164965 #> 12 通州区 794974 260607 <NA> 308153 161981 #> 13 昌平区 742206 316138 <NA> 242530 139781 #> 14 顺义区 906243 481208 <NA> 256631 119892 #> 15 大兴区 813856 230857 <NA> 297897 249759 #> 16 怀柔区 621007 164675 <NA> 276551 102307 #> 17 平谷区 563923 122765 <NA> 296794 98947 #> 18 密云县 614599 129269 <NA> 321490 129280 #> 19 延庆县 473278 63500 <NA> 276014 114161 #> # ℹ 3 more variables: 转贷财政部代理发行地方政府债券收入 <chr>, 上年结余 <chr>, #> # 调入资金 <chr>
|
lapply(fls, function(x){ readxl::read_xlsx(x) %>% mutate_all(as.character) %>% mutate(file = x, rowid = row_number()) -> tempxl tempxl %>% set_names(colnames(tempxl) %>% str_remove_all("\\r") %>% str_remove_all("\\n")) -> tempxl if ("收入总计" %in% colnames(tempxl)) { return(tempxl) } }) %>% bind_rows() -> df1
df1
|
#> # A tibble: 41 × 11 #> 地区 收入总计 本年收入 返还性收入 一般性转移支付收入 专项转移支付收入 #> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 区县合计 16205016 9030452 <NA> 4029832 2304235 #> 2 东城区 971460 729028 <NA> 98333 78198 #> 3 西城区 1795342 1468452 <NA> 84363 158129 #> 4 崇文区 540236 204271 <NA> 186131 66072 #> 5 宣武区 773193 456529 <NA> 157352 67875 #> 6 朝阳区 2148283 1883143 <NA> 131284 117391 #> 7 海淀区 2047327 1622426 <NA> 118242 219096 #> 8 石景山区 364908 179832 <NA> 123644 39254 #> 9 丰台区 841183 391719 <NA> 244972 193272 #> 10 门头沟区 405083 92666 <NA> 221442 83875 #> # ℹ 31 more rows #> # ℹ 5 more variables: 转贷财政部代理发行地方政府债券收入 <chr>, 上年结余 <chr>, #> # 调入资金 <chr>, file <chr>, rowid <int>
|
lapply(fls, function(x){ readxl::read_xlsx(x) %>% mutate_all(as.character) %>% mutate(file = x, rowid = row_number()) -> tempxl tempxl %>% set_names(colnames(tempxl) %>% str_remove_all("\\r") %>% str_remove_all("\\n")) -> tempxl if ("支出总计" %in% colnames(tempxl)) { return(tempxl) } }) %>% bind_rows() -> df2
df2
|
#> # A tibble: 43 × 11 #> 地区 支出总计 本年支出 一般性转移支付上解 专项转移支付上解 #> <chr> <chr> <chr> <chr> <chr> #> 1 区县合计 15032931 13319131 1434518 142496 #> 2 东城区 900682 639265 206548 19671 #> 3 西城区 1712184 1209101 429025 74058 #> 4 崇文区 455292 454642 <NA> 650 #> 5 宜武区 613071 502162 98213 1696 #> 6 朝阳区 2136776 1402892 643077 22717 #> 7 海淀区 1915156 1843983 55541 12632 #> 8 石景山区 337315 334417 2114 784 #> 9 丰台区 824096 822593 <NA> 1503 #> 10 门头沟区 378107 372620 <NA> 487 #> # ℹ 33 more rows #> # ℹ 6 more variables: 安排预算稳定调节基金 <chr>, 调出资金 <chr>, #> # 年终结余 <chr>, 其中净结余 <chr>, file <chr>, rowid <int>
|
这样就得到了提取结果。
点击这里跳转到 RStata 短书平台获取附件:使用 R 语言对扫描文档进行 OCR 并提取表格数据
评论