整合 WebMagic

使用 WebMagic 进行网页爬取并入库

本文档详细介绍如何使用 Java 和 WebMagic 进行网页爬取,包括添加依赖项、创建 PageProcessor 进行网页解析、创建 Pipeline 将爬取的数据存入数据库,以及运行爬虫的过程。

示例目标网页:https://www.sis.hawaii.edu/uhdad/avail.classes

1. 添加依赖项

首先,在 pom.xml 文件中添加 WebMagic 所需的依赖项,包括 WebMagic 核心库和扩展库。为避免冲突,排除了 slf4j-log4j12 依赖项。

<dependency>
  <groupId>us.codecraft</groupId>
  <artifactId>webmagic-core</artifactId>
  <version>0.9.1</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.9.1</version>
  <exclusions>
    <exclusion>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
    </exclusion>
  </exclusions>
</dependency>

推荐使用 0.9.1 版本,该版本兼容 JDK 1.8 并支持 SSL v3。

2. 创建 PageProcessor 进行网页解析

接下来,创建一个 PageProcessor 实现类,用于定义网页的处理逻辑。在此示例中,从指定的 CSS 选择器中提取链接和名称。

import java.util.List;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

public class InstitutionProcessor implements PageProcessor {

  private Site site = Site.me().setRetryTimes(3).setSleepTime(10000);

  @Override
  public void process(Page page) {
    String selector = "ul.institutions li a";
    List<String> links = page.getHtml().css(selector, "href").all();
    List<String> names = page.getHtml().css(selector, "text").all();

    page.putField("links", links);
    page.putField("names", names);
  }

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

3. 创建 Pipeline 将数据存入数据库

创建一个 Pipeline 实现类,用于将爬取到的数据保存到数据库。在此示例中,使用 Db 类进行数据库操作,并使用 SnowflakeIdGenerator 生成唯一的 ID。

import java.util.List;
import com.litongjava.data.utils.SnowflakeIdGenerator;
import com.litongjava.jfinal.plugin.activerecord.Db;
import com.litongjava.jfinal.plugin.activerecord.Record;
import lombok.extern.slf4j.Slf4j;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

@Slf4j
public class InstitutionPipeline implements Pipeline {

  @Override
  public void process(ResultItems resultItems, Task task) {
    List<String> links = resultItems.get("links");
    List<String> names = resultItems.get("names");
    // 插入数据库
    for (int i = 0; i < links.size(); i++) {
      String link = links.get(i);
      String[] split = link.split("=");
      if (split.length < 2) {
        continue;
      }
      String abbrName = split[1];
      Integer count = Db.queryInt("select count(1) from institution where abbr_name=?", abbrName);
      if (count > 0) {
        continue;
      } else {
        Record record = new Record();
        record.put("id", new SnowflakeIdGenerator(0, 0).generateId());
        record.put("abbr_name", abbrName);
        record.put("name", names.get(i));
        boolean saved = Db.save("institution", record);
        log.info("Saved {},{}", abbrName, saved);
      }
    }
  }
}

4. 运行爬虫

最后,通过指定要爬取的 URL,并添加 PageProcessorPipeline 来运行爬虫。

package com.litongjava.uh.courses.processor;

import org.junit.Test;
import com.litongjava.uh.courses.pipeline.InstitutionPipeline;
import us.codecraft.webmagic.Spider;

public class SpiderInstitutionTest {

  @Test
  public void test() {
    String url = "https://www.sis.hawaii.edu/uhdad/avail.classes";
    Spider.create(new InstitutionProcessor())
        // 添加目标 URL
        .addUrl(url)
        // 添加自定义 Pipeline
        .addPipeline(new InstitutionPipeline())
        // 启用 5 个线程并运行爬虫
        .thread(5).run();
  }
}

通过上述步骤,我们成功创建了一个完整的 WebMagic 爬虫示例,包括网页爬取和数据入库。