Java爬虫案例实战-webmagic抓取segmentfault博客文章

avatar 2021年06月13日15:35:10 0 256 views

本文介绍一下使用webmagic爬虫框架来抓取互联网上的博客文章。

webmagic是一个十分简单的java爬虫框架。

官方文档地址:http://webmagic.io

代码地址:https://github.com/saysky/blog-spider

完整代码可以从上面github里获取,框架采用springboot+jpa+webmagic实现

processor(负责解析页面,并传数据给pipeline)、

pipeline(负责处理数据,如插入数据库)

spider(负责创建爬虫线程,设置队列、pipeline和processor等)

这里主要介绍这三个类的实现。

 

一、核心代码

1、SegmentfaultPostPageProcessor

package com.liuyanzhao.crawler.component.processor;

import com.liuyanzhao.crawler.entity.Post;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.util.List;

/**
 * 文章页面解析
 *
 * @author 言曌
 * @date 2021/6/13 12:58 下午
 */
@Service
public class SegmentfaultPostPageProcessor implements PageProcessor {

    @Autowired
    private Site site;

    /**
     * 页面分析
     * 使用原生api的jsoup
     *
     * @param page
     */
    public void process(Page page) {
        Html html = page.getHtml();

        // 解析列表页面的所有链接
        List<Selectable> nodes = html.css("h2.blog-type-common").nodes();
        if (nodes.size() > 0) {
            List<String> links = html.css("h2.blog-type-common").links().all();
            System.out.println(links);
            page.addTargetRequests(links);
            // 解析下一页的URL
            List<Selectable> pageNode = html.css("ul.pagination > li.next").nodes();
            if (pageNode.size() > 0) {
                String nextPageUrl = pageNode.get(0).links().get();
                page.addTargetRequest(nextPageUrl);
                System.out.println(pageNode);
            }
            // 不向pipeline传递数据
            page.getResultItems().setSkip(true);
        }
        // 解析详情页面
        else {
            // 解析文章标题
            String title = html.css("div.card-body>h1>a", "text").get();
            // 解析文章内容
            String content = html.css("article.article-content").get();
            // 解析文章作者用户名
            String author = html.css("strong.align-self-center", "text").get();
            // 页面URL
            String url = page.getUrl().get();
            Post post = new Post();
            post.setTitle(title);
            post.setContent(content);
            post.setAuthor(author);
            post.setSourceUrl(url);
            // 把数据传递给pipeline,由pipeline保存到磁盘
            page.putField("post", post);
        }
    }

    @Override
    public Site getSite() {
        return site;
    }
}

 

2、SegmentfaultPostPipeline

package com.liuyanzhao.crawler.component.pipeline;

import cn.hutool.http.HtmlUtil;
import com.liuyanzhao.crawler.dao.PostDao;
import com.liuyanzhao.crawler.entity.Post;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.ListUtils;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

import java.util.Date;
import java.util.List;

/**
 * 采集segmentfault的文章
 *
 * @author 言曌
 * @date 2021/6/13 1:59 下午
 */
@Component
public class SegmentfaultPostPipeline implements Pipeline {

    @Autowired
    private PostDao postDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void process(ResultItems resultItems, Task task) {
        Post post = resultItems.get("post");
        // 摘要,截取200个字符
        String summaryText = HtmlUtil.cleanHtmlTag(post.getContent());
        if (summaryText.length() > 200) {
            summaryText = summaryText.substring(0, 200) + "...";
        }
        post.setSummary(summaryText);
        post.setCreateTime(new Date());
        post.setSourceSite("segmentfault");
        // 把数据存储到数据库
        // 判断URL是否已经入库,如果不存在再入库
        List<Post> postList = postDao.findBySourceUrl(post.getSourceUrl());
        if (ListUtils.isEmpty(postList)) {
            postDao.save(post);
        }
    }
}

 

3、SegmentfaultPostSpider

package com.liuyanzhao.crawler.component.spider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.scheduler.Scheduler;

/**
 * @author 言曌
 * @date 2021/6/13 2:02 下午
 */
@Component
public class SegmentfaultPostSpider {

    @Autowired
    private PageProcessor pageProcessor;

    @Autowired
    private Pipeline pipeline;

    @Autowired
    private Scheduler scheduler;

    public static final String START_URL = "https://segmentfault.com/t/java/blogs";

    public void doCrawler() {
        Spider.create(pageProcessor)
                // 设置自定义的pipeline
                .addPipeline(pipeline)
                // 配置scheduler,指定使用布隆过滤器
                .setScheduler(scheduler)
                // 设置起始URL
                .addUrl(START_URL)
                // 启动爬虫
                .start();
    }
}

 

二、效果图

结果如下

可能会遇到的问题

请求页面超时,访问页面失败,解决办法待补充

 

 

 

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
avatar

发表评论

avatar 登录者:匿名
可以匿名评论或者登录后台评论,评论回复后会有邮件通知

  

已通过评论:0   待审核评论数:0