【问题标题】:Convert PDF with columns to text将带有列的 PDF 转换为文本
【发布时间】:2015-06-01 21:27:06
【问题描述】:

在 Unix 或 Windows 中,我想将此 dictionary 转换为 Python dictionary。我复制了PDF 字典的内容并将它们放在.rtf 文件中,打算用Python 来read 它们。但是,它给出了类似的东西:

A /e/ 名词 ABO 系统的人类血型,含有 A 抗原(注意:A 型的人可以向同一组或 AB 组的人献血,并且可以接受 A型或O型患者的血液。)
AA
腹胀 /????b????dɒmn(ə)l ds ????tenʃ(ə)n/ 名词 abdo-
男性因气体或液体而被拉伸
一个
腹胀
AA abbr 戒酒无名氏

它基本上将 PDF 中的列压缩成一个奇怪的错误。如何将 PDF 转换为文本以便尊重列?换句话说,期望的输出是:

A /e/ 名词 ABO 系统的人类血型,含有 A 抗原(注意:A 型的人可以向同一组或 AB 组的人献血,并且可以接受 A型或O型患者的血液。)
AA abbr 戒酒无名氏

...等等

【问题讨论】:

  • 我或许可以提供帮助,但我无法下载您链接的 PDF。每次 3-5 MByte 后下载中止(完整文件似乎在 14 MByte 左右)。请您提供一个较小的 PDF 样本,只有 1 页吗?

标签: python pdf


【解决方案1】:

您基本上有两种选择来获取文本:

  1. 按原样直接从每个页面提取文本。
  2. 沿列空间将每一页一分为二,分别提取每一半的文本

对于第一个选项,我建议您先尝试pdftotext,但使用参数-layout。 (还有其他工具,例如 TET,来自 PDFlib 人员的文本提取工具包,如果 pdftotext 不够好,您可以尝试。)

对于使用 Ghostscript 和其他工具遵循第二个选项的道路,您可能需要查看我对以下问题的回答:


pdftotext -layout

您可以使用命令行工具pdftotext 进行尝试。您必须决定它是否“足够好”以达到您的目的。

以下命令仅从第 8 页(双列布局的第一页)中提取文本并将其打印到<stdout>

$ pdftotext -f 8 -l 8 -layout                                         \
           Dictionary+of+Medical+Terms+4th+Ed.-+\(Malestrom\).pdf - \
 | head -n 30

结果:

Medicine.fm Page 1 Thursday, November 20, 2003 4:26 PM

                                                          A
 A /e/ noun a human blood type of the ABO                abdominal distension /bdɒmn(ə)l ds
 A                                                        abdominal distension
 system, containing the A antigen (NOTE: Some-              tenʃ(ə)n/ noun a condition in which the abdo-
 one with type A can donate to people of the              men is stretched because of gas or fluid
 same group or of the AB group, and can receive           abdominal pain /b dɒmn(ə)l pen/ noun
                                                          abdominal pain
 blood from people with type A or type O.)                pain in the abdomen caused by indigestion or
 AA
 AA abbr Alcoholics Anonymous                             more serious disorders
 A & E /e ənd  i
                     /, A & E department /e ənd           abdominal viscera /bdɒmn(ə)l    vsərə/
 A & E                                                    abdominal viscera
    i
      d pɑ
           tmənt/ noun same as accident and
                                                          plural noun the organs which are contained in
 emergency department                                     the abdomen, e.g. the stomach, liver and intes-
 A & E medicine /e ənd     i
                              med(ə)sn/
 A & E medicine
                                                          tines
                                                          abdominal wall /b dɒmn(ə)l wɔ
                                                                                        l/ noun
                                                          abdominal wall
 noun the medical procedures used in A & E de-                                                            
 partments                                                muscular tissue which surrounds the abdomen
                                                          abdomino- /bdɒmnəυ/ prefix referring to
                                                          abdomino-

注意-layout的使用!没有它,提取的文本将如下所示:

Medicine.fm 第 1 页 2003 年 11 月 20 日星期四下午 4:26 一种 A /e/ 名词 ABO 的人类血型 系统,包含 A 抗原(注意:SomeA

A 型的人可以捐赠给 同组或AB组,可接收 A型或O型人的血液。) AA abbr 酗酒者匿名 A & E /e ənd i /, A & E 部门 /e ənd 一世 d pɑ tmənt/ 名词与事故和 急诊科 A & E 医学 /e ənd i med(ə)sn/ 名词 A & E deAA 中使用的医疗程序

A&E 急诊医学 隔间 AB /e bi /名词人类血型的 ABO 系统,包含 A 和 B 抗原 乙

我注意到该文件在第 8 页使用但未嵌入字体 CourierHelveticaHelvetica-BoldTimes-RomanTimes-Italic

这不会对文本提取造成问题,因为所有这些字体都使用/WinAnsiEncoding

