[wordpress搬家]nutch的二三事 — 数据清洗

本文介绍了在Nutch抓取数据并存入MySQL后,如何通过远程jdbc连接数据库,使用jsoup库来清洗和提取HTML内容中的结构化数据。针对HTML的半结构化特性,jsoup提供了类似CSS查询的语法进行高效提取。同时,文章提到了处理MySQL中文乱码及blob类型字段中文字符串正确读取的方法,附带了一个抓取AppChina游戏APP数据的简单示例代码。
摘要由CSDN通过智能技术生成

[2013.12.27]

好吧……这篇文章与nutch有关系也没有关系。

在nutch把数据放入数据库以后,因为是非结构化的,所以我们还需要从中提取我们需要的数据,这时就需要清洗数据了。

自己写一个小程序是很有用的,Ade这里用的方法是远程jdbc链接数据库,获取webpage中的content字段,然后使用jsoup提取数据。

选用jsoup的原因是content字段中保存了整个html,是半结构化的,需要足够的鲁棒性来从中按结构提取数据,传统的DOM方法肯定会崩溃。

本来想用Java自带的XPath,但就是因为无法将html转换为DOM而放弃了。Jsoup很好用,虽然不支持xpath,但是支持类似cssQuery的语法,几乎与XPath相同,在这里学习10分钟足以。另外jsoup还提供一个在线的实验,把自己要分析的html放上去,然后调试一下jsoup select很快就能定位出想要的数据了。这个与firebugs中找xpath很像。

还需要注意的一点是mysql链接的中文问题,这个网上有很多解决方案,这里就不一一熬述了。

另外,由于content字段是blob类型的,如果直接getString的化中文是乱码的,所以这里需要将blob按照byte获取,并new String(bytes, charset)这样做。由于blob的length是long,如果直接blob.getbytes是填充不到bytes数组中去的(会截断),所以这里需要先写入byteArrayOutputStream,再生成byte数组。

好了,下面给出代码,是一个抓取appchina上游戏app数据并分析的例子,为了追求速度,程序写的粗糙,大概理解其中的含义即可。


package me.yxyz.washer;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public class Main {
	public static final String driver = "com.mysql.jdbc.Driver";
	public static final String url = "jdbc:mysql://115.28.xxx.xxx:3306/nutch_appchina?useUnicode=true&characterEncoding=UTF-8";
	public static final String user = "root";
	public static final String password = "xxx";

	static HashMap<String, String> map = new HashMap<String, String>();

	private static BufferedWriter bw = null;
//	private static FileWriter fw = null;

	public static void main(
			String args[]) {

		File f = new File("/Users/ade/Desktop/result.csv");

		try {
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "GB2312" ));
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		Connection conn = null;
		try {
			Class.forName(driver);

			conn = DriverManager.getConnection(url,
					user,
					password);

			if (!conn.isClosed())
				System.out.println("Succeeded connecting to the Database!");

			Statement statement = conn.createStatement();
			String sql = "select id,content from webpage ";

			ResultSet rs = statement.executeQuery(sql);
			while (rs.next()) {
				String id = rs.getString("id");
				Blob b = rs.getBlob("content");
				String content;
				try {
					content = blobToString(b);
					map.put(id,
							content);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			System.out.println("done");
			System.out.println("start to parsing");
			Iterator<String> iter = map.keySet().iterator();
			while (iter.hasNext()) {
				String k = iter.next();
				String html = map.get(k);
				System.out.println(k + "------->");
				// System.out.println( html );
				if (html != null)
					dealData(html);
			}

			rs.close();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

			if( bw != null )
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}

	}

	private static String blobToString(
			Blob b) throws SQLException, IOException {
		InputStream is = b.getBinaryStream();

		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int readLen = 0;
		while ((readLen = is.read(buffer)) != -1) {
			bao.write(buffer,
					0,
					readLen);
		}

		byte[] byteArr = bao.toByteArray();
		String s = new String(byteArr, "utf8");

		return s;
	}

	private static void dealData(
			String html) {
		if (html == null)
			return;
		Document doc = Jsoup.parse(html);

		// learn at: http://jsoup.org/cookbook/extracting-data/selector-syntax
		// try at : try.jsoup.org
		// name (cn and en)
		Elements es = doc.select("ul.app_list > li> div.app_section>p.app_name");
		// rate
		Elements es2 = doc.select("ul.app_list > li> div.app_section>span");
		// download count
		Elements es3 = doc.select("ul.app_list > li> div.app_section>p.app_info>span:eq(0)");
		// date
		Elements es4 = doc.select("ul.app_list > li> div.app_section>p.app_info>span:eq(1)");
		// desc
		Elements es5 = doc.select("ul.app_list > li> div.app_section>p[class~=desc]");

		for (int i = 0; i < es2.size(); i++) {
			AppInfo info = new AppInfo();
			info.setCnName(es.get(i * 2).text());
			info.setEnName(es.get(i * 2 + 1).text());
			if( es2.size() > i )
				info.setRate(es2.get(i).text());
			if( es3.size() > i )
				info.setDownloadCount(es3.get(i).text());
			if( es4.size() > i )
				info.setDate(es4.get(i).text());
			if( es5.size() > i )
				info.setDescription(es5.get(i).text());
			System.out.println(info);
			if( bw !=null ){
				try {
					bw.append( info.toString() + "\n" );
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值