# PDF 转 CSV

将检测到的 PDF 文本表格转换成电子表格可打开的行。

> 在浏览器中将含文本的 PDF 表格提取为 CSV，适用于账单、发票、价目表和报告。检测依赖可读取文本的位置，可能遗漏特殊布局；扫描页需先进行 OCR。不会上传文件。

This is an interactive browser tool at https://httcup.github.io/tools/pdf-to-csv/. Files are processed on the device running that browser. Any deliberate sharing or optional network feature is described on the page. What follows is its written explanation; open the address to use it.

## Your 文件 are **processed in your browser**. No processing upload.

你选的那份 PDF，是在这台机器的内存里打开、读取的，用的是从这个地址发来的代码，CSV 也是这样写出来的。这里根本没有能做上传的东西，这一页的另一头也没有服务器可以接收。表格里写的东西，不管是账号、余额、一串收款方还是客户的报价，都留在这个标签页里。

- ✗ 不上传
- ✗ 不注册
- ✓ 断网可用
- ✓ 开源
- ✓ 文件留在你的设备上

## 怎么把 PDF 里的表格转成 CSV

1. **选一份 PDF。** 一次一份。浏览器直接从你的硬盘上把它读进来，而且是整份都读完再决定任何事，因为这份文件写的是 1.240,00 还是 1,240.00、日期是哪一种顺序，都是关于这份文件的事实，不是关于某一页的。
2. **看看它找出来的那些表。** 检查每个检测到的表格、列和可恢复的标题。跨页表格可能被连接，换行单元格会归并到其所属行。保存 CSV 前，请对照原文检查是否遗漏表格、错误合并行或出现布局错误。
3. **挑一张，或者全要。** 表不止一张的时候，表格上方那个选项决定哪些进 CSV：全部一张接一张，或者只要你来找的那一张。要是某张表带着余额，表格上方那一行会说明哪些余额比较相符、哪些行无法核对。带年份的日期写成 YYYY-MM-DD，金额是带正负号的普通数字；没有年份的日期原样保留，因为它属于哪一年只能靠猜。
4. **把 CSV 拿走。** 它按 RFC 4180 写，该加的引号都加，行尾是 CRLF，编码是带字节序标记的 UTF-8，这样 Excel 打开它的时候货币符号还是货币符号，而不会变成一串字母。所有表放在一个文件里的时候，每张表保留自己的表头行，表与表之间空一行。做出它来没有上传过任何东西。

## The longer version

