Storm【实践系列-如何写一个爬虫】 - ParserBolt
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相关推荐
- python可抓取数据包括什么_Python对JS型数据抓取有什么特别好的方法吗,pythonjs型抓取,想写一个爬虫,但是需要抓...
Python对JS型数据抓取有什么特别好的方法吗,pythonjs型抓取,想写一个爬虫,但是需要抓 想写一个爬虫,但是需要抓去的的数据是js生成的,在源代码里看不到,要怎么才能抓到呢? 最好是用pyt ...
- 花三分钟给女票写一个爬虫,做一回模范男友!
烦恼波及 女票是做运营的,一直苦恼于起推文标题.领导还会频繁突袭:"XX,给这次活动拟一个标题." tmd,自己分内的活都干不完,却要为活动策划起标题流汗,不是自己的活,还得笑着干 ...
- 用 Python + itchat 写一个爬虫脚本每天定时给女朋友发微信暖心话
项目介绍: 灵感来源 在掘金看到了一篇<用Node+wechaty写一个爬虫脚本每天定时给女(男)朋友发微信暖心话>后,我就想为什么不用 Python 去实现这个功能呢. JUST TO ...
- 用Node+wechaty写一个爬虫脚本每天定时给女朋友发微信暖心话
点击上方"前端小苑",选择"置顶公众号" 精品技术文章,热门资讯第一时间送达 wechatBot 微信每日说,每日自动发送微信消息给你心爱的人 项目介绍 灵感来 ...
- 用Node+wechaty写一个爬虫脚本每天定时给女(男)朋友发微信暖心话
wechatBot 微信每日说,每日自动发送微信消息给你心爱的人 项目介绍 灵感来源 在掘金看到了一篇<用Node + EJS写一个爬虫脚本每天定时女朋友发一封暖心邮件>后, 在评论区偶然 ...
- 【手写系列】写一个迷你版的Tomcat
前言 Tomcat,这只3脚猫,大学的时候就认识了,直到现在工作中,也常会和它打交道.这是一只神奇的猫,今天让我来抽象你,实现你! Tomcat Write MyTomcat Tomcat是非常流行的 ...
- 写一个爬虫爬取boss直聘网站
好的,我可以为您简要介绍如何编写一个爬虫来爬取 BOSS 直聘网站. 首先,您需要准备好以下几个东西: 安装 Python,并使用 pip 安装爬虫所需的库,如 requests 和 Beautifu ...
- 写一个爬虫,可以爬取百度文库内容
爬取百度文库内容需要使用爬虫技术.以下是一个简单的 Python 爬虫示例: import requestsurl ="https://wenku.baidu.com/view/your_d ...
- 写一个爬虫来获取地铁信息数据
用面向对象的方法来获取地铁信息数据 写在前面 具体代码如下 代码说明 这是说明 写在前面 最近在知乎上看到一篇关于地铁数据的分析,该篇文章很全面的分析了大陆(包括澳门香港)有地铁城市的分布.线路.站点 ...
最新文章
- 深入浅出Java垃圾回收机制
- 亿级流量架构之服务限流思路与方法
- JPA HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError
- 基于笛卡尔坐标系下的三边定位的研究(TOA方式定位)
- 心路历程(五)-find work and find house
- Intellj IDEA 注册码 2018
- 可以改位置吗_恒大文化旅游城售楼部位置外地人可以买吗优选好房泗洪
- Django 入门初探
- linux下导入mysql数据库命令
- jsp简单案例(供小白学习)
- 如何制作扫描连接WIFI二维码,手机扫码即可一键连接无线WIFI网络
- 机器学习(七)白化whitening
- LA3713 Astronauts
- JavaFX中嵌入谷歌Chromium内核
- 正则表达式可视化校验工具Regulex
- 如何关闭IE浏览器安全设置检查功能
- 【帧率倍频】基于FPGA的视频帧率倍频系统verilog开发实现
- Arcgis选择自己想要的区域地图
- LeetCode 460. LFU 缓存 -- 哈希查询+双向链表
- 我是如何记笔记的--谈谈自己的学习方法
热门文章
- DCMTK:将VeriLUM CCx_xx.dat文件转换为DCMTK显示文件
- DCMTK:查询/检索服务类用户(C-GET操作)
- VTK:Math之MatrixInverse
- ListElement QML类型
- C语言实现镜子mirror算法(附完整源码)
- C++ 中的 new/delete 和 new[]/delete[]
- java 减法_java 加减法2
- 怎么把线稿提取出来_ps提取线稿教程(ps怎么把图片的线稿弄出来)
- 如何找到设备的guid_如何禁止win10自动更新显卡驱动
- 处理时间_4_计算时间列所在的周的序号