前言:简单的小爬虫,采集到页面后,通过正则表达式对页面中的详情url及图片url进行解析,最终把图片保存到本地。同时为了提高效率,增加了线程池和简单的文件日志记录防重复。
项目中集中使用了hutool的插件功能,也可做学习使用,可参考hutool的api文档。hutool传送门
代码如下:
package com.zn;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
/**
* 图片网站采集并下载图片示例
*
* @author lds
*
*/
public class ImgGatherDemo {
/* 建立线程池操作,可根据任务量定义线程大小 */
private static ExecutorService executor = ThreadUtil.newExecutor(12);
public static void main(String[] args) {
List<Integer> numList = new ArrayList<Integer>();
for (int i = 2; i < 14; i++) {
numList.add(i);
}
for (Integer num : numList) {
executor.execute(() -> {
listInfo(num);
});
}
executor.shutdown();
}
/* 列表页地址 */
private static String listPage = "https://www.ooxx.com/img/";
/* 列表页正则,主要获取到详情url */
private static String list_reg = ".*?<article.*?>.*?<header><h2><a href=\\\"(.*?)\\\".*?</article>";
/**
* 采集列表页,并获得详情页url
*
* @param curPage 页码
*/
public static void listInfo(int curPage) {
System.out.println(curPage + "---------------------" + Thread.currentThread().getName());
String pageStr = HttpUtil.get(listPage + curPage);
List<String> infoList = ReUtil.findAllGroup1(list_reg, pageStr);
for (String infoUrl : infoList) {
getInfo(infoUrl, curPage);
}
}
/* 详情页分页区域正则 */
private static String info_reg1 = "<div.*?article-paging\\\">(.*?)</div>";
/* 详情页分页区域正则,获取各分页url */
private static String info_reg2 = "<a href=\\\"(.*?)\\\".*?</a>";
public static void getInfo(String infoUrl, int pageNum) {
String pageStr = HttpUtil.get(infoUrl);
getPic(pageStr, pageNum);
String pagNumStr = ReUtil.getGroup1(info_reg1, pageStr);
List<String> infoChildList = ReUtil.findAllGroup1(info_reg2, pagNumStr);
if (infoChildList == null || infoChildList.isEmpty()) {
System.out.println("列表为空!" + pageNum + "----" + infoUrl);
return;
}
/* 用txt文件记录采集日志,可防止图片重复采集,影响速度 */
String picLogPath = "E:\\game\\zn\\picLogUrl--" + pageNum + ".txt";
for (String infoChildUrl : infoChildList) {
if (recordArtUrl(infoChildUrl, picLogPath)) {
continue;
}
System.out.println(pageNum + "----" + infoChildUrl);
String pageChildStr = HttpUtil.get(infoChildUrl);
getPic(pageChildStr, pageNum);
}
}
/* 详情页图片区域正则--防止页面复杂度较高或混乱 */
private static String pic_reg1 = "<article.*?>(.*?)</article>";
/* 获取图片地址url正则 */
private static String pic_reg2 = "<img.*?src=\\\"(.*?)\\\".*?>";
private static String localDir = "E:\\game\\hs-zn\\pic\\";
/**
* 获取图片url,并且根据列表页分页进行文件夹分类,同时下载图片
* @param pageStr 详情页内容
* @param pageNum 列表页页码
*/
public static void getPic(String pageStr, int pageNum) {
String articleStr = ReUtil.getGroup1(pic_reg1, pageStr);
String imgUrl = ReUtil.getGroup1(pic_reg2, articleStr);
/* 图片存放分文件夹 */
String dowFilePath = localDir + pageNum;
if (!FileUtil.exist(dowFilePath)) {
FileUtil.mkdir(dowFilePath);
}
if (StrUtil.isEmpty(imgUrl)) {
return;
}
/* 图片过滤,此处不要jpg图片 */
if (imgUrl.contains(".jpg")) {
return;
}
/* 图片下载,并且存放到指定文件夹 */
HttpUtil.downloadFile(imgUrl, dowFilePath);
}
/**
* 记录下载图片的url,并且判断是否已下载
* @param infoUrl 下载图片url
* @param picLogPath 日志地址
* @return true 已下载,false 未下载
*/
private static boolean recordArtUrl(String infoUrl, String picLogPath) {
if (!FileUtil.exist(picLogPath)) {
FileUtil.writeUtf8String("", picLogPath);
}
List<String> artList = FileUtil.readUtf8Lines(picLogPath);
if (artList.contains(infoUrl)) {
return true;
}
artList.add(infoUrl);
FileUtil.writeUtf8Lines(artList, picLogPath);
return false;
}
}