WebMagic JAVA爬虫框架

官方文档

WebMagic总体架构

WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。

  1. Downloader

Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了Apache HttpClient作为下载工具。

  1. PageProcessor

PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。

在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。

  1. Scheduler

Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。

除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。

  1. Pipeline

Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。

Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。

爬取人民网新闻

新闻类别
list

实现

使用STS构建环境

  • 创建Spring Starter Project

  • 加入JPA,MySQL,Web依赖

  • 导入WebMagic依赖
    注意 :

    1. WebMagic 的核心包的log4j会与jpa的log4j冲突,需要排除WebMagic的jar
    2. 排除后会报org.apache.commons.lang.StringUtils找不到,需要导入commons-lang依赖
    <dependency>
        <groupId>us.codecraft</groupId>
        <artifactId>webmagic-core</artifactId>
        <version>0.5.3</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
    <dependency>
        <groupId>us.codecraft</groupId>
        <artifactId>webmagic-extension</artifactId>
        <version>0.5.3</version>
    </dependency>
    
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>
    

代码

  • PageProcessor 抽取内容
@Service
public class NewsProcessor implements PageProcessor {
    // 入口url
    public static final String URL_ENTER = "http://bj.people.com.cn/";
    // 类别导航
    private String URL_INDEX = "http://bj\\.people\\.com\\.cn/GB/\\d+/index\\.html";
    // 列表
    private String URL_LIST = "http://bj\\.people\\.com\\.cn/GB/\\d+/index\\d*\\.html";
    // 文章
    private String URL_POST = "http://bj\\.people\\.com\\.cn/n2/2016/\\d+/.+\\.html";
    // 设置
    private Site site = Site.me().setRetryTimes(10).setSleepTime(1000).setCycleRetryTimes(3);

    @Override
    public void process(Page page) {
        if (page.getUrl().get().equals(URL_ENTER)) {
            // 类别
            page.addTargetRequests(page.getHtml().xpath("//div[@class='pd_nav w1000 white  clear clearfix']").links().regex(URL_INDEX).all());
            System.out.println("enter"+page.getUrl().get());
        } else {
            System.out.println("enter"+page.getUrl().get());
            // 列表页
            if (page.getUrl().regex(URL_LIST).match()) {
                page.addTargetRequests(page.getHtml().xpath("//div[@class='ej_list_box clear']").links().regex(URL_POST).all());
                page.addTargetRequests(page.getHtml().links().regex(URL_LIST).all());
            } else {
                // 匹配当前域名
                String currentDomain = page.getUrl().regex("http.+\\.com\\.cn").toString();
                String title = page.getHtml().xpath("//div[@class='clearfix w1000_320 text_title']/h1/text()").toString();
                String contentTime = page.getHtml().xpath("//div[@class='box01']/div[@class='fl']/text()").regex("\\d{4}年\\d{2}月\\d{2}日\\s*\\d{2}:\\d{2}").toString();
                String content = page.getHtml().xpath("//div[@class='box_con']").toString();
                List<String> imgList = page.getHtml().xpath("//div[@class='box_con']//img/@src").all();
                List<String> result = new ArrayList<>();
                for (String img : imgList) {
                    // 匹配是否是绝对路劲
                    Pattern r = Pattern.compile("^http");
                    Matcher m = r.matcher(img);
                    if (!m.find()) {
                        // 不是绝对路径 拼接当前域名
                        result.add(currentDomain + img);
                    } else {
                        result.add(img);
                    }
                }
                News news = new News();
                news.setSourceUrl(page.getUrl().regex(URL_POST).toString());
                news.setContent(content);
                news.setContentTime(contentTime);
                news.setTitle(title);
                news.setImage(new Gson().toJson(result));
                if (news.getTitle() == null) {
                    page.setSkip(true);
                } else {
                    page.putField("news", news);
                }
            }
        }
    }

    @Override
    public Site getSite() {
        return site;
    }
}
  • Pipeline 持久化数据
@Service
public class NewsPipeline implements Pipeline {
    @Autowired
    private NewsService newsService;

    @Override
    public void process(ResultItems resultItems, Task task) {
        News news = (News) resultItems.get("news");
        if (!newsService.isExist(news)) {
            newsService.create(news);
        }
    }
}
  • 启动爬虫
@RequestMapping("/start")
private String start() {
    Spider.create(newsProcessor)// 创建抽取内容类
            .addUrl(NewsProcessor.URL_ENTER)// 添加入口url
            .addPipeline(newsPipeline)// 添加持久化类
            .thread(5)// 开启5个线程
            .run();// 启动
    return "success";
}

结果

  • 保存的数据


    新闻数据
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 今天由于项目需要,简单的配置了一下ssm框架,maven配置所需包,可直接粘贴复制 maven依赖 <depend...
    胡GaQue阅读 625评论 0 4
  • 工作到现在快要1年半了,一直没有时间自己从头搭建个框架,这个周末实在是无聊,真的不想打lol了,(黑色玫瑰开黑的喊...
    MacSam阅读 5,917评论 7 20
  • 简书 Wwwwei转载请注明原创出处,谢谢! 一些概念 Maven 一个项目管理工具,简单的理解为一种标准化的方式...
    Wwwwei阅读 9,157评论 13 57
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 本文主要讲解SSM(Spring+SpringMVC+MyBatis)框架搭建Java web项目的开发环境。 开...
    AceKitty阅读 2,559评论 1 14