呵呵,只为自己玩,哈哈。
技术难度:
1)快速高效的抓取记录,并去重,和以后的增量抓取。
2)因为口碑网的联系方式是图片的,如何批量的完成OCR的转换
本文只是一个实验,不建议使用在项目当中,如下是部分代码。
涉及的开源代码:
AspriseOCR
资源包,把crawler4j所有jar包放在你的应用目录中。
- Berkeley DB Java Edition 4.0.71 or higher
- fastutil 5.1.5
- DSI Utilities 1.0.10 or higher
- Apache HttpClient 4.0.1
- Apache Log4j 1.2.15
- Apache Commons Logging 1.1.1
- Apache Commons Codec 1.4
如上的JAR包都必须包括在你的项目lib当中,否则会出错。
第一步,抓取口碑网店铺信息。
如下是抓取的部分代码:
主程序入口:Controller.java
package com.aragon.crawdata;
import org.junit.Test;
import edu.uci.ics.crawler4j.crawler.CrawlController;
public class Controller {
private static String CRAWSITE = "http://beijing.koubei.com/";
@Test
public void test(){
CrawlController controller;
try {
controller = new CrawlController("/data/crawl/root");
controller.addSeed(CRAWSITE);
controller.start(MyCrawler.class, 3);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
抓取主程序 MyCrawler.java
package com.aragon.crawdata;
import java.util.ArrayList;
import java.util.regex.Pattern;
import edu.uci.ics.crawler4j.crawler.Page;
import edu.uci.ics.crawler4j.crawler.WebCrawler;
import edu.uci.ics.crawler4j.url.WebURL;
public class MyCrawler extends WebCrawler {
private static String CRAWSITE = "http://beijing.koubei.com/store/";
Pattern filters = Pattern.compile(".(detail--storeId-*)$");
SaveInDb savein = new SaveInDb();
public MyCrawler() {
}
public boolean shouldVisit(WebURL url) {
String href = url.getURL().toLowerCase();
if (filters.matcher(href).matches()) {
return false;
}
if (href.startsWith(CRAWSITE)) {
return true;
}
return false;
}
public void visit(Page page) {
int docid = page.getWebURL().getDocid();
String url = page.getWebURL().getURL();
System.out.println("Url:" + url);
Template4Koubei koubei = new Template4Koubei();
try {
CrawDataModel model = koubei.translationData(page.getHTML());
if (model != null) {
//保存在数据库当中。
savein
.update("insert into info(type,name,address,tel1,tel2,tel3,otherinfo,othertype,ownername) value ('"
+ model.getType()
+ "','"
+ model.getName()
+ "','"
+ model.getAddress()
+ "','"
+ model.getTel1()
+ "','"
+ model.getTel2()
+ "','"
+ model.getTel3()
+ "','"
+ model.getOtherInfo()
+ "','"
+ model.getOtherType()
+ "','"
+ model.getOwnerName() + "')");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String text = page.getText();
ArrayList<WebURL> links = page.getURLs();
}
}
真正解析口碑网店铺的类Template4Koubei.java
package com.aragon.crawdata;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.tags.Span;
import org.htmlparser.tags.TableColumn;
import org.htmlparser.util.NodeList;
public class Template4Koubei {
private static String NAME_TAG = "title-wrap yk-fix-float";// 名称
private static String TYPE_TAG = "detail-info-item";// 类型
private static String ADDRESS_TAG = "info yk-fix-float";// 地址
private static String TEL_TAG = "detail-info-item";// 电话,图像
private static String MOB_TAG = "detail-info-item";
private static String DETAIL_TAG = "detail-intro";
private static String OTHERINFO_TAG = "detail-info-item";
public CrawDataModel translationData(String webHtml) throws Exception {
CrawDataModel model = new CrawDataModel();
Object[] name = findCrawDataByCol(webHtml, NAME_TAG);
if (name != null && name[0] != null) {
model.setName(StringUtils.deleteWhitespace(name[0].toString()));
Object[] type = findCrawDataByCol(webHtml, TYPE_TAG);
if (type != null) {
model.setType(StringUtils.deleteWhitespace(type[0].toString()));
}
Object[] tel = findCrawDataByImageFilter(webHtml, TEL_TAG);
if (tel != null) {
for (int i = 0; i < tel.length; i++) {
if (i == 0) {
model.setTel1(StringUtils.deleteWhitespace(tel[0]
.toString()));
}
if (i == 1) {
model.setTel2(StringUtils.deleteWhitespace(tel[1]
.toString()));
}
if (i == 2) {
model.setTel3(StringUtils.deleteWhitespace(tel[2]
.toString()));
}
}
}
Object[] otherType = findCrawDataByCol(webHtml, OTHERINFO_TAG);
String otherTypeString = "";
if (otherType != null) {
for (int i = 0; i < otherType.length; i++) {
if (i < 3) {
otherTypeString += StringUtils
.deleteWhitespace(otherType[i].toString());
}
}
model.setOtherType(otherTypeString);
}
Object[] address = findCrawDataByCol(webHtml, ADDRESS_TAG);
if (address != null) {
model.setAddress(StringUtils.deleteWhitespace(address[0]
.toString()));
}
Object[] detail = findCrawDataByCol(webHtml, DETAIL_TAG);
if (detail != null) {
model.setOtherInfo(StringUtils.deleteWhitespace(detail[0]
.toString()));
}
} else {
return null;
}
// check address
if (model.getAddress() != null) {
if (model.getAddress().indexOf("电话") > 0) {
model.setOtherType(model.getAddress().substring(
model.getAddress().indexOf("电话")));
model.setAddress(model.getAddress().substring(0,
model.getAddress().indexOf("电话")));
}
}
return model;
}
public Object[] findCrawDataByCol(String webHtml, String Tag)
throws Exception {
String name = "";
List<String> resultTextList = new ArrayList<String>();
Parser parser = new Parser();
parser.setInputHTML(webHtml);
NodeFilter filter = new HasAttributeFilter("class", Tag);
/* NodeFilter filter 就是要解析的过滤器,实现有好多种,我采用的属性过滤,其他more api */
NodeList nodeList = parser.extractAllNodesThatMatch(filter);
/*
* extractAllNodesThatAre(class)已经不被推荐使用,在1.6版本中,我感到更加体形了灵活性.更好的适用了自定义的tag
*/
if (nodeList == null)
return null;
if (nodeList.size() == 0)
return null;
// System.out.println("start ============== ,size = "
// + nodeList.size());
Node[] nodes = nodeList.toNodeArray();
String line = "";
for (int i = 0; i < nodes.length; i++) {
Node node = nodes[i]; /* 得到所以符合的节点,类型化做对应的标签类 */
if (node instanceof Span) {
Span spanTag = (Span) node;
line = spanTag.toPlainTextString();
} else if (node instanceof TableColumn) {
TableColumn tableTag = (TableColumn) node;
line = tableTag.toPlainTextString();
} else if (node instanceof Div) {
Div divTag = (Div) node;
line = divTag.toPlainTextString();
}
if (StringUtil.isTrimEmpty(line)) {
continue;
} else {
resultTextList.add(line);
}
}
return resultTextList.toArray();
// return name;
}
public Object[] findCrawDataByImageFilter(String webHtml, String Tag)
throws Exception {
List<String> resultTextList = new ArrayList<String>();
Parser parser = new Parser();
parser.setInputHTML(webHtml);
NodeFilter filter = new NodeClassFilter(ImageTag.class);
/* NodeFilter filter 就是要解析的过滤器,实现有好多种,我采用的属性过滤,其他more api */
NodeList nodeList = parser.extractAllNodesThatMatch(filter);
/*
* extractAllNodesThatAre(class)已经不被推荐使用,在1.6版本中,我感到更加体形了灵活性.更好的适用了自定义的tag
*/
if (nodeList == null)
return null;
if (nodeList.size() == 0)
return null;
// System.out.println("start ============== ,size = "
// + nodeList.size());
Node[] nodes = nodeList.toNodeArray();
String line = "";
for (int i = 0; i < nodes.length; i++) {
Node node = nodes[i]; /* 得到所以符合的节点,类型化做对应的标签类 */
if (node.getParent().getText().indexOf(Tag) > 0) {
ImageTag imageTag = (ImageTag) node;
line = imageTag.getImageURL();
}
if (StringUtil.isTrimEmpty(line)) {
continue;
} else {
resultTextList.add(line);
}
}
return resultTextList.toArray();
// return name;
}
}
Model对象:CrawDataModel.java
package com.aragon.crawdata;
import java.io.Serializable;
public class CrawDataModel implements Serializable{
private Integer id;
private String type;
private String name;
private String address;
private String tel1;
private String tel2;
private String tel3;
private String ownerName;
private String otherInfo;
private String otherType;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTel1() {
return tel1;
}
public void setTel1(String tel1) {
this.tel1 = tel1;
}
public String getTel2() {
return tel2;
}
public void setTel2(String tel2) {
this.tel2 = tel2;
}
public String getTel3() {
return tel3;
}
public void setTel3(String tel3) {
this.tel3 = tel3;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public String getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String otherInfo) {
this.otherInfo = otherInfo;
}
public String getOtherType() {
return otherType;
}
public void setOtherType(String otherType) {
this.otherType = otherType;
}
}
哈哈,如上的步骤就可以把口碑网的店铺信息抓入你的数据库当中,我在恶劣的2M宽带条件下,一个小时抓了2000多条信息,当然了,没有加入去重的功能。
第二步:把电话,手机信息转换成指定的数字号码
从口碑网抓取的电话,手机信息都是图片信息,如何把他转换成数字号码,我们使用AspriseOCR。网上破解的方法很多。大家可以google一下。
如下是他的TEST实验。因为我的应用代码太多,所以就粘一个Test,从技术上没有问题。
package com.aragon.crawdata;
import java.io.File;
/**
*
* 本程序实现功能:给出一个图片的具体网络地址,把该图片的进行解析,解析后把图片内容以字符串形式进行返回
*/
public class RecognisePicture {
/**
*
* create date:2009-5-22 author:Administrator
*
*
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
recognise("http://count.koubei.com/showphone/showphone.php?f=jpg&w=96&h=10&bc=255,255,255&fc=0,0,0&fs=10&fn=arial&phone=MTI5NDU5ODg0Mw%3D%3D%23OQ532L8m6okoAzY6".replaceAll("&", "&"));
}
/**
*
* 解析指定网络地址的图片信息 create date:2009-5-22 author:Administrator
*
*
*
* @param fromUrl
*
* @return
*/
public static String recognise(String fromUrl) {
String result = "";
// 下载图片文件到本地磁盘
File file = DownLoadWithUrl.downLoadFile(fromUrl);
if (file != null) {
// 解析下载到本地磁盘文件
result = ParseJPEG_withOCR.getRecogniseStr(file);
// 删除下载到本地磁盘的文件
DownLoadWithUrl.delFile(file);
}
System.out.println("输出的电话号码是:"+result);
return result;
}
}
如下是实验结果:
输出的电话号码是:01O 51402688
哈哈,这样一来。是不是能减少很多MM的工作量呀。enjoy it!