Skip to content

Commit 06e3c11

Browse files
authored
Merge pull request theseawolves#10 from linsite/master
PhantomJS 将死,将会被谷歌Headless Chrome替代,可以关注下。
2 parents f70e2ed + 85b545b commit 06e3c11

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

source/_posts/itext_using_learning.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
title: 使用iText提取PDF文档中特定信息
3+
date: 2018-3-4 17:19:00
4+
tags:
5+
- 数据提取
6+
- Java
7+
author: Lin
8+
---
9+
## 1 简介
10+
[itextpdf](https://github.com/itext/itextpdf)是一款基于Java/.Net语言的专业的PDF处理工具,大多数场景下用于网站上在线生成PDF文档。网上可以找到很多PDF数据提取工具,但大多数只能简单的把PDF文档中的文字转换为纯文本,原有的PDF文档的排版,文档结构没有办法保留。工作中遇到一些场景,需要把PDF文档中的特定部分然后调用google翻译,翻译其中的一部分。现有的工具都没有办法满足需求。所以决定研究下itextpdf的源码,进行开发,提取想要的数据。
11+
12+
## 2 基本的例子
13+
在网上随便百度一下,找到的例子是这样的:利用itextpdf中的PdfTextExtractor对PDF内容的文本进行了提取。
14+
<!--more-->
15+
```
16+
package ulin.pdf_parser;
17+
18+
import java.io.FileInputStream;
19+
import java.io.FileNotFoundException;
20+
import java.io.FileOutputStream;
21+
import java.io.IOException;
22+
23+
24+
import com.itextpdf.text.pdf.PdfReader;
25+
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
26+
27+
/**
28+
* Hello world!
29+
*
30+
*/
31+
public class App
32+
{
33+
public static void main( String[] args ) throws FileNotFoundException, IOException
34+
{
35+
36+
String pdf = "test.pdf";
37+
PdfReader pdfReader = new PdfReader(new FileInputStream(pdf));
38+
//FileOutputStream outfs = new FileOutputStream(pdf + ".txt");
39+
40+
41+
System.out.println("number of pages:" + pdfReader.getNumberOfPages())
42+
int pageNumber = pdfReader.getNumberOfPages();
43+
44+
for(int i = 1; i <= pageNumber; i++)
45+
{
46+
//System.out.println(PdfTextExtractor.getTextFromPage(pdfReader, i).replace("\t", " "));
47+
System.out.println("Page:" + i);
48+
String content = PdfTextExtractor.getTextFromPage(pdfReader, i);
49+
//System.out.println(content.replace("\t", " "));
50+
51+
byte[] pageContent = content.replace("\t", " ").getBytes();
52+
//outfs.write(pageContent);
53+
//outfs.close();
54+
}
55+
pdfReader.close();
56+
}
57+
}
58+
59+
```
60+
## 3 想要提取的文档类型
61+
想要提取的文档如下:
62+
1 目录
63+
1.1 概述
64+
1.1.1 aaaa
65+
* desc:
66+
* * this is a test document!
67+
```
68+
#!/bin/bash
69+
some code
70+
```
71+
* summery
72+
比如要提取1.1.1标题和desc,及对应的代码(**各部分对应的字体是不一样的**,如果字体是一样的,这个文档的排版就太差了)。进行翻译时,code部分内容是不翻译的,如果按照基本的提取方式,把所有的文档提取出来,那么代码的正常的文字就混在了一起,没有办法调用Google翻译了。
73+
## 4 思路
74+
为弄清楚要怎么提取这样文本特征,研究了下,基本例子中内容的提取流程。
75+
PdfTextExtractor.getTextFromPage(pdfReader, i)函数的定义如下:
76+
```
77+
public static String getTextFromPage(PdfReader reader, int pageNumber) throws IOException{
78+
return getTextFromPage(reader, pageNumber, new LocationTextExtractionStrategy());
79+
}
80+
```
81+
函数传入了一个LocationTextExtractionStrategy对象。
82+
通过高度跟踪调用,最终找到是通过LocationTextExtractionStrategy对象的renderText函数完成对文本的渲染(提取)。
83+
```
84+
public void renderText(TextRenderInfo renderInfo) {
85+
LineSegment segment = renderInfo.getBaseline();
86+
if (renderInfo.getRise() != 0){
87+
Matrix riseOffsetTransform = new Matrix(0, -renderInfo.getRise());
88+
segment = segment.transformBy(riseOffsetTransform);
89+
}
90+
//DocumentFont df = renderInfo.getFont(); 此行代码用来调试,显示字体
91+
TextChunk tc = new TextChunk(renderInfo.getText(), tclStrat.createLocation(renderInfo, segment));
92+
locationalResult.add(tc);
93+
}
94+
```
95+
刚好PdfTextExtractor也提供了getTextFromPage的另外一种形式:
96+
```
97+
String content = PdfTextExtractor.getTextFromPage(pdfReader, i, new MyExtractor());
98+
```
99+
那么就可以通过自定义一个与LocationTextExtractionStrategy相似的类来实现基于字体实现对文本提取了。把LocationTextExtractionStrategy类的代码拷贝过来,然后修改renderText方法就可以了。
100+
## 5 解决
101+
通过自定义的MyExtractor类,调试代码,发现需要提取的文本的字体名称,然后根据这些名称,对输出的文本进行过滤,就能得到想要的数据了。如下是我调试时输出的信息,输出的字体名称为:ABCDEE+Cambria-Bold,Cambria-Bold才是字体名称,前面的ABCDEF是文档自己生成的,结构相似的文档输出的结果中,"+"号前的字符串是不同的,主要依靠后面的字体名称来区分。
102+
```
103+
font:ABCDEE+Cambria-Bold
104+
font:ABCDEE+Cambria-Bold
105+
font:ABCDEE+Cambria-Bold
106+
font:ABCDEE+Cambria-Bold
107+
font:ABCDEE+Cambria-Bold
108+
font:ABCDEE+Cambria-Bold
109+
font:ABCDEE+Cambria-Bold
110+
font:ABCDEE+Cambria-Bold
111+
font:ABCDEE+Cambria-Bold
112+
font:SymbolMT
113+
font:ABCDEE+Cambria
114+
font:ABCDEE+Cambria
115+
font:ABCDEE+Cambria
116+
font:ABCDEE+Cambria
117+
font:ABCDEE+Cambria
118+
font:ABCDEE+Cambria
119+
font:ABCDEE+Cambria
120+
```
121+
同一个字体的信息是连续的,但是1个字符接1个字符的样式渲染的,所以真正提取,还要加一些处理,识别当前字体发生变化的位置,把标记信息附加进去,就能把格式信息保留下来了。
122+
## 6 总结
123+
同样是基于开源项目来解决手头的问题。虽然解决过程有点波折,但还是挺有成就感的。

source/_posts/phantomjs-sso-login.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title:PhantomJS SSO单点登录,加Cookie异常情况处理
3+
date: 2017-12-13 15:36:44
4+
tags:
5+
- 网络爬虫
6+
- PhantomJS
7+
- Python
8+
author: Lin
9+
---
10+
11+
# Intro
12+
## PhantomJS加Cookie的流程
13+
* 加载一个页面
14+
一般会选择目的页面。
15+
```
16+
driver.get(url)
17+
```
18+
* 加载Cookie
19+
Cookie一般以分号分割。按照规范RFC2109规定,一个Cookie条目,有name,value,domain,secure,expires,pathcomment其中name与value是成对出现的,也是可以直接看到的属性。
20+
domain限定了cookie的作用范围,请求的域名不在此范围内时,浏览器不会发送Cookie。secure是一个可选项,没有值,用来标识此Cookie是否经过HTTPS发送。expires指定的是过期时间,path是Cookie的有效路径。comment是可选项,用来向客户端传递人眼可读信息。
21+
单点登录时,可能会跳转到登录页面,登录页面如果与当前页面不共域的时候,使用目的域是无法登录的。
22+
按照这些要求添加好Cookie。调用
23+
```
24+
driver.add_cookie(cookie)
25+
```
26+
<!--more-->
27+
一般页面在加载时,会有一些Cookie已经存在在driver中了,需要把这些cookie删除掉。
28+
```
29+
driver.delete_all_cookies()
30+
```
31+
之后再加载传入的登录后的Cookie。
32+
* 刷新页面
33+
有人用driver.refresh()来刷新页面,如果是SSO,加载Cookie时,跳转到别的页面了,这里的refresh是不能保证成功登录的。
34+
还是使用原来的url,
35+
driver.get(url)
36+
37+
# SSO登录失败
38+
## 原因
39+
前面说到,Cookie条目中的domain属性用来限制Cookie的作用范围。原来的做法是,以目的URL的域名作为所有Cookie的域属性,SSO情况下
40+
,页面跳转到了登录域,目标域是new.a.com的话,登录域是login.a.com,而PhantomJS要求,添加Cookie时,所添加的Cookie与当前页面的域一致,或者是共用一个父域名,没有进行处理的话,PhantomJS拒绝添加这个Cookie。Cookie添加失败,自然不能登录。
41+
## 解决方法
42+
加载第一个页面后,进行一次判断,如果是SSO(登录页与目标页不在一个域内),取两者自底向上的第一个公共父域,作为加Cookie时的domain属性,这样就可以保证,既能加载Cookie,又能成功登录。

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy