java解析 CHM实战
需求:java 解析 chm 文件,并将内容插入数据库和 redis.
Java 解析 chm 文件,网上除了 github 上有个家伙只言片语了一下,没有啥资料参考,包括 chm4j 这东西,没啥介绍,本着服务大众的精神,整理了下流程, 时间仓促,错误之处在所难免,
望指正.
第一步:下载 chm4j.jar 以及依赖 http://sourceforge.net/projects/chm4j/
第二步:新建 java 工程,建一个解析 ParseChm 类,建一个解析测试类,类似:
ParseChm 类:
//下面的包,请导入chm4j.jar,并且把chm4j.dll拷贝到jre的lib目录内,linux或mac请拷贝libchm4j.so即 //可,因为chm4j.jar依赖于c++
package cn.lswe.baseframe.utils;
import java.io.File;
import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;
import org.chm4j.*;
import cn.lswe.baseframe.validator.Conf;
public class ParseChm {
public static void main(String... args) {
try {
ChmFile cFile = new ChmFile(Conf.ChmSOurce); String dir = Conf.dir;
ChmEntry.Attribute attributes = ChmEntry.Attribute.ALL; ChmEntry[] entries = cFile.entries(attributes);
for (ChmEntry entry : entries) { listChmEntry(dir, entry, attributes);
}
} catch (IOException ex) {
System.out.println("Error : " + ex.getMessage());
}
}
/**
* Extracts recursively the sub entries of the specified ChmEntry into the
* specified output directory according to the specified attributes.
* @param output The output directory.
* @param entry
* @param attributes
* @throws java.io.IOException If an I/O error occurs.
*/
private static void listChmEntry(String output, ChmEntry entry, ChmEntry.Attribute attributes) throws IOException {
printEntry(entry);
String er=GuidHelper.CreateGuid().toString(); File dest = new File(output, entry.getPath());
if (entry.hasAttribute(ChmEntry.Attribute.DIRECTORY)) { if (!dest.isDirectory()) {
if (!dest.mkdirs()) {
throw new IOException("failed to create directory : " + dest);
}
}
for (ChmEntry e : entry.entries(attributes)) { listChmEntry(output, e, attributes);
}
} else {
InputStream in = null; OutputStream out = null; try {
in = entry.getInputStream();
out = new FileOutputStream(dest); int bufferSize = 1024;
byte[] data = new byte[bufferSize]; int nbRead;
while ((nbRead = in.read(data)) > 0) { out.write(data, 0, nbRead); out.flush();
}
} catch (IOException ex) { System.out.println(ex.getMessage());
} finally {
try {
if (out != null) { out.close();
}
} finally {
if (in != null) { in.close();
}
}
}
}
}
/**
* Display the specified entry.
* @param entry
*/
private static void printEntry(ChmEntry entry) {
StringBuilder sb = new StringBuilder("Extract entry " + entry + "("); boolean first = true;
for (ChmEntry.Attribute attribute : entry.getAttributes()) { if (first) {
first = false; } else {
sb.append(", ");
}
sb.append(attribute);
}
sb.append(")");
System.out.println(sb.toString());
}
}
这就得到了若干中转 html 文件(两万多个),注意,chm 文件的格式相当复杂,决定了这样的处
理方法,事实上我接下来的 word,freemind 文件,统统都这样处理的.
测试类:
package cn.lswe.baseframe.spider; import java.io.FileNotFoundException; import java.util.LinkedList;
import java.util.List;
import cn.lswe.baseframe.utils.FileHelper; import cn.lswe.baseframe.validator.Conf; import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
public class ParseDisease implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
public void process(Page page) { List<String>links=new LinkedList<String>(); links.add(Conf.diseaseDataSource);
page.addTargetRequests(links);
List<String> tdList = page.getHtml().xpath("table").xpath("td").all(); //这里利用了webmagic爬虫框架,可以参照这个链接做:
// http://webmagic.io/docs/zh/
int j=0; int k=0;
for(int i=0;i<tdList.size();i++){
//在这里,可以筛选,处理你的内容了
//插入jedis,插入数据库都ok
j=i+1; k=i+2;
String td1=tdList.get(i);
String td2=tdList.get(i);//第二列要拆分为一个数组,它是第一列的下一级分类
String td3=tdList.get(i);//如果第一列是字母,第三列和第二列一一对应,如果第一列是汉 字,第三列和第二列第二行开始一一对应,其编码是”B”+第一行第三列+本行第三列
}
System.out.println(tdList);
}
@Override
public Site getSite() { return site;
}
@SuppressWarnings("deprecation") public static void testSpider() {
// Conf.diseaseDataSource 嗅探的起点,比如www.ask.com,为了速度,请把所有资源文件部署
//到localhost
Spider.create(new ParseDisease())
.addUrl(Conf.diseaseDataSource)
.pipeline(new ConsolePipeline()).thread(5).run();
//开启5个线程抓取
}
}.
调用方法:
@ResponseBody
@RequestMapping("/test/spider")
public void spider()
{
//OschinaBlogPageProcesser.testSpider();
ParseChm.testSpider();
}