基于webmagic实现爬取博客园的所有精品文章

最近有一些工作上的需要,需要接触到爬虫来爬取数据。之前有使用过Python实现一个很简单的爬虫Demo,这次由于公司使用的是Java爬虫,基于webmagic框架去实现的爬虫。于是就参考了资料自己学习搭载了一个Demo,爬取了博客园所有精品文章的数据。


首先稍微了解了一下webmagic框架,下图是webmagic的流程示意图。

基于webmagic实现爬取博客园的所有精品文章_第1张图片

 功能覆盖整个爬虫的生命周期(链接提取、页面下载、内容抽取、持久化)。而其中PageProcesser就是整个爬虫的核心部分,也就是链接提取、内容抽取和持久化的具体逻辑设计。webmagic也简化了其他过程,它希望开发者可以专注于核心逻辑部分设计,而对于我这样的初学者也很容易就上手了。


模型类设计

public class CnBlogs {

	// 标题
	private String title;
	// 作者
	private String author;
	// 发布日期
	private String dateTime;
	// 地址
	private String url;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getDateTime() {
		return dateTime;
	}

	public void setDateTime(String dateTime) {
		this.dateTime = dateTime;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	@Override
	public String toString() {
		return "CnBlogs [title=" + title + ", author=" + author + ", dateTime=" + dateTime + ", url=" + url + "]";
	}
	
}

PageProcessor类(核心逻辑)

/*
 *@author HangDie
 *@date 2018/07/17
 */
public class CnBlogProcessor implements PageProcessor {

	// 抓取网站的相关配置,包括:编码、抓取间隔、重试次数等
	private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
	// 文章数量
	private static int size = 0;
	// 文章集合
	private static List cnBlogses = new ArrayList<>();

	// 抽取逻辑类
	@Override
	public void process(Page page) {
		// 如果是精华文章的列表页
		if (page.getUrl().regex("https://www.cnblogs.com/pick/.*").match()) {
			List list = page.getHtml().xpath("//div[@id='post_list']").links().regex("^(.*\\.html)$").all();
			// 去重复URL
			list = list.stream().distinct().collect(Collectors.toList());
			// 添加到待爬取队列
			page.addTargetRequests(list);
			page.addTargetRequests(page.getHtml().xpath("//div[@class='pager']").links().all());
		} else {
			size++;
			CnBlogs cnBlogs = new CnBlogs();
			// 标题
			cnBlogs.setTitle(page.getHtml().xpath("//div[@class='post']/h1[@class='postTitle']/a/text()").get());
			// 作者
			cnBlogs.setAuthor(page.getHtml().xpath("//a[@id='Header1_HeaderTitle']/text()").get());
			// 发布日期
			cnBlogs.setDateTime(page.getHtml().xpath("//div[@class='postDesc']/span[@id='post-date']/text()").get());
			// URL
			cnBlogs.setUrl(page.getUrl().toString());

			synchronized (cnBlogses) {
				cnBlogses.add(cnBlogs);
			}
		}
	}

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

通过POI写入Excel输出结果

    public static void printExcel(List cnBlogses) {
		System.out.println("正在写入Excel...");
		// 定义表头
		String[] title = { "序号", "标题", "作者", "发布日期", "链接" };
		// 创建excel工作簿
		HSSFWorkbook workbook = new HSSFWorkbook();
		// 创建工作表sheet
		HSSFSheet sheet = workbook.createSheet();
		// 创建第一行
		HSSFRow row = sheet.createRow(0);
		HSSFCell cell = null;
		// 插入第一行数据的表头
		for (int i = 0; i < title.length; i++) {
			cell = row.createCell(i);
			cell.setCellValue(title[i]);
		}
		int idx = 1;
		for (CnBlogs cnBlogs : cnBlogses) {
			HSSFRow nrow = sheet.createRow(idx);
			HSSFCell ncell = nrow.createCell(0);
			ncell.setCellValue(idx++);
			ncell = nrow.createCell(1);
			ncell.setCellValue(cnBlogs.getTitle());
			ncell = nrow.createCell(2);
			ncell.setCellValue(cnBlogs.getAuthor());
			ncell = nrow.createCell(3);
			ncell.setCellValue(cnBlogs.getDateTime());
			ncell = nrow.createCell(4);
			ncell.setCellValue(cnBlogs.getUrl());
		}

		// 设置自动列宽
		for (int i = 0; i < title.length; i++) {
			sheet.autoSizeColumn(i);
			sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 16 / 10);
		}
		// 创建excel文件
		File file = new File("C://Users/HangDie/Desktop/result.xls");
		try {
			file.createNewFile();
			// 将excel写入
			FileOutputStream stream = FileUtils.openOutputStream(file);
			workbook.write(stream);
			stream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("写入完成");
	}

爬取结果(采用Excel存储)

发现有部分标题或者数据丢失,实际上是因为有一些文章已经过于老旧了,其页面元素也有所改动。后续可能会收集一下几种标签元素规则,做一个通配。

你可能感兴趣的:(基于webmagic实现爬取博客园的所有精品文章)