2019独角兽企业重金招聘Python工程师标准>>>

阅读背景: 如果您对爬虫,或则web前端不够了解,请自行google。

代码前提:您需要参阅本ID 所写的前面两篇博文:  Storm【实践系列-如何写一个爬虫】 - Fetcher

本章主题: ParserBolt 如何完成的解析,并且如何从前面的组件得到数据,并emit出去。

博文流程:  博文将整个 爬虫系列公开,其过程为:

1 : 代码实现。

2 : 对代码的细节进行解析。

3 : 对真个设计进行回顾,并作总结。

如果您在参看本ID的博文的过程之中,只存在流程 1。那么请继续等待。一旦公司业务不处于饱和阶段。

本ID将保证每日一篇。

package com.digitalpebble.storm.crawler.bolt.parser;import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;import org.apache.commons.lang.StringUtils;
import org.apache.tika.Tika;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.sax.Link;
import org.apache.tika.sax.LinkContentHandler;
import org.apache.tika.sax.TeeContentHandler;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;import com.codahale.metrics.Timer;
import com.digitalpebble.storm.crawler.StormConfiguration;
import com.digitalpebble.storm.crawler.filtering.URLFilters;
import com.digitalpebble.storm.crawler.util.Configuration;
import com.digitalpebble.storm.crawler.util.HistogramMetric;
import com.digitalpebble.storm.crawler.util.MeterMetric;
import com.digitalpebble.storm.crawler.util.TimerMetric;
import com.digitalpebble.storm.crawler.util.URLUtil;/*** Uses Tika to parse the output of a fetch and extract text + metadata***/@SuppressWarnings("serial")
public class ParserBolt extends BaseRichBolt {private Configuration config;private Tika tika;private URLFilters filters = null;private OutputCollector collector;private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ParserBolt.class);private MeterMetric eventMeters;private HistogramMetric eventHistograms;private TimerMetric eventTimers;private boolean ignoreOutsideHost = false;private boolean ignoreOutsideDomain = false;public void prepare(Map conf, TopologyContext context,OutputCollector collector) {config = StormConfiguration.create();String urlconfigfile = config.get("urlfilters.config.file","urlfilters.json");if (urlconfigfile != null)try {filters = new URLFilters(urlconfigfile);} catch (IOException e) {LOG.error("Exception caught while loading the URLFilters");}ignoreOutsideHost = config.getBoolean("parser.ignore.outlinks.outside.host", false);ignoreOutsideDomain = config.getBoolean("parser.ignore.outlinks.outside.domain", false);// instanciate Tikalong start = System.currentTimeMillis();tika = new Tika();long end = System.currentTimeMillis();LOG.debug("Tika loaded in " + (end - start) + " msec");this.collector = collector;this.eventMeters = context.registerMetric("parser-meter",new MeterMetric(), 5);this.eventTimers = context.registerMetric("parser-timer",new TimerMetric(), 5);this.eventHistograms = context.registerMetric("parser-histograms",new HistogramMetric(), 5);}public void execute(Tuple tuple) {eventMeters.scope("tuple_in").mark();byte[] content = tuple.getBinaryByField("content");eventHistograms.scope("content_bytes").update(content.length);String url = tuple.getStringByField("url");HashMap<String, String[]> metadata = (HashMap<String, String[]>) tuple.getValueByField("metadata");// TODO check status etc...Timer.Context timer = eventTimers.scope("parsing").time();// rely on mime-type provided by server or guess?ByteArrayInputStream bais = new ByteArrayInputStream(content);Metadata md = new Metadata();String text = null;LinkContentHandler linkHandler = new LinkContentHandler();ContentHandler textHandler = new BodyContentHandler();TeeContentHandler teeHandler = new TeeContentHandler(linkHandler,textHandler);ParseContext parseContext = new ParseContext();// parsetry {tika.getParser().parse(bais, teeHandler, md, parseContext);text = textHandler.toString();} catch (Exception e) {LOG.error("Exception while parsing " + url, e.getMessage());eventMeters.scope("error_content_parsing_" + e.getClass().getSimpleName()).mark();collector.fail(tuple);eventMeters.scope("tuple_fail").mark();return;} finally {try {bais.close();} catch (IOException e) {LOG.error("Exception while closing stream", e);}}long duration = timer.stop();LOG.info("Parsed " + url + " in " + duration + " msec");// get the outlinks and convert them to strings (for now)String fromHost;URL url_;try {url_ = new URL(url);fromHost = url_.getHost().toLowerCase();} catch (MalformedURLException e1) {// we would have known by now as previous// components check whether the URL is validLOG.error("MalformedURLException on " + url);eventMeters.scope("error_outlinks_parsing_" + e1.getClass().getSimpleName()).mark();collector.fail(tuple);eventMeters.scope("tuple_fail").mark();return;}List<Link> links = linkHandler.getLinks();Set<String> slinks = new HashSet<String>(links.size());for (Link l : links) {if (StringUtils.isBlank(l.getUri()))continue;String urlOL = null;try {URL tmpURL = URLUtil.resolveURL(url_, l.getUri());urlOL = tmpURL.toExternalForm();} catch (MalformedURLException e) {LOG.debug("MalformedURLException on " + l.getUri());eventMeters.scope("error_out_link_parsing_"+ e.getClass().getSimpleName()).mark();continue;}// filter the urlsif (filters != null) {urlOL = filters.filter(urlOL);if (urlOL == null) {eventMeters.scope("outlink_filtered").mark();continue;}}if (urlOL != null && ignoreOutsideHost) {String toHost;try {toHost = new URL(urlOL).getHost().toLowerCase();} catch (MalformedURLException e) {toHost = null;}if (toHost == null || !toHost.equals(fromHost)) {urlOL = null; // skip iteventMeters.scope("outlink_outsideHost").mark();continue;}}if (urlOL != null) {slinks.add(urlOL);eventMeters.scope("outlink_kept").mark();}}// add parse md to metadatafor (String k : md.names()) {// TODO handle mutliple valuesString[] values = md.getValues(k);metadata.put("parse." + k, values);}collector.emit(tuple, new Values(url, content, metadata, text.trim(), slinks));collector.ack(tuple);eventMeters.scope("tuple_success").mark();}public void declareOutputFields(OutputFieldsDeclarer declarer) {// output of this module is the list of fields to index// with at least the URL, text contentdeclarer.declare(new Fields("url", "content", "metadata", "text","outlinks"));}}

转载于:https://my.oschina.net/infiniteSpace/blog/303813

Storm【实践系列-如何写一个爬虫】 - ParserBolt相关推荐

