文档章节

大白痴学习webmagic

大白痴
 大白痴
发布于 2014/03/28 00:43
字数 3224
阅读 22925
收藏 10

刚刚开始学,很多东西可能理解错了,还请各位指教

一些基本类:

Request包含要爬行的url和一些附加信息,Page的一个成员变量

   主要成员变量

String  url

Map<String, Object>  extras 存储附加信息

long  priority  优先级 值越大越优先

主要方法

Request(String url) { this.url = url; }构造函数

Request  setPriority(long  priority)  设置优先级需要PriorityScheduler管理

Object  getExtra(String key)获取想要的附加信息 通过keymap里寻找

Request  putExtra(String key, Object value) 添加一组附加信息

 

ResultItems包含抓取的结果,是Page类的一个成员变量,并且要在pipeline中处理

主要成员变量

Map<String, Object> fields  HashMap

Request  request;

boolean  skip 是否要跳过这条结果,跳过了就不会被pipeline处理

主要方法

<T> T get(String key)  通过key获取相应值

Map<String, Object>  getAll() { return fields; }

ResultItems  put(String key, T value) 给当前对象添加一对值就是field添加记录

Request  getRequest() { return request; }

 

Page包含页面抽取的结果和要去取的URL

   主要成员变量

Request  request;  主要就是url对象

ResultItems  resultItems  抓取的结果,用于持久化

Html  html;

String  rawText;

Selectable  url;

Int  statusCode;

List<Request>  targetRequests

   主要方法

Selectable  getUrl(){ return url;  } 获取当前页url                

Html  getHtml()获取当前页内容               

ResultItems  getResultItems(){return resultItems; }获得抓取的结果以在Pipeline持久化里使用

void  putField(String, Object)保存抓取的结果

void  addTargetRequests(List<String>  requests) 添加url 去抓取

void  addTargetRequests(List<String>  requests, long priority) 添加url 去抓取

void  addTargetRequest(String  requestString) 添加url 去抓取

void  addTargetRequest(Request request) 添加request 去抓取

 

 

Site:包含爬虫的一些配置

   主要成员变量

String  domain;

List<Request>  startRequests = new ArrayList<Request>();  爬虫开始的url

Map<String, String>  cookies = new LinkedHashMap<String, String>();

Map<String, String>  headers = new HashMap<String, String>()

String  userAgent;

String  charset;

int  sleepTime = 5000;

int  retryTimes = 0;

int  cycleRetryTimes = 0;

int  timeOut = 5000;

HttpHost  httpProxy

主要方法

Site me() { return new Site(); } 新生成一个Site

Site  addCookie(String name, String value)  说明Add a cookie with domain

Site  setDomain(String domain) 设置Sitedomain

Site  addStartRequest(Request  startRequest) 添加一条url到开始集里

Site  addHeader(String key, String value) 为下载器设置一个http

Task  toTask()转换为一个Task

 

Task:标识不同任务的接口(是个interface),没有成员变量

  主要方法

String  getUUID() 获取一个task的唯一ID

Site    getSite()  获取一个taskSite

 

Spider:爬虫入口,包含Downloader   Scheduler  PageProcessor  and  Pipeline

   主要成员变量

Downloader  downloader;

List<Pipeline>  pipelines = new ArrayList<Pipeline>();

Scheduler  scheduler = new QueueScheduler();

PageProcessor  pageProcessor;

List<Request>  startRequests;

Site  site;

String  uuid;

Logger logger = Logger.getLogger(getClass());

int  threadNum = 1;

 

  主要方法

Spider  create(PageProcessor pageProcessor) 创建一个爬虫

Spider  startUrls(List<String> startUrls)添加开始集合 也就是给startRequests赋值

Spider  startRequest(List<Request>  startRequests) 添加开始集合,给startRequests赋值

Spider  scheduler(Scheduler scheduler)  设置scheduler(url管理器),给scheduler赋值

Spider  setScheduler(Scheduler scheduler) 设置scheduler(url管理器) ,给scheduler赋值

Spider  pipeline(Pipeline pipeline) 设置pipeline(持久化),给pipelines队列添加一条

Spider  addPipeline(Pipeline pipeline) 设置pipeline(持久化),给pipelines队列添加一条

Spider  clearPipeline() 清空pipeline

Spider  downloader(Downloader downloader) 设置downloader(下载器),给downloader赋值

Spider  setDownloader(Downloader downloader)设置downloader,给downloader赋值

void  test(String... urls) 该方法只抓取一个单独的页面,用于测试抽取效果

