本文目录导读:

我来为你详细介绍Java实现爬虫的几种常见方案和完整案例。
基础爬虫方案
Maven依赖配置
<dependencies>
<!-- HTTP客户端 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- HTML解析器 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
简单爬虫示例 - 抓取网页内容
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class SimpleCrawler {
public static void main(String[] args) {
String url = "https://example.com/news";
crawl(url);
}
public static void crawl(String url) {
try {
// 发送HTTP请求并获取HTML文档
Document document = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.timeout(5000)
.get();
// 解析标题
String title = document.title();
System.out.println("页面标题: " + title);
// 提取所有链接
Elements links = document.select("a[href]");
for (Element link : links) {
String href = link.attr("abs:href");
String text = link.text();
System.out.println("链接: " + text + " -> " + href);
}
// 提取特定元素
Elements newsItems = document.select(".news-item");
for (Element item : newsItems) {
String title_text = item.select(".title").text();
String desc = item.select(".description").text();
System.out.println("新闻标题: " + title_text);
System.out.println("描述: " + desc);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
高级爬虫框架 - WebMagic
添加依赖
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.5</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.5</version>
</dependency>
WebMagic爬虫示例
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
public class WebMagicCrawler implements PageProcessor {
// 配置爬虫设置
private Site site = Site.me()
.setRetryTimes(3) // 重试次数
.setSleepTime(1000) // 请求间隔
.setTimeOut(10000) // 超时时间
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
@Override
public void process(Page page) {
// 爬取列表页
if (page.getUrl().regex("https://example.com/list/\\d+").match()) {
// 添加分页链接到待爬取队列
page.addTargetRequests(page.getHtml().links().regex("https://example.com/list/\\d+").all());
// 添加详情页链接到待爬取队列
page.addTargetRequests(page.getHtml().links().regex("https://example.com/detail/\\d+").all());
}
// 爬取详情页
if (page.getUrl().regex("https://example.com/detail/\\d+").match()) {
// 提取数据
String title = page.getHtml().xpath("//h1[@class='title']/text()").get();
String content = page.getHtml().xpath("//div[@class='content']/html()").get();
String author = page.getHtml().css(".author", "text").get();
String date = page.getHtml().xpath("//span[@class='date']/text()").get();
// 保存数据到resultItems
page.putField("title", title);
page.putField("content", content);
page.putField("author", author);
page.putField("date", date);
page.putField("url", page.getUrl().toString());
}
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
// 启动爬虫
Spider.create(new WebMagicCrawler())
.addUrl("https://example.com/list/1") // 起始URL
.addPipeline(new ConsolePipeline()) // 控制台输出
.addPipeline(new JsonFilePipeline("data")) // 保存为JSON文件
.thread(5) // 线程数
.run(); // 运行
}
}
使用HttpClient + Jsoup
完整爬虫工具类
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 org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AdvancedCrawler {
private CloseableHttpClient httpClient;
private Map<String, String> headers;
public AdvancedCrawler() {
this.httpClient = HttpClients.createDefault();
this.headers = new HashMap<>();
headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.put("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
}
// 获取网页内容
public String getPageContent(String url) throws IOException {
HttpGet httpGet = new HttpGet(url);
// 设置请求头
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "UTF-8");
}
}
// 解析并提取数据
public void parseAndExtract(String html) {
Document doc = Jsoup.parse(html);
// 使用CSS选择器
Elements elements = doc.select("div.article");
for (Element element : elements) {
String title = element.select("h2.title").text();
String summary = element.select("p.summary").text();
String link = element.select("a").attr("href");
System.out.println("标题: " + title);
System.out.println(" " + summary);
System.out.println("链接: " + link);
}
// 使用正则表达式提取邮箱
String text = doc.text();
Pattern emailPattern = Pattern.compile("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b");
Matcher matcher = emailPattern.matcher(text);
while (matcher.find()) {
System.out.println("邮箱: " + matcher.group());
}
}
// 带会话的爬取(处理登录等)
public void crawlWithSession() throws IOException {
// 实现登录并维持会话
CloseableHttpClient sessionClient = HttpClients.custom()
.setDefaultRequestConfig(null)
.build();
// 添加Cookie处理
// 实际使用时需要添加CookieStore
}
public static void main(String[] args) {
AdvancedCrawler crawler = new AdvancedCrawler();
try {
String content = crawler.getPageContent("https://example.com");
crawler.parseAndExtract(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
数据持久化 - 保存到数据库
import java.sql.*;
import java.util.List;
import java.util.ArrayList;
public class DataPersistence {
private Connection connection;
public DataPersistence() {
// 初始化数据库连接
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/crawler",
"username",
"password"
);
} catch (Exception e) {
e.printStackTrace();
}
}
// 保存爬取的数据
public void saveArticle(String title, String content, String url) {
String sql = "INSERT INTO articles (title, content, url, crawl_time) VALUES (?, ?, ?, NOW())";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
pstmt.setString(1, title);
pstmt.setString(2, content);
pstmt.setString(3, url);
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 批量保存
public void batchSave(List<Article> articles) {
String sql = "INSERT INTO articles (title, content, url) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
for (Article article : articles) {
pstmt.setString(1, article.getTitle());
pstmt.setString(2, article.getContent());
pstmt.setString(3, article.getUrl());
pstmt.addBatch();
}
pstmt.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 文章实体类
static class Article {
private String title;
private String content;
private String url;
// getters and setters
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
}
}
反爬虫处理
import java.util.Random;
public class AntiCrawlStrategy {
private static Random random = new Random();
// 随机User-Agent
private static String[] USER_AGENTS = {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15",
"Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15"
};
// 获取随机User-Agent
public static String getRandomUserAgent() {
return USER_AGENTS[random.nextInt(USER_AGENTS.length)];
}
// 添加请求延迟
public static void delay() {
try {
// 随机延迟1-3秒
Thread.sleep(1000 + random.nextInt(2000));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 使用代理IP
public static String getProxyIP() {
// 实际使用时从代理池获取
return "http://proxy-ip:port";
}
}
完整爬虫运行示例
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CrawlerRunner {
public static void main(String[] args) {
// 使用线程池控制并发
ExecutorService executor = Executors.newFixedThreadPool(5);
// 爬取多个URL
String[] urls = {
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3"
};
for (String url : urls) {
executor.submit(() -> {
try {
// 添加延迟避免被封
Thread.sleep(1000);
// 执行爬取
AdvancedCrawler crawler = new AdvancedCrawler();
String content = crawler.getPageContent(url);
crawler.parseAndExtract(content);
System.out.println("成功爬取: " + url);
} catch (Exception e) {
System.err.println("爬取失败: " + url);
e.printStackTrace();
}
});
}
executor.shutdown();
}
}
注意事项
- 遵守robots.txt协议
- 设置合理的请求频率
- 处理异常和重试机制
- 数据去重和增量爬取
- 遵守网站使用条款
- 注意数据隐私和版权问题
这个案例覆盖了从简单到复杂的Java爬虫实现,你可以根据实际需求选择合适的方案,爬虫技术要合法使用。