如何将PDF文件中的行提取到csv文件中?
我想从这里得到美国所有大学的列表,并将其放入CSV文件中。然后,我将CSV文件导入SQL server(以便可以轻松运行查询) 我尝试了几个在线pdf-to-csv转换器和基于Java的pdf-to-csv教程。什么都没用。我今天为此花了6-8个小时,但失败了。导入csv时,我的csv文件乱七八糟,数据库中有很多空值。 我甚至试着搜索一个DHS api,它可以给我这个信息,但没有找到 有没有人能帮我把这些学院提取出来,就像pdf文件中显示的那样如何将PDF文件中的行提取到csv文件中?,pdf,Pdf,我想从这里得到美国所有大学的列表,并将其放入CSV文件中。然后,我将CSV文件导入SQL server(以便可以轻松运行查询) 我尝试了几个在线pdf-to-csv转换器和基于Java的pdf-to-csv教程。什么都没用。我今天为此花了6-8个小时,但失败了。导入csv时,我的csv文件乱七八糟,数据库中有很多空值。 我甚至试着搜索一个DHS api,它可以给我这个信息,但没有找到 有没有人能帮我把这些学院提取出来,就像pdf文件中显示的那样 PS:你可以看到所有的大学也在使用它。但是,您必须
PS:你可以看到所有的大学也在使用它。但是,您必须手动滚动以提取所有结果。这将花费太长时间,并且数据将不会以pdf文件中给出的格式提供。我曾经有一个Ruby项目做过这种工作。 我使用了gem pdf/reader,它甚至可以正常工作,但我建议不要使用这种方法,pdf的内容没有字段开始和停止的标记,而是必须测量每段文本的位置(每个字段有许多段),这里是第一个字段的示例
"I
NUL ETX
Am"
NUL ETX
School
NUL ETX
Inc.
并将其与您必须通过实验找到的边界进行比较,如“如果位置距离左边缘>2.54cm,距离左边缘<5.78cm”等。。
它冗长乏味,容易出错
最简单的解决方案是通过手动滚动、选择并将内容复制到编辑器中,然后删除额外的头和尾,或者使用一些类似于mechanize的web scraping gem,然后将此文本转换为CSV,以某种方式读取整个文本内容。最后一部分很简单,因为结构是固定的
"I Am" School
118 Siskiyou Avenue
Mount Shasta , CA , 96067
5309266263 <--end of first record
424 Aviation
13230 SW 132 Ave.
Miami , FL , 33186
7862424848 <--end of second record
“我是”学校
西斯基尤大街118号
加利福尼亚州沙斯塔山,96067
5309266263正如在对该问题的评论中所说
考虑到相当直接的页面内容流样式,应该可以使用不太复杂的自定义文本提取器提取数据
详细内容:
页面内容流样式
常规表格条目内容是逐条绘制的,每个条目按读取顺序逐字段绘制。因此,在浏览内容流时,我们不必尝试重新安排内容以建立顺序。这使得这项任务相当容易
因此,主要工作是忽略非条目,即第一页上的标题、指示新第一个字母开始位置的栏以及页码
我们是通过
- 忽略图形和非黑色文本,它们负责标题和首字母栏李>
- 不接受不以“学校名称”列中的数据开头的条目,该列负责只存在于“校园名称”列中的页码
(其他方法也可以这样做,例如忽略底部页面区域中的所有内容来处理页码。)
现在我们只需将条目拆分为字段
文档结构也有帮助,因为它是一个非常统一的文档,表列在每页上的位置和维度都相同。所以我们只需要在固定的x值下进行解析
只有一个障碍:在某些条目中,原子文本块包含不同列的内容。例如,有时F和M列的内容被绘制为类似“YN”的单个字符串,并且通过字符间距引入光学距离
所以我们必须一个字符一个字符地处理文本块,而不是作为一个整体
一个示例实现
我在这里使用Java和PDF库iText(当前版本5.5.7开发快照)。这并不意味着不能使用不同的设置,这只是我最习惯的设置
作为分隔符,我使用制表符,因为其他可能的候选字符也作为文本的一部分出现,我不想处理转义
这是为处理上述内容而引入的自定义RenderListener
类:
public class CertifiedSchoolListExtractionStrategy implements RenderListener
{
public CertifiedSchoolListExtractionStrategy(Appendable data, Appendable nonData)
{
this.data = data;
this.nonData = nonData;
}
//
// RenderListener implementation
//
@Override
public void beginTextBlock() { }
@Override
public void endTextBlock() { }
@Override
public void renderImage(ImageRenderInfo renderInfo) { }
@Override
public void renderText(TextRenderInfo renderInfo)
{
try
{
Vector startPoint = renderInfo.getBaseline().getStartPoint();
BaseColor fillColor = renderInfo.getFillColor();
if (fillColor instanceof GrayColor && ((GrayColor)fillColor).getGray() == 0)
{
if (debug)
data.append(String.format("%4d\t%3.3f %3.3f\t%s\n", chunk, startPoint.get(I1), startPoint.get(I2), renderInfo.getText()));
for (TextRenderInfo info : renderInfo.getCharacterRenderInfos())
{
renderCharacter(info);
}
}
else
{
if (debug)
nonData.append(String.format("%4d\t%3.3f %3.3f\t%s\n", chunk, startPoint.get(I1), startPoint.get(I2), renderInfo.getText()));
if (currentField > -1)
finishEntry();
entryBuilder.append(renderInfo.getText());
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
chunk++;
}
}
public void renderCharacter(TextRenderInfo renderInfo) throws IOException
{
Vector startPoint = renderInfo.getBaseline().getStartPoint();
float x = startPoint.get(I1);
if (currentField > -1)
{
if (isInCurrentField(x))
{
entryBuilder.append(renderInfo.getText());
return;
}
if (isInNextField(x))
{
currentField++;
entryBuilder.append('\t').append(renderInfo.getText());
return;
}
finishEntry();
}
if (isInNextField(x))
{
finishEntry();
currentField = 0;
}
entryBuilder.append(renderInfo.getText());
}
public void close() throws IOException
{
finishEntry();
}
boolean isInCurrentField(float x)
{
if (currentField == -1)
return false;
if (x < fieldstarts[currentField])
return false;
if (currentField == fieldstarts.length - 1)
return true;
return x <= fieldstarts[currentField + 1];
}
boolean isInNextField(float x)
{
if (currentField == fieldstarts.length - 1)
return false;
if (x < fieldstarts[currentField + 1])
return false;
if (currentField == fieldstarts.length - 2)
return true;
return x <= fieldstarts[currentField + 2];
}
void finishEntry() throws IOException
{
if (entryBuilder.length() > 0)
{
if (currentField == fieldstarts.length - 1)
{
data.append(entryBuilder).append('\n');
}
else
{
nonData.append(entryBuilder).append('\n');
}
entryBuilder.setLength(0);
}
currentField = -1;
}
//
// hidden members
//
final Appendable data, nonData;
boolean debug = false;
int chunk = 0;
int currentField = -1;
StringBuilder entryBuilder = new StringBuilder();
final int[] fieldstarts = {20, 254, 404, 415, 431, 508, 534};
}
选择大小为1的字体TT2
9.72 0 0 9.72 20.16 687.36 Tm
设置文本矩阵以将文本插入坐标移动到20.16687.36,然后按9.72的因子缩放所有内容
0 g
选择灰度填充颜色黑色
0 Tc
0 Tw
选择附加字符和字间距为0
(SCHOOL)Tj
在这里画“学校”
选择字体TT1
3.4082 0 TD
将文本插入点沿x方向移动3.4082
<0003>Tj
选择字体,移动文本插入点,并绘制字符串“NAME”,然后间隔17887.4个文本单位,然后绘制“CAMPUS”
向左移动56.782,向下移动1.3086,即到达第一条入口线的起点
("I)Tj
/TT3 1 Tf
.6528 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(Am")Tj
/TT3 1 Tf
1.7783 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(School)Tj
/TT3 1 Tf
2.6919 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Inc.)-16894.2("I)]TJ
/TT3 1 Tf
18.9997 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(Am")Tj
/TT3 1 Tf
1.7783 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(School)Tj
/TT3 1 Tf
2.6919 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Inc.)-8239.9(Y)-1018.9(N)-576.7(Mount)]TJ
/TT3 1 Tf
15.189 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Shasta)-2423.3(CA)-2443.7(41789)]TJ
再次上移到条目的主线
[(Y)-1018.9(N)-576.7(Westlake)]TJ
因此,我们可以按原样消化文本,无需排序(内容可以以完全不同的方式排序)
但我们也看到,没有明显的列起点和终点。因此,要将文本与列关联,我们必须计算每个字符的位置,并将它们与外部给定的列起始位置进行比较
库支持的解析
PDF库通常提供一些机制来帮助解析此类内容流
这有两种基本架构,一个库可以解析内容流
- 作为一个整体,并将其作为定位文本块或
- 或者使用侦听器模式分段转发单个定位的文本块
前一个变体一开始似乎更容易处理,但可能需要大量资源(我遇到过多MB的内容流),而第二个变体似乎更难处理,但内存需求更小
我使用的库(iText)遵循后一种方法,但您的问题也可以使用前一种方法之后的库来解决
RenderListener
是一个侦听器
<0003>Tj
/TT2 1 Tf
.2261 0 TD
[(NAME)-17887.4(CAMPUS)]TJ
/TT1 1 Tf
24.1809 0 TD
<0003>Tj
/TT2 1 Tf
.2261 0 TD
[(NAME)-8986.6(F)-923.7(M)-459.3(CITY)-6349.9(ST)-1390.2(CAMPUS)]TJ
/TT1 1 Tf
28.5147 0 TD
<0003>Tj
/TT2 1 Tf
.2261 0 TD
(ID)Tj
/TT4 1 Tf
-56.782 -1.3086 TD
("I)Tj
/TT3 1 Tf
.6528 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(Am")Tj
/TT3 1 Tf
1.7783 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(School)Tj
/TT3 1 Tf
2.6919 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Inc.)-16894.2("I)]TJ
/TT3 1 Tf
18.9997 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(Am")Tj
/TT3 1 Tf
1.7783 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(School)Tj
/TT3 1 Tf
2.6919 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Inc.)-8239.9(Y)-1018.9(N)-576.7(Mount)]TJ
/TT3 1 Tf
15.189 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
[(Shasta)-2423.3(CA)-2443.7(41789)]TJ
[(Inc.)-7228.7(A)]TJ
/TT3 1 Tf
9.26 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(F)Tj
/TT3 1 Tf
.4595 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(International)Tj
/TT3 1 Tf
5.2886 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(of)Tj
/TT3 1 Tf
.8325 0 TD
<0003>Tj
/TT4 1 Tf
.2261 0 TD
(Westlake)Tj
/TT3 1 Tf
3.7739 0 TD
<0003>Tj
/TT4 1 Tf
-11.8374 -1.3086 TD
(Village)Tj
15.4938 1.3086 TD
[(Y)-1018.9(N)-576.7(Westlake)]TJ
$ pdftotext -layout <input.pdf> <output.txt>
$ head -30 test.txt
Updated
SEVP Certified Schools September 16, 2015
SCHOOL NAME CAMPUS NAME F M CITY ST CAMPUS ID
"I Am" School Inc. "I Am" School Inc. Y N Mount Shasta CA 41789
424 Aviation 424 Aviation N Y Miami FL 103705
‐ A ‐
A F International School of Languages Inc. A F International College Y N Los Angeles CA 9538
A F International School of Languages Inc. A F International of Westlake Y N Westlake Village CA 57589
Village
A. T. Still University of Health Sciences Kirksville Coll of Osteopathic Y N Kirksville MO 3606
Medicine
Aaron School Aaron School ‐ 30th Street Y N New York NY 159091
Aaron School Aaron School Y N New York NY 114558
ABC Beauty Academy, INC. ABC Beauty Academy, INC. N Y Flushing NY 95879
ABC Beauty Academy, LLC ABC Beauty Academy N Y Garland TX 50677
Abcott Institute Abcott Institute N Y Southfield MI 197890
Aberdeen Catholic School System Roncalli Primary Y N Aberdeen SD 180510
Aberdeen Catholic School System Roncalli Y N Aberdeen SD 21405
Aberdeen Catholic School System Roncalli Elementary Y N Aberdeen SD 180511
Aberdeen School District 6‐1 Aberdeen Central High School Y N Aberdeen SD 36568
Abiding Savior Lutheran School Abiding Savior Lutheran School Y N Lake Forest CA 9920
Abilene Christian Schools Abilene Christian Schools Y N Abilene TX 8973
Abilene Christian University Abilene Christian University Y N Abilene TX 7498
Abington Friends School Abington Friends School Y N Jenkintown PA 20191
Above It All, Inc Benchmark Flight /Hawaii Flight N Y Kailua‐Kona HI 24353
Academy
Abraham Baldwin Agricultural College Tifton Campus Y N Tifton GA 6931
Abraham Joshua Heschel School Abraham Joshua Heschel School Y N New York NY 106824
ABT Jacqueline Kennedy Onassis School ABT Jacqueline Kennedy Onassis Y Y New York NY 52401
userVariables = school, campus;
{ start = IsNumeric(Substring(Line(0),112,115));
school = ""; campus = "";
{ start = 1;
maxCount = 2;
school = Concat(school, " ", Trim(Substring(Line(0),1,52)));
campus = Concat(campus, " ", Trim(Substring(Line(0),53,82)));
}
output = Concat(Trim(school), "|", Trim(campus));
}