void  processRequest(Request request){  //核心处理流程

      Page page = downloader.download(request, this);

      pageProcessor.process(page);

      extractAndAddRequests(page);

      for (Pipeline pipeline : pipelines)

        pipeline.process(page.getResultItems(), this);

}

 

一个简单例子

Spider.create(new SimplePageProcessor("http://my.oschina.net/",

                                  "http://my.oschina.net/*blog/*")).run()

如果想把结果存到文件里怎么办呢?

Spider.create(new  SimplePageProcessor("http://my.oschina.net/",

  "http://my.oschina.net/*blog/*")) .pipeline(new FilePipeline("/data/temp/webmagic/")).run();

 

使用FileCacheQueueScheduler在文件中存取url和游标以便关闭后重新继续开始

Spider.create(new SimplePageProcessor("http://my.oschina.net/",

  "http://my.oschina.net/*blog/*"))

 .scheduler(new FileCacheQueueScheduler("/data/temp/webmagic/cache/")).run();













webmagic四大模块代码解析

 

downloader文件件夹  download一般不用管

Downloader是一个接口

主要方法

Page  download(Request request, Task task);下载页面并存到Page对象

void  setThread(int threadNum); 设置线程数

HttpClientDownloader 继承Downloader接口

主要成员变量

Logger  logger = Logger.getLogger(getClass());

Map<String, CloseableHttpClient>  httpClients = new HashMap<String, CloseableHttpClient>();

HttpClientGenerator  httpClientGenerator = new HttpClientGenerator();

   主要方法

Html  download(String url)  下载html

Html  download(String url, String charset)

Page  download(Request request, Task task) 实现接口方法


HttpClientGenerator 这个类是HttpClient产生器,就是工厂

主要成员变量

PoolingHttpClientConnectionManager  connectionManager;

主要方法

CloseableHttpClient   generateClient(Site site)

CloseableHttpClient   getClient(Site site)

HttpClientGenerator  setPoolSize(int poolSize)

void  generateCookie(HttpClientBuilder httpClientBuilder, Site site)

 

目前有几个Downloader的实现:

 

 HttpClientDownloader

集成了Apache HttpClientDownloaderApache HttpClient(4.0后整合到HttpCompenent项目中)是强大的Java http下载器,它支持自定义HTTP(对于爬虫比较有用的就是User-agentcookie)、自动redirect、连接复用、cookie保留、设置代理等诸多强大的功能。

SeleniumDownloader(这个文件里没有)

对于一些Javascript动态加载的网页,仅仅使用http模拟下载工具,并不能取到页面的内容。这方面的思路有两种:一种是抽丝剥茧,分析js的逻辑,再用爬虫去重现它;另一种就是:内置一个浏览器,直接获取最后加载完的页面。webmagic-selenium包中整合了SeleniumSeleniumDownloader,可以直接进行动态载页面的抓取。使用selenium需要安装一些native的工具,具体步骤可以参考作者的博文使用Selenium来抓取动态加载的页面

 

 

 

 

 

 

 

PageProcessor文件夹,页面分析及链接抽取,是我们使用的关键

PageProcessor是一个接口,用于定制爬虫,可定制启动url和一些设置,如何发现要抓取的url,数据要如何提取和存储

   主要方法

void  process(Page page); 处理Page对象,提取URL,提取数据并存储

Site  getSite() 获取site 的一些设置信息

 

通过编写一个实现PageProcessor接口的类,就可以定制一个自己的爬虫,比如

public  class  GithubRepoPageProcesser implements  PageProcessor {

private  Site  site = Site.me().setRetryTimes(3).setSleepTime(100); //一些设置信息

 @Override

 public void  process(Page  page) { //通过正则表达式和Xpath来抓取

   //要抓取的链接需要显示地添加

   page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());

   //抓取规则

   page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());

   page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());

   if (page.getResultItems().get("name")==null){  page.setSkip(true);  } //skip this page

   page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));

   }

@Override

 public Site  getSite() {

        return site;

    }

 

public  static  void  main(String[]  args) {

      Spider.create(new GithubRepoPageProcesser()).addUrl("https://github.com/code4craft").thread(5).run();

    }

}

 

 

 

几种抓取方式

1.java正则表达式:这个不多讲 .  []  () 

2.Jsoup支持jquerycss selector的方式选取元素

   String content = "blabla"; Document doc = JSoup.parse(content);  Elements links = doc.select("a[href]");

3. HtmlCleaner支持XPath的方式选取元素:

4.Xpath tagNode.evaluateXPath("//a/@href ")

