목차(Table of Contents)는 문서를 구성하는 주요 구성항목 중 하나다. 금융감독원 다트(Dart)에서 4대 회계법인 사업보고서를 다운로드 받아 보고서에서 목차를 추출해낸다.
pdf_toc()
먼저 “삼정회계법인” 감사보고서에서 목차를 추출한다. pdftools
팩키지에서 pdf_toc()
함수를 사용한다.
library(tidyverse)
library(pdftools)
kpmg_pdf <- "data/[삼정회계법인]회계법인사업보고서(2020.06.29).pdf"
kpmg_toc_list <- pdftools::pdf_toc(kpmg_pdf)
kpmg_toc <- kpmg_toc_list %>%
pluck("children") %>%
map_chr("title") %>%
str_trim() %>%
str_remove_all(" ")
kpmg_toc
[1] "사업보고서"
[2] "대표이사등의확인ㆍ서명"
[3] "I.회계법인의개황"
[4] "Ⅱ.주요사업의내용"
[5] "Ⅲ.감사보고서품질관리관련정보"
[6] "Ⅳ.인력에관한사항"
[7] "Ⅴ.손해배상준비금및손해배상공동기금등의현황"
[8] "Ⅵ.최근3개사업연도의감리결과"
[9] "Ⅶ.최근3개사업연도의소송현황"
상기 스크립트를 함수로 제작하여 나머지 다른 회사(삼일, 안진, 한영)에 대한 사업보고서 목차도 추출한다. toc_extract()
함수를 제작하여 앞서 스크립트로 제작한 코드를 최대한 재활용한다.
toc_extract <- function(annual_report) {
report_toc_list <- pdftools::pdf_toc(annual_report)
report_toc <- report_toc_list %>%
pluck("children") %>%
map_chr("title") %>%
str_trim() %>%
str_remove_all(" ")
return(report_toc)
}
toc_extract(kpmg_pdf)
[1] "사업보고서"
[2] "대표이사등의확인ㆍ서명"
[3] "I.회계법인의개황"
[4] "Ⅱ.주요사업의내용"
[5] "Ⅲ.감사보고서품질관리관련정보"
[6] "Ⅳ.인력에관한사항"
[7] "Ⅴ.손해배상준비금및손해배상공동기금등의현황"
[8] "Ⅵ.최근3개사업연도의감리결과"
[9] "Ⅶ.최근3개사업연도의소송현황"
이제 나머지 회사에 대해서도 동일한 작업을 하여 사업보고서 목차의 일관성에 대해서 살펴보자.
accounting_firms <- fs::dir_ls(path = "data/", glob = "*(2020*.pdf")
toc_firms_list <- map(accounting_firms, toc_extract)
toc_firms_list %>%
enframe() %>%
# mutate(firm_name = str_extract_all(name, "[pdf|2020]") ) %>%
mutate(firm_name = str_extract(name, pattern = "(?<=\\[).*?(?=\\])")) %>%
select(firm_name, value) %>%
unnest_auto(value) %>%
count(value)
# A tibble: 10 x 2
value n
<chr> <int>
1 I.회계법인의개황 4
2 Ⅱ.주요사업의내용 4
3 Ⅲ.감사보고서품질관리관련정보 4
4 Ⅳ.인력에관한사항 4
5 Ⅴ.손해배상준비금및손해배상공동기금등의현황 4
6 Ⅵ.최근3개사업연도의감리결과 4
7 Ⅶ.최근3개사업연도의소송현황 4
8 대표이사등의확인ㆍ서명 5
9 사업보고서 4
10 정정신고(보고) 1
pdf_toc()
pdf_info(filename) %>% pluck("pages")
방식으로 전체 PDF 파일에서 “목차”를 찾아야하지만, 목차는 문서의 앞부분에 위치하는 대체로 관계대로 첫장부터 10장까지 목차가 들어가는 페이지와 “사업보고서” 가 들어가는 장을 찾아 이를 뽑아낸다.
find_toc_page <- function(filename) {
## PDF file pages
pdf_file_pages <- pdf_info(filename) %>% pluck("pages")
## PDF 페이지별 텍스트 저장 리스트
pdf_text_pages <- list()
## PDF 페이지별 텍스트 저장: 앞쪽 10페이지만 검색
for( i in 1:10) {
pdf_pages <- pdftools::pdf_subset(filename, pages= i)
pdf_text_pages[[i]] <- pdftools::pdf_text(pdf_pages)
}
## PDF 페이지별 목차가 들어간 페이지 확인
pdf_text_pages_df <- pdf_text_pages %>%
map(str_remove_all, pattern = " ") %>%
str_match(pattern = "목차|사업보고서") %>%
as_tibble()
## PDF 목차 페이지 추출
toc_page_start_number <- which(pdf_text_pages_df$V1 == "목차")
toc_page_end_number <- which(pdf_text_pages_df$V1 == "사업보고서") %>% as.integer()
return(glue::glue("{toc_page_start_number} : {toc_page_end_number - 1}"))
}
find_toc_page_safely <- safely(find_toc_page, otherwise = NA_integer_)
find_toc_page_safely(kpmg_pdf)
$result
1 : 2
$error
NULL
이제 나머지 문서에 대해 목차가 시작되는 페이지와 목차가 끝나는 페이지를 추출한다.
toc_pages_list <- map(accounting_firms, find_toc_page_safely)
toc_pages_df <- toc_pages_list %>%
enframe() %>%
mutate(firm_name = str_extract(name, pattern = "(?<=\\[).*?(?=\\])")) %>%
select(firm_name, value) %>%
unnest_auto(value) %>%
unnest(result) %>%
separate(result, into = c("start", "end"), sep=":", convert = TRUE) %>%
group_by(firm_name, start) %>%
summarise(end = min(end)) ## 안진 정정신고 사항 반영
toc_pages_df
# A tibble: 4 x 3
# Groups: firm_name [4]
firm_name start end
<chr> <dbl> <int>
1 삼일회계법인 1 2
2 삼정회계법인 1 2
3 안진회계법인 1 2
4 한영회계법인 1 2
이제 가장 큰 제목에 달린 목차만 추출하는 것이 아니라 목차에 포함된 모든 큰제목, 작은제목에 달린 모든 텍스트를 추출하여 이와 연결된 페이지수도 함께 추출한다.
kpmg_toc_text <- pdftools::pdf_subset(kpmg_pdf, pages= 1:2) %>%
pdf_text()
kpmg_toc_list <- kpmg_toc_text %>%
str_split(pattern = "\n")
listviewer::jsonedit(kpmg_toc_list)
kpmg_finstr_toc_df <- kpmg_toc_list %>%
enframe() %>%
unnest(value) %>%
mutate(pages = str_extract(value, pattern = "[0-9]+$")) %>%
mutate(title = str_remove_all(value, "[0-9]+$")) %>%
mutate(title = str_remove_all(title, "\\.")) %>%
# mutate(title = str_extract_all(value, pattern = "^.*? \\.")) %>%
select(title, pages) %>%
unnest(title) %>%
mutate(title = str_remove_all(title, " "))
kpmg_finstr_toc_df %>%
DT::datatable()
_output.pdf
파일 생성된 결과 삭제하여 다음 작업에도 문제가 없도록 조치를 취해둠.
데이터 과학자 이광춘 저작
kwangchun.lee.7@gmail.com