日期:2014-05-17  浏览次数:20682 次

[java]使用htmlparser获取豆瓣日记

内容很简单就是使用htmlparser这个工具库来进行一些html的简单解析

?

测试页面:http://www.douban.com/people/maybedekky/notes

?

拦截的规则也是很简单的?

  • 豆瓣每页的url形式是http://www.douban.com/people/maybedekky/notes?start= 每页10页的话 第一页就是=0 第二页=10 以此类推
  • 文章页面的url是http://www.douban.com/note/数字/ 的形式也很好获取到
  • 然后就是文章内容 标题直接获取<title></title>就可以了 而内容则是被div class="note" id="link-report“包裹的?

按照以上规则匹配就可以了

代码如下:

package org.cc.douban;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
/**
 * 
 * @author fair_jm
 * http://fair-jm.iteye.com/
 *
 */
public class MayBeTest {

	public static final int PAGE_SIZE = 10;

	/**
	 * 如果输出的标题和内容是乱序的很正常 因为用了多线程在输出的时候也没加锁 
	 * 可以放到数据库 或者生成文本 方法中并没有共享变量所以不会产生太大的问题
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		List<String> articel_urls = getUrl(
				"http://www.douban.com/people/maybedekky/notes", 11);
		Executor exec = Executors.newCachedThreadPool();
		final CountDownLatch cdl = new CountDownLatch(articel_urls.size());
		for (String url : articel_urls) {
			final String u = url;
			exec.execute(new Runnable() {

				@Override
				public void run() {
					getArticle(u);
					cdl.countDown();
				}
			});
		}

		cdl.await();

		System.out.println("任务完成");
	}

	/**
	 * 得到文字(这里直接输出)
	 * @param url 文章的url
	 */
	public static void getArticle(String url) {
		try {
			Parser parser = new Parser(url);
			parser.setEncoding("UTF-8");
			NodeFilter articleFilter = new NodeFilter() {
				public boolean accept(Node node) {
					if (node.getText().startsWith(
							"div class=\"note\" id=\"link-report\"")) {
						return true;
					} else {
						return false;
					}
				}
			};

			NodeFilter titleFilter = new NodeFilter() {
				public boolean accept(Node node) {
					if (node.getText().startsWith("title")) {
						return true;
					} else {
						return false;
					}
				}
			};

			OrFilter or1 = new OrFilter(new NodeFilter[] { articleFilter,
					titleFilter });
			NodeList list = parser.extractAllNodesThatMatch(or1);
			for (int i = 0; i < list.size(); i++) {
				Node tag = list.elementAt(i);
				System.out.println(tag.getText() + "\n"
						+ tag.getChildren().asString().trim() + "\n");

			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

    /**
     * 
     * @param url 要获取日志的地址
     * @param pageCount 多少页
     * @return 返回对应的url列表
     */
	public static List<String> getUrl(String url, int pageCount) {
		List<String> urls = new ArrayList<String>();
		try {
			for (int page = 0; page < pageCount; page++) {
				Parser parser = new Parser(
						url+"?start="
								+ page * pageCount);
				parser.setEncoding("gbk");
				NodeList list = parser
						.extractAllNodesThatMatch(new NodeClassFilter(
								LinkTag.class));
				for (int i = 0; i < list.size(); i++) {
					Node tag = list.elementAt(i);
					if (tag instanceof LinkTag)// <a> 标签
					{
						LinkTag link = (LinkTag) tag;
						String linkUrl = link.getLink();// url
						String text = link.getLinkText();// 链接文字
						if (linkUrl.contains("http://www.douban.com/note")
								&& linkUrl.endsWith("/")) {
							if (!urls.contains(linkUrl)) {
								urls.add(linkUrl);
							}
						}
					}
				}
			}
		} catch (ParserException e) {
			e.printStackTrace();
		}
		for (String s : urls) {
			System.out.println(s);
		}
		return urls;
	}
}