5.CSS选择:$("a[href]").attr("href")

 

webmagic主要实现了CSS SelectorXPath和正则表达式三种抓取方式,其实现放在Selector文件下

 

 

 

Scheduler文件夹,URL管理 主要有两个实现QueueSchedulerFileCacheQueueScheduler


Scheduler是一个接口,实现它可以管理要抓取的URL,还可以去重复

  主要方法

void push(Request request, Task task)  添加一个要抓取的url

Request poll(Task task)  取出一个URL来爬行

 

QueueScheduler继承Scheduler接口,一个简单的内存队列,速度较快,并且是线程安全的

主要成员变量

Logger  logger = Logger.getLogger(getClass());

BlockingQueue<Request>  queue = new LinkedBlockingQueue<Request>();

Set<String>  urls = new HashSet<String>();

   主要方法

void  push(Request request, Task task)  queue里边添加一个request

Request  poll(Task task)  queue里边弹出一个request

 

PriorityScheduler继承Scheduler接口,是一个文件队列,它可以用于耗时较长的下载任务,在任务中途停止后,下次执行仍然从中止的URL开始继续爬取。

主要成员变量

Logger  logger = Logger.getLogger(getClass());

BlockingQueue<Request>  noPriorityQueue = new  LinkedBlockingQueue<Request>();

Set<String>  urls = new HashSet<String>();

主要方法

void  push(Request request, Task task) 添加一个request

Request  poll(Task task) 弹出一个request

 

Pipeline文件夹,用于后续处理和持久化 主要有四个实现

Pipeline是一个接口,用于持久化 离线处理  只有一个方法

  主要方法

void  process(ResultItems resultItems, Task  task) resultItems通过get(key)得到数据

 

CollectorPipeline<T>也是一个接口,且继承了Pipeline,新增了一个方法

    主要方法

List<T>  getCollected(); 获取收集到的所有信息

 

ConsolePipeline 实现了Pipeline接口,把结果输出到控制台

 public void process(ResultItems resultItems, Task task) {

     System.out.println("get page: " + resultItems.getRequest().getUrl());

     for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {

            System.out.println(entry.getKey() + ":\t" + entry.getValue());

        }

    }

ResultItemsCollectorPipeline实现了CollectorPipeline<T>接口

主要成员变量

List<ResultItems>  collector = new  ArrayList<ResultItems>();

     主要方法

public  synchronized  void  process(ResultItems resultItems, Task task) {

        collector.add(resultItems);

    }

public  List<ResultItems>  getCollected() {

        return collector;

}

 

FilePipeline 实现了FilePersistentBasePipeline接口,把数据存到文件里,每个URL单独保存到一个页面,以URLMD5结果作为文件名

   主要成员变量

Logger  logger = Logger.getLogger(getClass());

   主要方法

FilePipeline() {  setPath("/data/webmagic/");  } 默认构造函数 设置了存储路径

FilePipeline(String  path) {  setPath(path);  } 自定义存储路径

void  process(ResultItems resultItems, Task task)


selector文件夹,算是PageProcessor的扩展吧,因为要集合很多选取方式


Selectable:接口 可选的文本                                             

Selectable  xpath(String xpath);使用xpath选择

Selectable  $(String selector);  使用CSS选择

Selectable  $(String selector, String attrName); 使用CSS选择

Selectable  css(String selector); 使用CSS选择

Selectable  css(String selector, String attrName); 使用CSS选择

Selectable  regex(String regex);使用正则表达式选择group默认为1

Selectable  regex(String regex, int group); 使用正则表达式选择

Selectable  replace(String regex, String replacement);

Selectable  smartContent(); 选取smart content

Selectable  links(); 选取所有链接


PlainText:实现了Selectable接口

PlainText(List<String> strings)

PlainText(String text)

PlainText  create(String text)

Selectable  select(Selector selector, List<String> strings)

Selectable  selectList(Selector selector, List<String> strings)

 

Html:继承了PlainText

主要成员变量

Logger  logger = Logger.getLogger(getClass());

Document  document; 存储解析过的文档

boolean  init = false;

主要方法:给出新增的方法

Html(List<String> strings)

Html(String text)

Html(Document document)

void   initDocument() 简单的初始化方法

Html  create(String text)

String  selectDocument(Selector selector)

List<String>  selectDocumentForList(Selector selector)

String  getText()

Document  getDocument()

 

Selectors:一个抽象类

RegexSelector  regex(String expr)        RegexSelector  regex(String expr, int group)

