您好,登录后才能下订单哦!
# 怎么用jsoup实现抓取图片爬虫
## 前言
在当今互联网时代,网络爬虫技术已经成为获取网络数据的重要手段之一。其中,图片爬虫作为专门用于抓取网络图片的工具,在数据采集、内容分析等领域有着广泛的应用。本文将详细介绍如何使用Java的jsoup库来实现一个高效的图片爬虫。
## 一、jsoup简介
### 1.1 什么是jsoup
jsoup是一款Java编写的HTML解析器,它能够直接解析某个URL地址或HTML文本内容。jsoup提供了一套非常便捷的API,可以通过DOM、CSS以及类似jQuery的操作方法来取出和操作数据。
主要功能包括:
- 从URL、文件或字符串中抓取和解析HTML
- 使用DOM遍历或CSS选择器查找和提取数据
- 操作HTML元素、属性和文本
- 清除用户提交的内容以防止XSS攻击
### 1.2 jsoup的优势
相比于其他HTML解析库,jsoup具有以下优势:
1. 简单易用的API
2. 支持CSS选择器语法
3. 能够处理不规范的HTML(类似浏览器)
4. 内置HTML清理功能
5. 轻量级且性能良好
## 二、环境准备
### 2.1 安装jsoup
要在项目中使用jsoup,可以通过以下方式添加依赖:
Maven项目:
```xml
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.16.1</version>
</dependency>
Gradle项目:
implementation 'org.jsoup:jsoup:1.16.1'
或者直接下载jar包:jsoup官网下载
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class BasicExample {
public static void main(String[] args) throws Exception {
// 从URL获取HTML文档
Document doc = Jsoup.connect("https://example.com").get();
// 获取页面标题
String title = doc.title();
System.out.println("Title: " + title);
// 使用CSS选择器获取元素
String firstParagraph = doc.select("p").first().text();
System.out.println("First paragraph: " + firstParagraph);
}
}
一个基本的图片爬虫通常包含以下步骤: 1. 发送HTTP请求获取网页内容 2. 解析HTML文档 3. 提取图片URL 4. 下载图片到本地 5. 处理分页或链接跳转
网页中的图片通常以以下几种形式存在:
- <img>
标签的src属性
- <img>
标签的data-src属性(懒加载)
- CSS背景图片
- JavaScript动态加载的图片
我们的爬虫主要关注<img>
标签的src和data-src属性。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
public class BasicImageCrawler {
// 图片保存目录
private static final String SAVE_DIR = "downloaded_images";
public static void main(String[] args) {
String url = "https://example.com";
try {
// 创建保存目录
Files.createDirectories(Paths.get(SAVE_DIR));
// 获取HTML文档
Document doc = Jsoup.connect(url).get();
// 选择所有img标签
Elements imgElements = doc.select("img");
for (Element img : imgElements) {
// 获取图片URL
String imgUrl = img.absUrl("src");
// 处理data-src(懒加载情况)
if (imgUrl.isEmpty()) {
imgUrl = img.absUrl("data-src");
}
if (!imgUrl.isEmpty()) {
System.out.println("Found image: " + imgUrl);
downloadImage(imgUrl);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void downloadImage(String imgUrl) throws IOException {
// 从URL中提取文件名
String fileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1);
// 防止文件名无效
if (fileName.isEmpty() || !fileName.contains(".")) {
fileName = "image_" + System.currentTimeMillis() + ".jpg";
}
// 下载图片
try (InputStream in = new URL(imgUrl).openStream()) {
Files.copy(in, Paths.get(SAVE_DIR, fileName));
System.out.println("Downloaded: " + fileName);
} catch (Exception e) {
System.err.println("Failed to download: " + imgUrl);
}
}
}
Jsoup.connect(url).get()
- 建立连接并获取HTML文档doc.select("img")
- 使用CSS选择器选取所有img标签img.absUrl("src")
- 获取绝对URL(相对于当前页面)许多现代网站使用懒加载技术,初始时图片并不在src属性中,而是在data-src等自定义属性中。我们需要同时检查这些属性:
// 扩展的图片URL获取方法
private static String getImageUrl(Element img) {
String[] attrNames = {"src", "data-src", "data-original", "data-srcset"};
for (String attr : attrNames) {
String url = img.absUrl(attr);
if (!url.isEmpty()) {
return url;
}
}
return "";
}
要实现网站的多页面爬取,我们需要发现并跟踪链接:
// 递归爬取页面
private static void crawlPage(String url, Set<String> visitedUrls, int depth) throws IOException {
if (depth <= 0 || visitedUrls.contains(url)) {
return;
}
visitedUrls.add(url);
System.out.println("Crawling: " + url);
try {
Document doc = Jsoup.connect(url)
.timeout(10000)
.get();
// 下载图片
downloadImagesFromDoc(doc);
// 查找并跟踪其他链接
Elements links = doc.select("a[href]");
for (Element link : links) {
String nextUrl = link.absUrl("href");
if (isValidUrl(nextUrl)) {
crawlPage(nextUrl, visitedUrls, depth - 1);
}
}
} catch (IOException e) {
System.err.println("Failed to crawl: " + url);
}
}
// 简单的URL验证
private static boolean isValidUrl(String url) {
return url.startsWith("http") && !url.contains("logout") && !url.contains("signout");
}
许多网站会阻止默认的Java用户代理,我们需要设置合理的请求头:
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
.timeout(10000)
.referrer("https://www.google.com")
.get();
我们可以根据图片属性进行过滤和分类:
// 只下载大于指定尺寸的图片
private static boolean shouldDownload(Element img) {
String widthStr = img.attr("width");
String heightStr = img.attr("height");
try {
int width = widthStr.isEmpty() ? 0 : Integer.parseInt(widthStr);
int height = heightStr.isEmpty() ? 0 : Integer.parseInt(heightStr);
// 只下载宽度大于100像素的图片
return width > 100 || height > 100;
} catch (NumberFormatException e) {
return true;
}
}
使用线程池提高下载速度:
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static void downloadImageAsync(String imgUrl) {
executor.submit(() -> {
try {
downloadImage(imgUrl);
} catch (IOException e) {
System.err.println("Failed to download: " + imgUrl);
}
});
}
jsoup本身没有内置连接池,但我们可以实现简单的重用:
private static Connection getConnection(String url) {
return Jsoup.connect(url)
.userAgent("Mozilla/5.0...")
.timeout(10000);
}
使用Set存储已访问URL和已下载图片的hash:
private static Set<String> downloadedImages = new HashSet<>();
private static void downloadImage(String imgUrl) throws IOException {
// 检查是否已下载
String hash = Integer.toHexString(imgUrl.hashCode());
if (downloadedImages.contains(hash)) {
return;
}
// 下载逻辑...
// 添加到已下载集合
downloadedImages.add(hash);
}
try {
Document doc = Jsoup.connect(url)
.timeout(10000)
.get();
// 处理文档
} catch (SocketTimeoutException e) {
System.err.println("Timeout while fetching: " + url);
} catch (HttpStatusException e) {
System.err.println("HTTP error: " + e.getStatusCode() + " for URL: " + url);
} catch (IOException e) {
System.err.println("IO error while fetching: " + url);
}
使用SLF4J或Log4j记录爬取过程:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(ImageCrawler.class);
// 使用示例
logger.info("Starting to crawl: {}", url);
logger.warn("Failed to download image: {}", imgUrl, e);
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AdvancedImageCrawler {
private static final String SAVE_DIR = "downloaded_images";
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
private static final Set<String> visitedUrls = new HashSet<>();
private static final Set<String> downloadedImages = new HashSet<>();
public static void main(String[] args) {
String startUrl = "https://example.com";
int maxDepth = 2;
try {
Files.createDirectories(Paths.get(SAVE_DIR));
crawlPage(startUrl, maxDepth);
executor.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void crawlPage(String url, int depth) throws IOException {
if (depth <= 0 || visitedUrls.contains(url)) {
return;
}
visitedUrls.add(url);
System.out.println("Crawling: " + url + " at depth: " + depth);
try {
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0...")
.timeout(10000)
.get();
// 下载图片
Elements imgs = doc.select("img");
for (Element img : imgs) {
String imgUrl = getImageUrl(img);
if (!imgUrl.isEmpty() && shouldDownload(img)) {
downloadImageAsync(imgUrl);
}
}
// 递归爬取链接
Elements links = doc.select("a[href]");
for (Element link : links) {
String nextUrl = link.absUrl("href");
if (isValidUrl(nextUrl)) {
executor.submit(() -> {
try {
crawlPage(nextUrl, depth - 1);
} catch (IOException e) {
System.err.println("Error crawling: " + nextUrl);
}
});
}
}
} catch (IOException e) {
System.err.println("Failed to crawl: " + url);
}
}
// 其他辅助方法...
// getImageUrl(), shouldDownload(), isValidUrl(), downloadImageAsync()
// 参考前面章节的实现
}
在开发和使用网络爬虫时,必须注意以下事项:
// 在请求间添加延迟
Thread.sleep(1000); // 1秒延迟
本文详细介绍了如何使用jsoup实现一个功能完善的图片爬虫,从基础实现到高级功能,再到性能优化和异常处理。jsoup虽然是一个轻量级库,但配合Java强大的网络和IO能力,完全可以构建出强大的网络爬虫应用。
在实际应用中,请根据具体需求调整代码,并始终遵守网络道德和相关法律法规。希望本文能够帮助你快速掌握jsoup爬虫开发技术。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。