1. 引言
B站(哔哩哔哩)作为国内领先的视频分享平台,其弹幕功能是其核心特色之一。弹幕数据不仅反映了用户的实时互动情绪,还能用于内容分析、舆情监控、用户行为研究等场景。本文将介绍如何使用 Java爬虫 抓取B站弹幕,并将其存储到 MySQL数据库,最后进行简单的数据分析。
1.1 技术栈
- Java爬虫:使用
HttpClient
发送HTTP请求,Jsoup
或JSON解析库
处理数据。 - 数据库:MySQL 存储弹幕数据。
- 数据分析:使用Java进行词频统计,或结合Python进行更复杂的分析(如情感分析)。
2. B站弹幕抓取
B站的弹幕数据通常以 XML 或 JSON 格式存储,可以通过分析B站API获取弹幕数据。
2.1 分析B站弹幕API
- 打开B站任意视频(如
https://www.bilibili.com/video/BV1GJ411x7h7
)。 - 按
F12
打开开发者工具,在 Network(网络) 选项卡中筛选danmu
或bullet
相关请求。
找到弹幕API,通常是类似:
- text复制下载api.bilibili.com/x/v1/dm/lis…
oid
是视频的唯一标识,可以通过B站API或网页源码获取。
2.2 Java爬虫实现
我们使用 HttpClient
发送请求,并用 Jsoup
解析XML格式的弹幕数据。
(1)添加Maven依赖
<dependencies>
<!-- HTTP请求 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- XML解析 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
(2)获取弹幕数据
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
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.ArrayList;
import java.util.List;
public class BiliBiliDanmuCrawler {
// 代理配置
private static final String PROXY_HOST = "www.16yun.cn";
private static final int PROXY_PORT = 5445;
private static final String PROXY_USER = "16QMSOML";
private static final String PROXY_PASS = "280651";
public static List<String> fetchDanmu(String oid) throws IOException {
String url = "https://api.bilibili.com/x/v1/dm/list.so?oid=" + oid;
// 1. 设置代理
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
// 2. 代理认证(如果代理需要用户名/密码)
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(PROXY_HOST, PROXY_PORT),
new UsernamePasswordCredentials(PROXY_USER, PROXY_PASS)
);
// 3. 配置HTTP客户端(带代理)
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setProxy(proxy)
.build();
// 4. 设置请求超时(可选)
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时(毫秒)
.setSocketTimeout(5000) // 读取超时(毫秒)
.build();
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(config); // 应用超时设置
List<String> danmuList = new ArrayList<>();
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
String xml = EntityUtils.toString(response.getEntity());
Document doc = Jsoup.parse(xml);
Elements danmus = doc.select("d");
for (Element danmu : danmus) {
danmuList.add(danmu.text());
}
} finally {
httpClient.close(); // 确保关闭HTTP客户端
}
return danmuList;
}
public static void main(String[] args) throws IOException {
String oid = "12345678"; // 替换为真实oid
List<String> danmus = fetchDanmu(oid);
danmus.forEach(System.out::println);
}
}
3. 存储弹幕到MySQL
3.1 创建数据库表
CREATE TABLE bilibili_danmu (
id INT AUTO_INCREMENT PRIMARY KEY,
content TEXT,
video_id VARCHAR(50),
crawl_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3.2 Java写入MySQL
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
public class DanmuStorage {
private static final String DB_URL = "jdbc:mysql://localhost:3306/bilibili?useSSL=false";
private static final String USER = "root";
private static final String PASSWORD = "123456";
public static void saveDanmu(List<String> danmus, String videoId) {
String sql = "INSERT INTO bilibili_danmu (content, video_id) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (String danmu : danmus) {
pstmt.setString(1, danmu);
pstmt.setString(2, videoId);
pstmt.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
String oid = "12345678"; // 替换为真实oid
List<String> danmus = BiliBiliDanmuCrawler.fetchDanmu(oid);
saveDanmu(danmus, "BV1GJ411x7h7");
}
}
4. 弹幕数据分析
4.1 词频统计
import java.util.*;
import java.util.stream.Collectors;
public class DanmuAnalysis {
public static Map<String, Long> wordFrequency(List<String> danmus) {
return danmus.stream()
.flatMap(danmu -> Arrays.stream(danmu.split(" ")))
.filter(word -> word.length() > 1) // 过滤单字
.collect(Collectors.groupingBy(
word -> word,
Collectors.counting()
))
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(20)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
public static void main(String[] args) throws IOException {
String oid = "12345678";
List<String> danmus = BiliBiliDanmuCrawler.fetchDanmu(oid);
Map<String, Long> wordFreq = wordFrequency(danmus);
wordFreq.forEach((word, count) -> System.out.println(word + ": " + count));
}
}
5. 总结
本文介绍了:
- B站弹幕API分析:如何找到弹幕数据接口。
- Java爬虫实现:使用
HttpClient
+Jsoup
抓取弹幕。 - 数据存储:将弹幕存入MySQL数据库。
- 数据分析:词频统计及情感分析(可选)。
扩展方向
- 反爬策略:B站可能有反爬机制,可以尝试使用代理IP或模拟浏览器(Selenium)。
- 实时弹幕:使用WebSocket监听B站实时弹幕。
- 可视化:用ECharts或Python Matplotlib 绘制弹幕词云。