WebMagic JAVA爬虫框架

作者: 茗同学 | 来源:发表于2016-12-22 13:13 被阅读1380次
    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";
    }
    

    结果

    • 保存的数据


      新闻数据

    相关文章

      网友评论

        本文标题:WebMagic JAVA爬虫框架

        本文链接:https://www.haomeiwen.com/subject/efacvttx.html