但是,还有其他字体作为子集嵌入。这些字体确实使用/Custom 编码,但它们不提供/ToUnicode 表。可靠的文本提取(将字形名称反向翻译为字符名称)需要此表。

我说的可以看这张表:

$ pdffonts -f 8 -l 8 Dictionary+of+Medical+Terms+4th+Ed.-+\(Malestrom\).pdf 
 name                           type        encoding      emb sub uni object ID
 ------------------------------ ----------- ------------- --- --- --- ---------
 Helvetica-Bold                 Type 1      WinAnsi       no  no  no    1505  0
 Courier                        Type 1      WinAnsi       no  no  no    1507  0
 Helvetica                      Type 1      WinAnsi       no  no  no    1497  0
 MOEKLA+Times-PhoneticIPA       Type 1C     Custom        yes yes yes   1509  0
 Times-Roman                    Type 1      WinAnsi       no  no  no    1506  0
 Times-Italic                   Type 1      WinAnsi       no  no  no    1499  0
 IGFBAL+EuropeanPi-Three        Type 1C     Custom        yes yes no    1502  0

碰巧我最近为一个新的 GitHub 项目手工编码了 5 个不同的 PDF 文件,并带有注释的源代码。这 5 个文件展示了正确的/ToUnicode 表对于作为子集嵌入的每种字体的重要性。可以在这里找到它们,以及解释更多细节的自述文件

【讨论】:

  • 在我的终端上运行以下命令给了我 pdftotext 命令不退出的错误 $ pdftotext -f 8 -l 8 -layout \ Dictionary+of+Medical+Terms+4th+Ed.-+ (Malestrom).pdf - \ | head -n 30 这很奇怪,因为我已经安装了 pdftotext,并且在 python 脚本中运行它时工作正常。但我也有两列的 pdf 文件(例如科学文章),并希望将它们全部作为一列阅读。你能帮我解决这个问题吗?提前谢谢你。
  • @HR123r:您无法使用 pdftotext 阅读 2-col PDF 文档“全部作为一列”。您还将获得两列中的文本,并且您必须使用其他文本工具对其进行按摩以再次分隔列(例如 cut)。
【解决方案2】:

您可以使用pdfminer 从 PDF 中提取文本:http://www.unixuser.org/~euske/python/pdfminer/

【讨论】:

    【解决方案3】:

    PDF 文档几乎没有文档结构的概念。 PDF 内容流包括在页面上放置字形的说明,但放置顺序不必与文档结构相对应。

    您没有说明您使用的是什么平台。如果您使用的是 OS X,您也许可以使用 PDFKit 来实现您想要的。

    【讨论】:

      【解决方案4】:
      I have solved this issue with R. May be it has small bugs which can be corrected to your needs.
      
          countWhiteSpaces <-
        function(x)
          attr(gregexpr("(?<=[^ ])[ ]+(?=[^ ])", x, perl = TRUE)[[1]], "match.length")
      
      getColumnCount <- function(path){
        library(pdftools)
        x <- pdf_text(path)
        write.csv(x,"data.txt")
        res <- readLines("data.txt")
      
        yy <- c()
        for(i in seq(1:length(res))){
          y = as.list(countWhiteSpaces(res[i]))
          yy[i]= length(y[y > 1])
      
        }
        li = list(colsInPdf= 1+as.integer(names(sort(table(yy), decreasing=T)[1])),lines = res)
        return(li)
      }
      
      result <- getColumnCount("pathToPdfFile.pdf")
      lines <- result$lines
      sizeOfText <- length(lines)
      colsInPdf <- result$colsInPdf
      df <- data.frame(matrix(ncol = result$colsInPdf, nrow = 0))
      df <- df[1,]
      
      
      for(i in seq(1:sizeOfText)){
        line = lines[i]
        y = as.list(countWhiteSpaces(line))
        yy = length(y[y > 1])
        t = as.list(strsplit(line, '\\s{2,}')[[1]])
        if(t[1]==""){t=t[-1]}
        t = unlist(t)
        if(length(t)==colsInPdf){
          df <- rbind(df, t)
        }
      
      }
      df = paste(df,collapse = " ")
      
      Clean_String <- function(string){
        # Lowercase
        temp <- tolower(string)
        # Remove everything that is not a number or letter (may want to keep more 
        # stuff in your actual analyses). 
        temp <- stringr::str_replace_all(temp,"[^a-zA-Z\\s]", " ")
        # Shrink down to just one white space
        temp <- stringr::str_replace_all(temp,"[\\s]+", " ")
        # Split it
        temp <- stringr::str_split(temp, " ")[[1]]
        temp <- gsub(",", " ",temp)
        # Get rid of trailing "" if necessary
        indexes <- which(temp == "")
        if(length(indexes) > 0){
          temp <- temp[-indexes]
        } 
        return(temp)
      }
      
      toString(Clean_String(df))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-09-24
        • 1970-01-01
        • 2019-01-02
        • 1970-01-01
        • 2014-01-03
        • 2021-11-26
        相关资源
        最近更新 更多