va爬虫可通过HttpClient获取网页,用Jsoup解析HTML,结合线程
一个Java爬虫涉及多个步骤,从设置开发环境到编写代码抓取和处理网页数据,以下是一个详细的指南,帮助你从头开始构建一个功能完善的Java爬虫。
环境准备
1 安装Java Development Kit (JDK)
确保你的系统已经安装了JDK,你可以从Oracle官网或OpenJDK下载并安装最新版本的JDK。
2 选择开发工具
常用的Java开发工具包括:
- Eclipse: 开源且功能强大的IDE。
- IntelliJ IDEA: 强大的智能IDE,有社区版和付费版。
- NetBeans: 另一个流行的开源IDE。
3 添加必要的库
为了简化HTTP请求和HTML解析,可以使用以下第三方库:
- Jsoup: 用于解析HTML的Java库,支持DOM操作和CSS选择器。
- Apache HttpClient: 用于发送HTTP请求。
- Selenium(可选): 如果需要处理动态加载的内容,如JavaScript渲染的页面。
你可以通过Maven或Gradle来管理这些依赖,使用Maven时,在pom.xml中添加:

<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependencies>
基本爬虫结构
一个基本的Java爬虫通常包括以下几个部分:
- 发送HTTP请求:获取网页内容。
- 解析HTML:提取所需的数据。
- 数据存储:将抓取的数据保存到文件、数据库或其他存储介质中。
- 多线程处理(可选):提高爬取效率。
1 发送HTTP请求
使用Jsoup可以简化HTTP请求和HTML解析的过程,以下是一个简单的示例:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class SimpleCrawler {
public static void main(String[] args) {
try {
// 发送HTTP GET请求
Document doc = Jsoup.connect("https://example.com").get();
// 打印网页标题
System.out.println("Title: " + doc.title());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2 解析HTML
使用Jsoup的CSS选择器,可以轻松提取网页中的特定元素,提取所有的链接:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class LinkExtractor {
public static void main(String[] args) {
try {
Document doc = Jsoup.connect("https://example.com").get();
Elements links = doc.select("a[href]");
for (Element link : links) {
System.out.println("Link: " + link.attr("href"));
System.out.println("Text: " + link.text());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3 数据存储
根据需求,你可以选择不同的存储方式:

- 文本文件:简单易行,适合小规模数据。
- CSV/Excel文件:适合表格数据。
- 数据库:如MySQL、MongoDB,适合大规模数据和复杂查询。
以下是将数据保存到CSV文件的示例:
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;
public class CsvCrawler {
public static void main(String[] args) {
try {
Document doc = Jsoup.connect("https://example.com").get();
Elements links = doc.select("a[href]");
FileWriter writer = new FileWriter("links.csv");
writer.append("URL,Text
");
for (Element link : links) {
writer.append(link.attr("href")).append(",")
.append(link.text()).append("
");
}
writer.flush();
writer.close();
System.out.println("Data saved to links.csv");
} catch (IOException e) {
e.printStackTrace();
}
}
}
进阶功能
1 多线程爬取
为了提高爬取速度,可以使用多线程并行处理多个URL,Java的ExecutorService可以方便地管理线程池。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.;
public class MultiThreadedCrawler {
private static final List<String> URLS = Arrays.asList(
"https://example.com",
"https://www.wikipedia.org",
"https://www.github.com"
);
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<String>> results = null;
try (FileWriter writer = new FileWriter("multi_threaded_links.csv")) {
writer.append("URL,Text
");
results = executor.invokeAll(URLS.stream()
.map(url -> (Callable<String>) () -> {
Document doc = Jsoup.connect(url).get();
Elements links = doc.select("a[href]");
StringBuilder sb = new StringBuilder();
for (Element link : links) {
sb.append(link.attr("href")).append(",")
.append(link.text()).append("
");
}
return sb.toString();
})
.collect(Collectors.toList()));
for (Future<String> result : results) {
writer.append(result.get());
}
System.out.println("Data saved to multi_threaded_links.csv");
} catch (InterruptedException | ExecutionException | IOException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
2 处理动态内容
有些网站使用JavaScript动态加载内容,Jsoup无法直接处理,这时可以使用Selenium模拟浏览器行为,以下是一个简单的Selenium示例:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.util.List;
public class SeleniumCrawler {
public static void main(String[] args) {
// 设置ChromeDriver路径
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
// 获取页面标题
System.out.println("Title: " + driver.getTitle());
// 提取所有链接
List<WebElement> links = driver.findElements(By.tagName("a"));
for (WebElement link : links) {
System.out.println("Link: " + link.getAttribute("href"));
System.out.println("Text: " + link.getText());
}
driver.quit();
}
}
注意:使用Selenium需要下载相应的浏览器驱动,如ChromeDriver,并确保驱动版本与浏览器版本匹配。
3 遵守Robots协议和延时策略
在进行爬取前,应检查目标网站的robots.txt文件,了解允许爬取的部分,为了避免对目标服务器造成过大压力,可以在请求之间加入延时。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class PoliteCrawler {
public static void main(String[] args) {
String url = "https://example.com";
Random random = new Random();
int delay = 1000 + random.nextInt(2000); // 1到3秒随机延时
try {
TimeUnit.MILLISECONDS.sleep(delay);
Document doc = Jsoup.connect(url).get();
System.out.println("Title: " + doc.title());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
完整示例:简单的Java爬虫项目结构
假设我们要爬取一个博客网站的所有文章标题和链接,并将结果保存到CSV文件中,以下是项目的简要结构和代码示例。
1 项目结构
BlogCrawler/
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── BlogCrawler.java
├── lib/
│ └── jsoup-1.15.4.jar
├── target/
└── pom.xml (如果使用Maven)
2 BlogCrawler.java代码示例
package com.example; 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.HashSet; import java.util.Set; import java.util.concurrent.; import java.util.; import java.util.stream.; import java.nio.file.; import java.util.; import org.jsoup.; import org.jsoup.nodes.; import org.jsoup.select.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.; import java.;
