
网络爬虫本质是模拟浏览器的行为,向目标网站发送请求、接收响应,并从响应数据中提取有效信息的程序。针对小说爬取场景,其核心流程可分为四步:
Java 实现爬虫的核心依赖两类技术:一是基于 HttpURLConnection 或第三方库(如 HttpClient)的 HTTP 通信能力;二是基于 JSoup 的 HTML 解析能力,这也是本文实战的核心技术栈。
xml
<!-- HTTP 客户端 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<!-- HTML 解析工具 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.4</version>
</dependency>
<!-- 字符编码处理 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>java
运行
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* HTTP 请求工具类:封装 GET 请求,获取页面源码
*/
public class HttpUtils {
// 模拟浏览器请求头,避免被反爬识别
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36";
/**
* 发送 GET 请求获取页面源码
* @param url 目标小说页面 URL
* @return 页面 HTML 源码
*/
public static String getHtml(String url) {
// 1. 创建 HTTP 客户端对象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2. 构建 GET 请求
HttpGet httpGet = new HttpGet(url);
// 设置请求头,模拟浏览器
httpGet.setHeader("User-Agent", USER_AGENT);
httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
CloseableHttpResponse response = null;
try {
// 3. 发送请求,获取响应
response = httpClient.execute(httpGet);
// 4. 处理响应状态码(200 表示成功)
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
// 5. 解析响应内容为字符串(指定编码,避免乱码)
return EntityUtils.toString(entity, "UTF-8");
} else {
System.out.println("请求失败,状态码:" + response.getStatusLine().getStatusCode());
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
// 6. 关闭资源,避免内存泄漏
try {
if (response != null) {
response.close();
}
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}java
运行
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.FileWriter;
import java.io.IOException;
import java.util.regex.Pattern;
/**
* 小说解析工具类:从 HTML 中提取标题、正文并保存
*/
public class NovelParser {
// 匹配小说正文的正则(可根据目标网站调整)
private static final Pattern CONTENT_PATTERN = Pattern.compile("\\s{2,}");
/**
* 解析小说章节页面
* @param html 页面源码
* @param savePath 本地保存路径
*/
public static void parseNovel(String html, String savePath) {
if (html == null || html.isEmpty()) {
System.out.println("页面源码为空,解析失败");
return;
}
// 1. 将 HTML 源码解析为 Document 对象(JSoup 核心)
Document doc = Jsoup.parse(html);
// 2. 提取小说标题(根据目标网站的 CSS 选择器调整)
Element titleElement = doc.selectFirst("h1.novel-title");
String novelTitle = titleElement != null ? titleElement.text() : "未知标题";
// 3. 提取小说正文(核心:通过 CSS 选择器定位正文区域)
Element contentElement = doc.selectFirst("div.novel-content");
if (contentElement == null) {
System.out.println("未找到正文区域,解析失败");
return;
}
// 4. 清理正文格式(去除多余空格、换行)
String novelContent = contentElement.text().replaceAll(CONTENT_PATTERN.pattern(), "\n");
// 5. 保存到本地文件
saveNovel(novelTitle, novelContent, savePath);
}
/**
* 保存小说内容到本地
* @param title 标题
* @param content 正文
* @param savePath 保存路径
*/
private static void saveNovel(String title, String content, String savePath) {
try (FileWriter writer = new FileWriter(savePath, true)) {
// 写入标题 + 分隔线
writer.write("=====" + title + "=====\n");
// 写入正文
writer.write(content + "\n\n");
System.out.println("小说章节「" + title + "」保存成功,路径:" + savePath);
} catch (IOException e) {
System.out.println("保存小说失败:" + e.getMessage());
e.printStackTrace();
}
}
}java
运行
/**
* 小说爬虫主程序
*/
public class NovelCrawler {
public static void main(String[] args) {
// 目标小说章节 URL(需替换为实际可访问的小说页面)
String novelUrl = "https://example.com/novel/chapter/123";
// 本地保存路径
String savePath = "D:/novel/test_novel.txt";
// 1. 发送 HTTP 请求,获取页面源码
String html = HttpUtils.getHtml(novelUrl);
// 2. 解析并保存小说内容
NovelParser.parseNovel(html, savePath);
}
}HttpUtils 中设置 User-Agent 等请求头,是模拟浏览器行为的核心,可避免大部分基础反爬机制;Jsoup.parse(html) 将字符串转为可操作的 DOM 对象,selectFirst()/select() 通过 CSS 选择器定位元素,这是 HTML 解析的关键;try-with-resources 自动关闭文件流,避免资源泄漏。Java 爬虫发送请求的本质是遵循 HTTP 协议与服务器交互:
HttpURLConnection(JDK 原生)或 HttpClient(第三方库)负责构建请求报文,包含 URL、请求方法(GET/POST)、请求头(User-Agent、Cookie 等);小说网站的内容以 HTML 形式返回,JSoup 是解析 HTML 的核心工具,其原理是:
div.novel-content)、XPath 定位目标元素;.text())或属性(.attr("href")),得到小说标题、正文、下一章链接等数据。实际爬取小说时,常会遇到反爬机制,需针对性处理:
Thread.sleep(1000)),避免短时间高频请求;ExecutorService)提高爬取效率;原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。