1.webmagic框架
webmagic框架是一个Java实现的爬虫框架,底层依然是HttpClient和jsoup
组件:
- downloader:下载器组件
- PageProcessor:页面解析组件(必须自定义)
- scheculer:访问队列组件
- pipeline:数据持久化组件(默认是输出到控制台)
2.入门程序
2.1创建工程
- 创建一个Maven工程
- 添加坐标
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>us.codecraft</groupId> <artifactId>webmagic-core</artifactId> <version>0.9.0</version> </dependency> <dependency> <groupId>us.codecraft</groupId> <artifactId>webmagic-extension</artifactId> <version>0.9.0</version> </dependency>
2.2入门程序
1.创建PageProcess接口实现类
package org.example;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
/**
* 实现分析的业务逻辑
*/
public class MypageProcessor implements PageProcessor {
/**
* 页面分析
*
* @param page 下载结果封装成Page对象
* 可以从page对象中获得下载的结果
*/
@Override
public void process(Page page) {
Html html = page.getHtml();
String htmlStr = html.toString();
//把结果输出到控制台
// ResultItems resultItems = page.getResultItems();
// resultItems.put("html", htmlStr);
page.putField("html", htmlStr);
}
/**
* 返回一个Site对象
* Site就是站点的配置
* 返回默认配置使用Site.me创建一个Site对象
*
* @return
*/
@Override
public Site getSite() {
return Site.me();
}
public static void main(String[] args) {
Spider.create(new MypageProcessor())
//设置起始的url
.addUrl("http://www.itcast.cn")
//启动爬虫
//run 是同步方法在当前线程中执行
//start 在新线程中执行爬虫
.run();
}
}
2.在实现类中实现页面分析的业务逻辑
3.初始化爬虫
4.启动爬虫
5.结果
3.组件介绍
3.1Downloader
下载器组件,使用HttpClient实现
如果没有特殊需求不需要自定义,默认的组件就可以满足全部需求
自定义时需要实现Downloader接口
向PageProcess传递数据时,把结果封装成Page对象
3.2PageProcess(必须自定义)
页面分析的业务组件,页面分析的逻辑在其中实现
需要实现PageProcessor接口
3.2.1.Site
Site代表一个站点信息
可以设置抓取的频率
重试的次数
超时时间
如果没有特殊需求 直接使用默认配置即可
3.2.2Page
getHtml(): 返回抓取的结果
getResultItems(): 返回ResultItems对象, 向pipeline传递数据时使用
getTargetReqyests()、getTargetReqyest(): 向scheduler对象中添加url
3.2.3html(Selectable)
html也是一个Selectable对象
一个Selectable就可以表示一个dom节点
使用html解析页面三种方式:
1.使用原生jsoup方法进行解析
Document document = html.getDocument();
2.使用框架提供的css选择器
html.css("选择器")
html.$("选择器")
3.使用Xpath解析
3.2.4ResultItems
作用就是把解析的结果传递给pipeline
可以使用page对象的getResultItems()方法获取该对象
也可以直接使用putField方法将数据添加到ResultItems对象中
3.2.5Request
并不是Http请求的Request对象,就是把url封装成Request对象
可以添加一个 也可以添加多个
3.3pipeline(自定义频率高)
数据持久化组件
框架提供了三个实现,ConsolePipeline:向控制台输出 默认的
FilePipeline:向磁盘文件中输出
JsonFilePipeline: 保存Json格式的文件
也可以自定义pipeline:
需要实现pipeline接口。
package org.example;
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.pipeline.FilePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;
import java.util.List;
/**
* 获取黑马网站全部网页
*/
public class FilePipelinePageProcessor implements PageProcessor {
@Override
public void process(Page page) {
//访问黑马首页
Html html = page.getHtml();
//解析首页中所有的链接地址
// Selectable css = html.css("a", "href");
Selectable links = html.links();
List<String> all = links.all();
//把链接地址添加到访问队列中
page.addTargetRequests(all);
//把页面传递给pipeline 保存到磁盘
page.putField("html",html.get());
}
@Override
public Site getSite() {
return PageProcessor.super.getSite();
}
public static void main(String[] args) {
FilePipeline filePipeline = new FilePipeline();
filePipeline.setPath("Z:\\html");
//使用spider初始化爬虫
Spider.create(new FilePipelinePageProcessor())
//设置起始的url
.addUrl("http://www.itheima.com")
//设置使用的pipeline
.addPipeline(new ConsolePipeline())
.addPipeline(filePipeline)
//启动
.run();
}
}
3.4Scheduler
访问url队列
1.默认使用的内存队列
url数据量大时会占用大量的内存
2.文件形式的队列
需要制定保存队列文档的文件路径和文件名
3.redis分布式队列
实现分布式爬虫时 大规模爬虫时使用
3.4.1url去重
webmagic框架中可以对url进行去重处理
1.默认使用HashSet进行去重
需要占用大量的内存
2.规模大时 应该是用redis去重
使用redis成本高,需要搭建集群
3.布隆过滤器去重
内存小,速度快,成本低
缺点是有可能误判,不能删除
3.4.2布隆过滤器的使用
1.添加guava的jar包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
public static void main(String[] args) {
FilePipeline filePipeline = new FilePipeline();
filePipeline.setPath("Z:\\html");
//创建一个Scheduler
QueueScheduler scheduler = new QueueScheduler();
//指定队列使用布隆过滤器去重
//初始化一个布隆过滤器 参数就是容量
scheduler.setDuplicateRemover(new BloomFilterDuplicateRemover(10000000));
//使用spider初始化爬虫
Spider.create(new FilePipelinePageProcessor())
//设置起始的url
.addUrl("http://www.itheima.com")
//设置使用的pipeline
.addPipeline(new ConsolePipeline())
.addPipeline(filePipeline)
//设置使用的Scheduler对象
.setScheduler(scheduler)
//启动
.run();
}
3.5Spider
工具类,可以初始化爬虫
在spider中配置各个组件
启动爬虫
4.页面解析
4.1jsoup
package org.example;
import org.jsoup.nodes.Document;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
public class MypageProcessor1 implements PageProcessor {
@Override
public void process(Page page) {
//使用原生Jsoup的api解析页面
Html html = page.getHtml();
//得到一个jsoup的Document对象
Document document = html.getDocument();
String title = document.getElementsByTag("title").text();
//传递给pipeline
page.putField("title", title);
}
@Override
public Site getSite() {
return PageProcessor.super.getSite();
}
public static void main(String[] args) {
Spider.create(new MypageProcessor1())
.addUrl("https://www.jd.com")
.start();
}
}
4.2css选择器解析
//使用css解析器解析页面
Selectable domTitle = html.$("title","text");
// String title1 = domTitle.toString();
String title2 = domTitle.get();
page.putField("title2",title2);
Selectable元素 两个方法 get()、toString() 都可以把结果转换为字符串
如果返回的是一个dom列表,那么只返回第一个元素
all()就可以得到列表
4.3Xpath解析
这个是webmagic框架中实现的
XPath 教程 (w3school.com.cn)
package org.example;
import org.jsoup.nodes.Document;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;
import java.util.List;
public class MypageProcessor1 implements PageProcessor {
@Override
public void process(Page page) {
//使用原生Jsoup的api解析页面
Html html = page.getHtml();
//得到一个jsoup的Document对象
Document document = html.getDocument();
String title = document.getElementsByTag("title").text();
//传递给pipeline
page.putField("title", title);
//使用css解析器解析页面
Selectable domTitle = html.$("title", "text");
// String title1 = domTitle.toString();
String title2 = domTitle.get();
page.putField("title2", title2);
//选择一个节点列表
// 只返回第一个
String s = html.css("link", "href").get();
// 返回列表
List<String> all = html.css("link", "href").all();
System.out.println(s);
System.out.println(all);
//使用Xpath进行解析
Selectable xpath = html.xpath("//*[@id=\"navitems-group1\"]/li[1]/a/text()");
String addr = xpath.get();
page.putField("addr", addr);
}
@Override
public Site getSite() {
return PageProcessor.super.getSite();
}
public static void main(String[] args) {
Spider.create(new MypageProcessor1())
.addUrl("https://www.jd.com")
.start();
}
}