V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
sillydaddy
V2EX  ›  问与答

从 pdf 文件中复制表格,顺序是错乱的, pdf 表格中的文本选择顺序是怎么定义的呢?

  •  
  •   sillydaddy · 356 天前 · 1480 次点击
    这是一个创建于 356 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这个 pdf 文件,是建设银行储蓄卡的消费明细,表格形式的。里面的文本都可以选择,但鼠标框选文本时,整个的顺序几乎完全错乱:有时选不中某一个单元,有时选中了鼠标框之外的几行。即使我按住`option`键,选中特定的一列,拷贝出的文本的顺序也不是原始文档里的顺序。

    开始我以为这是 pdf 的固有问题,可是我自己拿 macOS 上的 Number 做了一个同样的表格,然后导出为 pdf ,发现是可以有序选中文本的。不知道建行的 pdf 文件是用的什么工具生成的。

    现在有点疑惑,pdf 中的表格,在选择它里面文本时,选中的顺序是依据什么而定的呢?我模糊记得网页里的表格,有时也有这个选中顺序的问题。
    22 条回复    2023-11-30 09:14:25 +08:00
    Huahuo
        1
    Huahuo  
       356 天前
    我也有相似的需求,求教 python 有什么库可以顺序读 pdf 的表格吗?
    zhangshine
        2
    zhangshine  
       356 天前
    我对 pdf 有一点研究。PDF 其实是把字画上去,并不存在 word 里面的行或者段落的格式。所以你复制的时候的感觉和复制图片识别的文字的感觉差不多。
    xomix
        3
    xomix  
       356 天前
    pdf 实际上是一种虚拟打印指令把文字打印到虚拟纸张的指定位置。
    所以当然可以:
    a.虚拟打印一组表格文字到指定位置
    b.虚拟打印将表格绘制为图片到指定位置
    c.虚拟随机字符顺序将表格打印到指定位置

    既然你无法通过 pdf 复制,那就考虑去水印和 ocr 。
    sillydaddy
        4
    sillydaddy  
    OP
       356 天前
    @Huahuo 我现在还没到要用 python 读取那一步 🐶 。网上好像不少这种提取 pdf 表格的工具。
    @zhangshine pdf 文档是不是分 2 种,其中 1 种是可以直接选文字的,一般纯文本转 pdf 就是这种。所以感觉跟图片 ocr 还是有点区别。
    @xomix 文字是可以直接复制的,只不过顺序是乱的。ocr 也是会考虑的。不知道有 1#楼说的 python 工具可以读取 pdf 表格吗?
    xomix
        5
    xomix  
       356 天前
    @sillydaddy 你再认真看看我的回复,我想你的那个表格的输出方式是我例子里面的 c 例,也就是说你复制出来的结果就是正确结果,它就是随机乱序将文本输出至坐标位置实现的表格。
    这种时候只能 ocr
    yiyiwa
        6
    yiyiwa  
       356 天前   ❤️ 1
    python pdfplumber 这个库可以
    sillydaddy
        7
    sillydaddy  
    OP
       356 天前
    @xomix 我明白你的意思了,就是说生成 pdf 的原始文本顺序就是乱的,但每个字符映射到 pdf 的位置是正确的,所以复制会有问题?按照这个说法,框选文字时,其实复制的是原始(顺序错乱)文本的一部分,比如计算出鼠标框左上角位置对应的文本,然后复制到鼠标框右下角位置对应的文本结束?这块框选复制的逻辑没有太明白。
    zhangshine
        8
    zhangshine  
       356 天前
    @sillydaddy 算是个 plus 版本,就是再画的基础上会添加一些结构信息,这样就和 word 差不多了。
    chesha1
        9
    chesha1  
       356 天前
    我建议你直接截图给 chatgpt ,然后让他输出给你想要的格式,我打 latex 里的数学公式就是这么做的,而且准确率很高
    xomix
        10
    xomix  
       356 天前
    @sillydaddy pdf 你没做过深入理解吧。
    我简单说一下,方便让你明白,很多东西是大致这样不是严格的原理。

    pdf 是把 图像 或 文字 按照固定格式渲染的技术,有点儿像 htrml 。

    当他输出一段文字时候,可以对每一个文字设置其定位属性,但是这段文字本身是连续的文本。因此你可以选择这段文字,但当你选择了这段文字时,能够复制的是文本段的实际顺序而不是展示顺序,所以看起来是正常顺序,但是复制后是乱序。
    sillydaddy
        11
    sillydaddy  
    OP
       356 天前
    @zhangshine 明白了
    @chesha1 gpt4 吧,我还冇有呢

    @xomix 举个具体的例子,如果 pdf 打印输出的结果是"0123456789",而生成这个打印结果的原始文本是"5678901234",也就是说,「文本索引」->「打印位置」的映射关系是 0->5, 1->6, 2->7, 3->8, 4->9, 5->0, 6->1, 7->2, 8->3, 9->4 。那么当我在 pdf 中,用鼠标从"0123456789"当中的"0"字符,也就是打印位置是 0 的地方,开始往后框选三个字符,框选的位置分别是 0,1,2 ,那么从根据「文本索引」->「打印位置」的关系,反映射回去,得出实际被选中的字符是"567"对吗?

    如果是(像你说的)直接建立的是「文本字符」->「打印位置」的映射,也就是说"0"->0, "1"->1, ... "9"->9 ,那么鼠标框选,根据位置反映射到字符时,就不会出现问题了。

    你能根据这个例子解释一下吗?因为#10 楼的逻辑我没太理解。
    xomix
        12
    xomix  
       356 天前
    @sillydaddy
    以下是一段伪代码,肯定不是 pdf ,只是方便你理解。

    打印代码段如下
    ···
    文本段开始
    [绝对位置 0 ,3]1
    [绝对位置 0 ,0]2
    [绝对位置 0 ,9]3
    [绝对位置 0 ,5]4
    [绝对位置 0 ,7]5
    [绝对位置 0 ,6]6
    [绝对位置 0 ,1]7
    [绝对位置 0 ,2]8
    [绝对位置 0 ,4]9
    [绝对位置 0 ,8]0
    文本段结束
    ···

    你看到的展示将会是
    2781946503

    因为是组文本,当你选择时候,这些文字会都被你选中,但是你复制时会复制无格式信息的文本段内容
    1234567890
    sillydaddy
        13
    sillydaddy  
    OP
       356 天前
    @xomix 你#12 楼说到的这一层面我是理解的。我不理解的是,如果#12 楼的例子中,只选中 10 个字符中的 3 个字符,会发生什么?怎么根据鼠标框选的位置,反推得到框选选中的字符。想了解这个,是因为根据它可以推理出在 pdf 中选择表格里面的一部分内容时,会发生什么。
    不过大概的意思我知道了,谢谢你耐心的解释。
    Huahuo
        14
    Huahuo  
       356 天前
    @yiyiwa 多谢
    @sillydaddy python pdfplumber 这个好用
    kumakichi
        15
    kumakichi  
       356 天前
    一个猜想,
    截图 丢给 gpt 生成 csv 格式的?
    然后复制回来?
    013231
        16
    013231  
       356 天前   ❤️ 1
    findsomeone
        17
    findsomeone  
       356 天前
    除了 py 那个库,如果你用 iphone 的话,截图放相册再识别复制也可以~~
    xomix
        18
    xomix  
       356 天前
    @sillydaddy 不同的 api 处理方式不一样,这个没有一概而论的。不过大致都是选择三个文本,至于是选择原始数据三个文本还是选择实际现实数据三个文本,最后按照原始文本顺序排列。
    xomix
        19
    xomix  
       356 天前
    @sillydaddy 这还是理想情况,如果说一开始 pdf 就不想让你复制,生成的时候可能用多组随机顺序文本按照指定位置输出,你复制的文本就更乱了。
    sillydaddy
        20
    sillydaddy  
    OP
       356 天前
    @yiyiwa
    @Huahuo
    @013231
    感谢。看了下 pdfplumber 这个库不错,还可以可视化 debug 。camelot 也不错,也可以可视化 debug ,文档也挺详细。
    HiyaKuso
        21
    HiyaKuso  
       356 天前
    我之前用的 pdfplumber 和 PyMuPDF ,最终用了 pdfplumber ,不过后来新项目用了 PyMuPDF ,因为更新 1.23.0 版本后代码写起来比较简单,准确度还行,又可以转为 DataFrame 使用。
    代码大概是这样:
    tables = page.find_tables()
    df = tables[0].to_pandas()
    df.to_excel('example.xlsx', index=False)
    sillydaddy
        22
    sillydaddy  
    OP
       355 天前
    @HiyaKuso 是啊,用起来真简单
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1880 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 16:32 · PVG 00:32 · LAX 08:32 · JFK 11:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.