[上传银行账单安全吗？](https://httcup.github.io/tools/guides/is-it-safe-to-upload-a-bank-statement/): 账单把收款人、金额和余额放在一个文件中。了解转换器得到什么，谨慎服务如何处理，以及如何分辨上传是否必要。

## Also in the box

- [收据与发票识别](https://httcup.github.io/tools/receipt-invoice-extractor/): 读取照片，检查字段和裁剪结果，准备供邮件应用使用的压缩附件和合计。
- [图片转 PDF](https://httcup.github.io/tools/images-to-pdf/): 把你的图片装进一个文档。
- [文档扫描](https://httcup.github.io/tools/document-scanner/): 把纸拍下来，回来的是一份看着像扫描的东西。
- [从视频里提取音频](https://httcup.github.io/tools/extract-audio-from-video/): 把视频拖进来，声音就取出来了。画面从不解码，也不上传任何东西。

## Questions

### PDF 里根本没有表格，它怎么找出表格来？

从文字落在哪里看出来。一页纸先在旁边有一栏小字的地方被分开；这一栏小字跟表格里的一栏分得开，是因为表格的单元格恰好落在同一条基线上，而小字只是碰巧挨在旁边。然后每一块从上往下走，在标题和空白处切成一段一段，每一段的栏位，就是好几行都认同一个单元格在那里开始或者结束的位置。栏位相同的几段会重新拼成一张表。这里没有按银行或者按表单分的模板，所以也不存在哪种版式它没学过。

### 它只能处理对账单吗？

不是。它一开始是个对账单转换工具，后来改成找出一份文件里的每一张表，因为头一份真正拿来试的对账单只有两笔交易，却有另外五张表，一个只要交易的工具在上面什么都没找到。发票、价目表、时刻表、成绩和报告，同样都是表格。对账单多出来的是余额，只要有，工具就比较可读余额之间的净变动。

### 摘要太长、一栏放不下的时候会怎么样？

它会被并回它那一行，而这正是大多数 PDF 转 CSV 的结果没法用的原因。只有一格文字、紧挨着某一行的一行，就是那一行的单元格的延续；如果它离下面那一行更近，就并到下面那一行里，一段放在数值上方、太长而折行的标签就是这么印的。带着不止一格、或者带着数字的一行，是它自己的一行。

### 余额核对能说明什么？

工具把两个可读余额之间的金额合计与余额变化比较，说明有多少次比较相符。同一道算术也用来识别可能的余额栏和金额栏，不依赖表头文字。页面会列出无法核对的行：第一个余额之前或最后一个余额之后的金额，以及含有缺失或无法读取金额的区间。借方或贷方没有用到的空白单元格按零算，无法读取的值不会按零算。余额相符不能排除互相抵消的错误，也不能验证描述和日期。使用 CSV 之前仍需对照 PDF 检查。

### 日期出错了。03/04 是 3 月 4 日，不是 4 月 3 日。

改表格上方那个选项，全部立刻重算。纯数字的日期确实有歧义，而工具是从这份文件本身来定它，不是从你所在的地区：只要这份文件里任何一处的日期有大于 12 的那一位，仅这一行就把所有日期的顺序定下来了，页面也会说明这一点。当每一个日期都落在 12 号或者更早的时候，文件里没有任何东西能把两种顺序分开，所以它会说的正是*这件事*，并且先按日在前来算，直到你另行指定。像信用卡对账单那样不带年份印出来的日期，原样保留。

### 扫描出来的 PDF 能用吗？

不能，而且它会直说，而不是丢给你一个空文件。扫描件是一张照片：那些行是像素，没有可以对齐的文字。页面接着会告诉你可以怎么办；如果是对账单，头一条建议正是大多数人会忽略的那条，几乎每一家网上银行都可以直接给你同一份对账单的 CSV、OFX 或者 QIF，那既不用转换，也比从任何一张图里读出来更准确。

### 带密码的 PDF 它能打开吗？

不能，而且这是故意的。银行会给很多对账单上锁，通常用出生日期或者账号的后几位。把这层保护取掉，跟读出一张表是两回事，所以工具会拒绝，并且指给你几条不用把文件交出去的路。最好的一条是本站的 [PDF 解锁工具](https://httcup.github.io/unlock-pdf/)：它在你自己的浏览器里把密码取下来，页面上一个字都不改写，所以文字会原样落在它当初被印上去的位置。用 Chrome 或者 Edge 输入密码打开再打印回 PDF，或者在 Mac 上用「预览」导出，也一样可以。不要用别的那些说能替你解锁的网站，那正是把这一页存在的意义所要挡住的那份文件传上去。

### 我的 PDF 会被上传到什么地方吗？

不会。文件是你自己的浏览器在你自己的硬件上读的，CSV 也是这样写出来的。这个工具没有服务器那一端，页面的 `Content-Security-Policy` 列出了它可以联系的每一个地址，其中没有一个属于本站。最简单的证明，是断开网络，照样转一份 PDF。

### CSV 开头那个奇怪的字符是什么？

那是字节序标记，是故意留的。Windows 上的 Excel 读一个没有它的 CSV 时，会按系统的旧代码页来解，于是一张以英镑或者欧元记账的表格，货币符号会变成一个字母。这个标记告诉它这是 UTF-8。所有要紧的读取程序都会悄悄跳过它；严格到会把它显示出来的解析器，会给你一个开头带着不可见字符的首列表头，这就是这个取舍的代价。

### 有大小限制吗？要钱吗？

工具里没有写死任何限制。限制是你自己的机器：文件在读的时候是放在内存里的，几百页的量，一台笔记本处理起来不会有怨言。它是免费的，不注册、不登录，也没有试用期。本站带广告，那是养活它的东西；广告拿不到任何关于你文件的内容。

### 断网能用吗？

能。把页面加载一次，然后断开网络，它照样能用。这也是证明什么都没被上传的最简单的办法：一个把你的文件发出去转换的工具，你一拔网线它就停了。

## How the privacy claim is verifiable

- **人们拿来转换的 PDF，恰恰是最经不起上传的那些。** 没有人会为一张自己能重新敲一遍的表去找转换工具。来到这里的是对账单、发票、工资条和报告：一份你付给了谁、付完还剩多少的名单，一位客户的报价，一家公司的数字。把这些交给陌生人的服务器去换一张表格，意味着他们拿到了、留下了，并且因此成了一个值得攻击的目标。这一页没有另一头：根本没有可以发过去的地方。
- **余额核对会比较净变动，也会说明核对范围。** 在 PDF 里找表格是推断，栏位边界和行的归属都可能出错。工具把两个可读余额之间的金额合计与余额变化比较，说明有多少次比较相符、哪些行无法核对。第一个余额之前、最后一个余额之后的金额，以及含有缺失或无法读取金额的区间，都不能核对。相符是有用的线索，不是每个值都正确的证明：互相抵消的错误仍可能通过。无法识别余额的表格不会显示余额核对结果。
- **表格是从纸面上看出来的，不是靠每家银行、每种表单一套模板。** 这个工具里没有银行列表，也没有版式列表，也就不存在「你的版式不在里面」。一页纸会在旁边有一栏小字的地方被分开，然后在每一块里找那些单元格对得齐的连续几行。所以它在一家没人听说过的银行的对账单上、在一份没人见过的报告上也能用，而碰上栏与栏真的挤在一起的那种表，它也真的会失败。
- **密码不由它来取，页面会告诉你去哪里取。** 带密码的 PDF 会被拒绝，而不是被打开。把一份文件的保护取掉，跟读出里面的表格是两回事，一声不响地替你做掉，是一个工具不该有的举动。页面做的是另一件事：把那些不用把文件交出去的办法列给你。头一条是本站的 [PDF 解锁工具](https://httcup.github.io/unlock-pdf/)，它在你自己的浏览器里把密码取下来，页面上什么都不改写；也可以用浏览器或者「预览」把它打印、导出成一份新的 PDF。它仍然明明白白地说，不要把这份文件交给别的任何一个说能替你解锁的网站，那正是这一页要挡住的那一次上传。
- **它读不了一页纸的照片，也不假装能读。** 扫描件是一张图：那些行是像素，文件里根本没有可以对齐成栏的文字。这一点会被如实报告，同时给出不用上传任何东西的几条路；如果那是一份对账单，头一条是大多数人都有、却想不起来的那条，银行几乎一定可以直接给你同一份对账单的 CSV。从图里认字叫 OCR，那是另一个工具，不是这一个。
- **Google 加载了什么，又没拿到什么。** 广告和统计脚本来自 Google。这两个都没有拿到关于你文件的任何东西：不是文件，不是某张表、某一行，不是某个数字、文件名或者页数。每一行读 PDF 或者写 CSV 的代码都由这个源站发出，并且列在代码仓库里。
- **打赏按钮加载了什么，又没拿到什么。** 页眉上那个「Buy me a coffee」按钮，是由 cdnjs.buymeacoffee.com 的一段脚本画出来的，字体取自 Google Fonts。它就是一个链接，仅此而已：它不上报访问，也拿不到任何关于你或者你文件的东西。你不点它就什么都不会发生，而点下去要去的是别人的网站。
- **断网也能用。** 把网络断掉，这一页上的所有功能照常。这是最简单的一个证明：一个把你的文件发出去转换的工具，这时候就停了。

**Check it yourself.** None of the above has to be taken on trust. This page is generated from the templates and config in the repository by a build script you can read and run yourself, and the result is committed to the `dist` branch — so you can diff what is served against what a build of the sources produces: https://github.com/httcup/tools

The files worth reading first are `config/site.toml` for the Content-Security-Policy，一页纸在没有任何表格线可依的情况下是怎么分成几块的，看 `src/layout.js`；表格和它们的栏位是怎么找出来的，看 `src/tables.js`；一行一行是怎么排出来的，看 `src/rows.js`；比较对账单余额的那段算术在 `src/check.js`。这几个都够不着网络，它们底下负责读 PDF 的部分也一样。