  1. python可抓取数据包括什么_Python对JS型数据抓取有什么特别好的方法吗,pythonjs型抓取,想写一个爬虫,但是需要抓...

    Python对JS型数据抓取有什么特别好的方法吗,pythonjs型抓取,想写一个爬虫,但是需要抓 想写一个爬虫,但是需要抓去的的数据是js生成的,在源代码里看不到,要怎么才能抓到呢? 最好是用pyt ...

  2. 花三分钟给女票写一个爬虫,做一回模范男友!

    烦恼波及 女票是做运营的,一直苦恼于起推文标题.领导还会频繁突袭:"XX,给这次活动拟一个标题." tmd,自己分内的活都干不完,却要为活动策划起标题流汗,不是自己的活,还得笑着干 ...

  3. 用 Python + itchat 写一个爬虫脚本每天定时给女朋友发微信暖心话

    项目介绍: 灵感来源 在掘金看到了一篇<用Node+wechaty写一个爬虫脚本每天定时给女(男)朋友发微信暖心话>后,我就想为什么不用 Python 去实现这个功能呢. JUST TO ...

  4. 用Node+wechaty写一个爬虫脚本每天定时给女朋友发微信暖心话

    点击上方"前端小苑",选择"置顶公众号" 精品技术文章,热门资讯第一时间送达 wechatBot 微信每日说,每日自动发送微信消息给你心爱的人 项目介绍 灵感来 ...

  5. 用Node+wechaty写一个爬虫脚本每天定时给女(男)朋友发微信暖心话

    wechatBot 微信每日说,每日自动发送微信消息给你心爱的人 项目介绍 灵感来源 在掘金看到了一篇<用Node + EJS写一个爬虫脚本每天定时女朋友发一封暖心邮件>后, 在评论区偶然 ...

  6. 【手写系列】写一个迷你版的Tomcat

    前言 Tomcat,这只3脚猫,大学的时候就认识了,直到现在工作中,也常会和它打交道.这是一只神奇的猫,今天让我来抽象你,实现你! Tomcat Write MyTomcat Tomcat是非常流行的 ...

  7. 写一个爬虫爬取boss直聘网站

    好的,我可以为您简要介绍如何编写一个爬虫来爬取 BOSS 直聘网站. 首先,您需要准备好以下几个东西: 安装 Python,并使用 pip 安装爬虫所需的库,如 requests 和 Beautifu ...

  8. 写一个爬虫,可以爬取百度文库内容

    爬取百度文库内容需要使用爬虫技术.以下是一个简单的 Python 爬虫示例: import requestsurl ="https://wenku.baidu.com/view/your_d ...

  9. 写一个爬虫来获取地铁信息数据

    用面向对象的方法来获取地铁信息数据 写在前面 具体代码如下 代码说明 这是说明 写在前面 最近在知乎上看到一篇关于地铁数据的分析,该篇文章很全面的分析了大陆(包括澳门香港)有地铁城市的分布.线路.站点 ...

最新文章

  1. 深入浅出Java垃圾回收机制
  2. 亿级流量架构之服务限流思路与方法
  3. JPA HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError
  4. 基于笛卡尔坐标系下的三边定位的研究(TOA方式定位)
  5. 心路历程(五)-find work and find house
  6. Intellj IDEA 注册码 2018
  7. 可以改位置吗_恒大文化旅游城售楼部位置外地人可以买吗优选好房泗洪
  8. Django 入门初探
  9. linux下导入mysql数据库命令
  10. jsp简单案例(供小白学习)
  11. 如何制作扫描连接WIFI二维码,手机扫码即可一键连接无线WIFI网络
  12. 机器学习(七)白化whitening
  13. LA3713 Astronauts
  14. JavaFX中嵌入谷歌Chromium内核
  15. 正则表达式可视化校验工具Regulex
  16. 如何关闭IE浏览器安全设置检查功能
  17. 【帧率倍频】基于FPGA的视频帧率倍频系统verilog开发实现
  18. Arcgis选择自己想要的区域地图
  19. LeetCode 460. LFU 缓存 -- 哈希查询+双向链表
  20. 我是如何记笔记的--谈谈自己的学习方法

热门文章

  1. DCMTK:将VeriLUM CCx_xx.dat文件转换为DCMTK显示文件
  2. DCMTK:查询/检索服务类用户(C-GET操作)
  3. VTK:Math之MatrixInverse
  4. ListElement QML类型
  5. C语言实现镜子mirror算法(附完整源码)
  6. C++ 中的 new/delete 和 new[]/delete[]
  7. java 减法_java 加减法2
  8. 怎么把线稿提取出来_ps提取线稿教程(ps怎么把图片的线稿弄出来)
  9. 如何找到设备的guid_如何禁止win10自动更新显卡驱动
  10. 处理时间_4_计算时间列所在的周的序号