本文目录一览:
java 实现网络爬虫用哪个爬虫框架比较好
有些人问,开发网络爬虫应该选择 Nutch、Crawler4j、WebMagic、Scrapy、WebCollector 还是其他的?这里按照我的经验随便扯淡一下: 上面说的爬虫,基本可以分 3 类:
- 分布式爬虫:Nutch
- Java 单机爬虫:Crawler4j、WebMagic、WebCollector
- 非 Java 单机爬虫:Scrapy
第一类:分布式爬虫
爬虫使用分布式,主要是解决两个问题:
- 海量 URL 管理
- 网速
现在比较流行的分布式爬虫是 Apache 的 Nutch。但是对于大多数用户来说,Nutch 是这几类爬虫里最不好的选择,理由如下: - Nutch 是为搜索引擎设计的爬虫,大多数用户是需要一个做精准数据爬取(精抽取)的爬虫。Nutch 运行的一套流程里,有三分之二是为了搜索引擎而设计的。对精抽取没有太大的意义。也就是说,用 Nutch 做数据抽取,会浪费很多时间在不必要的计算上。如果你试图通过对 Nutch 进行二次开发,来使得它适用于精抽取的业务,基本上就要破坏 Nutch 的框架,把 Nutch 改得面目全非,有修改 Nutch 的能力,不如自己重新写一个分布式爬虫框架。
- Nutch 依赖 Hadoop 运行,Hadoop 本身会消耗很多时间。如果集群机器数量较少,爬取速度反而不如单机爬虫快。
- Nutch 的插件系统蹩脚。利用反射机制加载和调用插件,使得程序编写和调试都变得异常困难。Nutch 并没有为精抽取提供相应的插件挂载点。大多数 Nutch 的精抽取插件,都是挂载在“页面解析”(parser) 这个挂载点的,这个挂载点其实是为了解析链接(为后续爬取提供 URL),以及为搜索引擎提供一些易抽取的网页信息(网页的 meta 信息、text 文本)。
- Nutch 的二次开发成本高。爬虫的编写和调试所需的时间,往往是单机爬虫所需的十倍不止。了解 Nutch 源码的学习成本很高,何况是要让一个团队的人都读懂 Nutch 源码。调试过程中会出现除程序本身之外的各种问题(Hadoop 的问题、HBase 的问题)。
- Nutch2 的持久化数据误解。很多人其实理解错了,这里说的持久化数据是指将 URL 信息(URL 管理所需要的数据)存放到 Avro、HBase、MySQL,并不是你要抽取的结构化数据。其实对大多数人来说,URL 信息存在哪里无所谓。
- Nutch2 的版本目前并不适合开发。官方现在稳定的 Nutch 版本是 nutch2.2.1,但是这个版本绑定了 gora-0.3。如果想用 HBase 配合 Nutch(大多数人用 nutch2 就是为了用 HBase),只能使用 0.90 版本左右的 HBase,相应的就要将 Hadoop 版本降到 hadoop 0.2 左右。而且 nutch2 的官方教程比较有误导作用。 所以,如果你不是要做搜索引擎,尽量不要选择 Nutch 作为爬虫。有些团队就喜欢跟风,非要选择 Nutch 来开发精抽取的爬虫,其实是冲着 Nutch 的名气(Nutch 作者是 Doug Cutting),当然最后的结果往往是项目延期完成。 如果你是要做搜索引擎,Nutch1.x 是一个非常好的选择。Nutch1.x 和 Solr 或者 ES 配合,就可以构成一套非常强大的搜索引擎了。如果非要用 Nutch2 的话,建议等到 Nutch2.3 发布再看。目前的 Nutch2 是一个非常不稳定的版本。
java 网络爬虫怎么实现
网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。 传统爬虫从一个或若干初始网页的 URL 开始,获得初始网页上的 URL,在抓取网页的过程中,不断从当前页面上抽取新的 URL 放入队列,直到满足系统的一定停止条件。对于垂直搜索来说,聚焦爬虫,即有针对性地爬取特定主题网页的爬虫,更为适合。 以下是一个使用 Java 实现的简单爬虫核心代码:
public void crawl() throws Throwable {
while (continueCrawling()) {
CrawlerUrl url = getNextUrl(); // 获取待爬取队列中的下一个 URL
if (url != null) {
printCrawlInfo();
String content = getContent(url); // 获取 URL 的文本信息
// 聚焦爬虫只爬取与主题内容相关的网页,这里采用正则匹配简单处理
if (isContentRelevant(content, this.regexpSearchPattern)) {
saveContent(url, content); // 保存网页至本地
// 获取网页内容中的链接,并放入待爬取队列中
Collection urlStrings = extractUrls(content, url);
addUrlsToUrlQueue(url, urlStrings);
} else {
System.out.println(url + " is not relevant ignoring ...");
}
// 延时防止被对方屏蔽
Thread.sleep(this.delayBetweenUrls);
}
}
closeOutputStream();
}
private CrawlerUrl getNextUrl() throws Throwable {
CrawlerUrl nextUrl = null;
while ((nextUrl == null) && (!urlQueue.isEmpty())) {
CrawlerUrl crawlerUrl = this.urlQueue.remove();
// doWeHavePermissionToVisit:是否有权限访问该 URL,友好的爬虫会根据网站提供的 "Robot.txt" 中配置的规则进行爬取
// isUrlAlreadyVisited:URL 是否访问过,大型的搜索引擎往往采用 BloomFilter 进行排重,这里简单使用 HashMap
// isDepthAcceptable:是否达到指定的深度上限。爬虫一般采取广度优先的方式。一些网站会构建爬虫陷阱(自动生成一些无效链接使爬虫陷入死循环),采用深度限制加以避免
if (doWeHavePermissionToVisit(crawlerUrl)
&& (!isUrlAlreadyVisited(crawlerUrl))
&& isDepthAcceptable(crawlerUrl)) {
nextUrl = crawlerUrl;
// System.out.println("Next url to be visited is " + nextUrl);
}
}
return nextUrl;
}
private String getContent(CrawlerUrl url) throws Throwable {
// HttpClient4.1 的调用与之前的方式不同
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url.getUrlString());
StringBuffer strBuf = new StringBuffer();
HttpResponse response = client.execute(httpGet);
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
HttpEntity entity = response.getEntity();
if (entity != null) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(entity.getContent(), "UTF-8"));
String line = null;
if (entity.getContentLength() > 0) {
strBuf = new StringBuffer((int) entity.getContentLength());
while ((line = reader.readLine()) != null) {
strBuf.append(line);
}
}
}
if (entity != null) {
entity.consumeContent();
}
}
// 将 url 标记为已访问
markUrlAsVisited(url);
return strBuf.toString();
}
public static boolean isContentRelevant(String content, Pattern regexpPattern) {
boolean retValue = false;
if (content != null) {
// 是否符合正则表达式的条件
Matcher m = regexpPattern.matcher(content.toLowerCase());
retValue = m.find();
}
return retValue;
}
public List extractUrls(String text, CrawlerUrl crawlerUrl) {
Map urlMap = new HashMap();
extractHttpUrls(urlMap, text);
extractRelativeUrls(urlMap, text, crawlerUrl);
return new ArrayList(urlMap.keySet());
}
private void extractHttpUrls(Map urlMap, String text) {
Matcher m = (text);
while (m.find()) {
String url = m.group();
String[] terms = url.split("a href=\"");
for (String term : terms) {
// System.out.println("Term = " + term);
if (term.startsWith("http")) {
int index = term.indexOf("\"");
if (index > 0) {
term = term.substring(0, index);
}
urlMap.put(term, term);
System.out.println("Hyperlink: " + term);
}
}
}
}
private void extractRelativeUrls(Map urlMap, String text, CrawlerUrl crawlerUrl) {
Matcher m = relativeRegexp.matcher(text);
URL textURL = crawlerUrl.getURL();
String host = textURL.getHost();
while (m.find()) {
String url = m.group();
String[] terms = url.split("a href=\"");
for (String term : terms) {
if (term.startsWith("/")) {
int index = term.indexOf("\"");
if (index > 0) {
term = term.substring(0, index);
}
String s = "http://" + host + term;
urlMap.put(s, s);
System.out.println("Relative url: " + s);
}
}
}
}
public static void main(String[] args) {
try {
String url = "";
Queue urlQueue = new LinkedList();
String regexp = "java";
urlQueue.add(new CrawlerUrl(url, 0));
NaiveCrawler crawler = new NaiveCrawler(urlQueue, 100, 5, 1000L, regexp);
// boolean allowCrawl = crawler.areWeAllowedToVisit(url);
// System.out.println("Allowed to crawl: " + url + " " + allowCrawl);
crawler.crawl();
} catch (Throwable t) {
System.out.println(t.toString());
t.printStackTrace();
}
}
java爬虫框架都有什么?哪个比较好学易用?谢谢!知道有nutch和heritrix可以,但是学习
登录的,建议你用 Jsoup 带着 cookie 进去。 动态的,建议你用 HtmlUnit。 WebMagic 和 Jsoup 都很好学。有时间学学,虽然不是必会,但是这种小工具说不定什么时候就用得上。