CssSelector  $(String expr)              CssSelector  $(String expr, String attrName)

XpathSelector  xpath(String expr)        XsoupSelector  xsoup(String expr)

AndSelector  and(Selector... selectors)    OrSelector  or(Selector... selectors)

SmartContentSelector  smartContent() 

Selector:接口,文本抽取器 就两个方法

String  select(String text) 抽取单条结果,若有多个,只有第一个被选择

List<String>  selectList(String text) 抽取所有结果

 

ElementSelector:接口   针对html elements

String select(Element element);

List<String> selectList(Element element);

 

 

RegexSelector:实现Selector接口,使用正则表达式抽取

主要成员变量

String  regexStr;

Pattern  regex;

int  group = 1;

主要方法

RegexSelector(String regexStr, int group)构造

RegexSelector(String regexStr)构造

String  select(String text)重写

List<String>  selectList(String text)重写

RegexResult  selectGroup(String text)

List<RegexResult>  selectGroupList(String text)

 

XpathSelector:实现Selector接口,使用Xpath抽取

主要成员变量

String  xpathStr;

主要成员方法

XpathSelector(String xpathStr)

String  select(String text)重写

List<String>  selectList(String text)重写

 

ReplaceSelector:实现Selector接口,重置选择器

主要成员变量

String  regexStr;

String  replacement;

Pattern  regex;

主要成员方法

ReplaceSelector(String regexStr, String replacement)

String  select(String text)重写

List<String>  selectList(String text)重写

 

 AndSelector:实现Selector接口,所有选择器以管道式安排,后一个用前一个的结果

主要成员变量

List<Selector>  selectors = new ArrayList<Selector>()

主要成员方法

AndSelector(Selector... selectors)

AndSelector(List<Selector> selectors)

String  select(String text)重写

List<String>  selectList(String text)重写

 

OrSelector:实现Selector接口,所有提取器独自工作,提取的结果将会整合起来

主要成员变量

List<Selector>  selectors = new ArrayList<Selector>()

主要成员方法

OrSelector(Selector... selectors)

OrSelector(List<Selector> selectors)

String  select(String text)重写

List<String>  selectList(String text)重写

 

OrSelector:实现Selector接口,所有提取器独自工作,提取的结果将会整合起来

主要成员变量

List<Selector>  selectors = new ArrayList<Selector>()

主要成员方法

OrSelector(Selector... selectors)

OrSelector(List<Selector> selectors)

String  select(String text)重写

List<String>  selectList(String text)重写

 

BaseElementSelector:抽象类 继承于Selector, ElementSelector

String  select(String text)重写

List<String>  selectList(String text)重写

 

CssSelector:继承BaseElementSelector   CSS selector. Based on Jsoup

主要成员变量

String  selectorText;

String  attrName;

主要成员方法

CssSelector(String selectorText)

CssSelector(String selectorText, String attrName)

String getValue(Element element)

String  select(String text)重写

List<String>  selectList(String text)重写

 

XsoupSelector:继承BaseElementSelector   XPath selector based on Xsoup

主要成员变量

XPathEvaluator xPathEvaluator;

主要成员方法

XsoupSelector(String xpathStr)

String  select(String text)重写

List<String>  selectList(String text)重写

例如,我已经下载了一个页面,现在要抽取某个区域的所有包含"blog"的链接,我可以这样写:

String content = "blabla"; //content是用别的爬虫工具抽取到的正文

List<String>  links = Html.create(content)

.$("div.title")  //css 选择,Java里虽然很少有$符号出现,不过貌似$作为方法名是合法的

.xpath("//@href")  //提取链接

.regex(".*blog.*") //正则匹配过滤

.all(); //转换为string列表

 


utils文件夹,一些实用工具

 

UrlUtilsurlhtml的工具

  Pattern patternForProtocal = Pattern.compile("[\\w]+://")

Pattern patternForCharset = Pattern.compile("charset\\s*=\\s*['\"]*([^\\s;'\"]*)");

  Pattern patternForHref = Pattern.compile("(<a[^<>]*href=)[\"']{0,1}([^\"'<>\\s]*)[\"']{0,1}", Pattern.CASE_INSENSITIVE);

String canonicalizeUrl(String url, String refer)

  String getHost(String url)

  String removeProtocol(String url)

  String getDomain(String url)

String fixAllRelativeHrefs(String html, String url)

List<Request> convertToRequests(Collection<String> urls)

List<String> convertToUrls(Collection<Request> requests)

String getCharset(String contentType)

ThreadUtils

  ExecutorService newFixedThreadPool(int threadSize)

NumberUtils:抽象类

  int compareLong(long o1, long o2)

FilePersistentBase:文件持久化的基本对象

  String path

String PATH_SEPERATOR = "/"

  String getPath()

  void checkAndMakeParentDirecotry(String fullName)

File getFile(String fullName)

void setPath(String path)

EnvironmentUtil

   String USE_XSOUP = "xsoup"

   boolean useXsoup()

   void  setUseXsoup(boolean useXsoup)


© 著作权归作者所有

大白痴
粉丝 1
博文 3
码字总数 5947
作品 0
厦门
私信 提问
加载中

评论(5)

天王盖地虎
天王盖地虎
总结的不错。
不过:一切不排版的代码都是耍流氓!28
数据工厂
数据工厂
我觉得对于开发者来说,能脚本化编写爬虫是一件挺开心的事情( ̄▽ ̄)"。所以我们团队开发了一个专门让开发者用简单的几行 javascript 就能在云上编写和运行复杂爬虫的系统,叫神箭手云爬虫开发平台: http://www.shenjianshou.cn 。欢迎同行们来试用拍砖,尽情给俺们提意见。有想法的可以加群讨论: 342953471
烦烦烦的JerryD
烦烦烦的JerryD
不错
y
yanjianlee
不错啊
gray夜
gray夜
感谢分享
webmagic 0.2.0 发布,Java垂直爬虫框架

此次更新的主题是"方便"(之前的主题是"灵活")。 增加了webmagic-extension模块。 增加了注解方式支持,可以通过POJO+注解的方式编写一个爬虫,更符合Java开发习惯。以下是抓取oschina博客的完...

黄亿华
2013/08/12
5.1K
22
webmagic的example运行失败

我在eclipse中建立工程后将webmagic/lib中的除webmagic-core和webmagic-extension外的jar包导入工程,又将webmagic/webmagic-core/src/main/us和webmagic/webmagic-extension/src/main/us复制......

zzblac
2015/12/16
235
2
webmagic 存储

@大白痴 你好,想跟你请教个问题: 我的webmagic为什吗存储不到本地,就是使用pipeline

城花祭泪
2015/11/17
251
0
WebMagic 0.4.1 发布,Java 爬虫框架

此次更新加强了Ajax抓取的功能,并进行了一些功能改进。同时引入了重要的脚本化功能"webmagic-script",为今后的WebMagic-Avalon计划做准备。 功能增强: 修复了抓取完页面后,Spider偶尔无法...

黄亿华
2013/11/28
3.3K
17
webmagic的设计机制及原理-如何开发一个Java爬虫

此文章是webmagic 0.1.0版的设计手册,后续版本的入门及用户手册请看这里:https://github.com/code4craft/webmagic/blob/master/user-manual.md 之前就有网友在博客里留言,觉得webmagic的实...

黄亿华
2013/07/20
67.8K
94

没有更多内容

加载失败,请刷新页面

加载更多

Phpstorm2018 永久激活

1、安装phpstorm,安装包请自行官网下载 http://www.jetbrains.com/phpstorm/download/ 2、下载JetbrainsCrack.jar文件,存放至你的phpstorm执行文件同级目录下 下载JetbrainsCrack.jar 提取...

happyfish319
19分钟前
5
0
谈一谈Android进程间通信的几种方式

###来看一下Android中除了AIDL还有哪些进程间通信的方式: 1、Bundle Bundle实现了Parcelable,所以在Android中我们可以通过Intent在不同进程间传递Bundle数据。 但是在Intent 传输数据的过程...

二营长的意大利炮手
20分钟前
6
0
互联网薪资“高开低走”,你的能力是否真的可以匹配高薪?

对于国内外主流互联网大厂,技术出身似乎已经成为各大掌门人的必备标签。谷歌 CEO 桑达尔·皮查伊、马克·扎克伯格、李彦宏、马化腾、雷军等等皆为技术人出身,都曾参与了公司内部重要产品的...

Java技术剑
21分钟前
6
0
java 多线程

线程声明周期 线程的五个状态:新建,就绪,运行,阻塞,死亡。 其中就绪和运行两个状态客户互相转换,但运行到阻塞,阻塞到就绪,只能单向转换。 刚new出的线程就是【新建】状态,调用start...

雷开你的门
23分钟前
7
0
构造器Constructor是否可被overrid

构造器不能被重写,不能用static修饰构造器,只能用public private protected这三个权限修饰符,且不能有返回语句。

无名氏的程序员
27分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部