基于 Hive 的评论数据分析前处理流程实践
本文记录一次小测的完整实现过程,内容覆盖 B站评论获取、原始数据整理、Hive 端清洗、MySQL 落库以及结果导出。整体思路是搭建一条从数据抓取到分析落地的基础数据处理流程。([cnblogs.com][1])
说明:文中示例仅用于学习测试,实际采集时需要注意访问频率和平台规则。
1. 项目流程概述
这次实验的目标不是只把评论爬下来,而是把一整套数据链路走通。整体流程可以概括为:
B站评论接口 → Python采集脚本 → 本地原始文件 → 格式预处理 → HDFS → Hive清洗 → MySQL存储 → CSV导出分析。([cnblogs.com][1])
如果按执行顺序来看,大致可以分成下面几个步骤:
- 输入视频的 BV 号;
- 调用接口抓取评论数据;
- 将原始结果保存为 JSON 或 CSV;
- 再把数据转换成适合 Hive 导入的文本格式;
- 上传到 HDFS;
- 在 Hive 中建立原始表并完成清洗;
- 将清洗后的结果同步到 MySQL;
- 最后导出结果,便于后续可视化或统计分析。([cnblogs.com][1])
2. 实验环境准备
2.1 Python 部分
首先准备 Python 运行环境,并安装数据采集和处理会用到的依赖:
sudo yum install -y python3 python3-devel python3-pip
pip3 install requests pandas
2.2 Hadoop 与 Hive
启动 HDFS,并检查 Hive 元数据服务是否正常:
start-dfs.sh
hive --service metastore &
jps
2.3 MySQL 环境
MySQL 用来存放最终清洗结果,便于后续报表、接口调用或者简单查询分析。原文中还补充了 JDBC 驱动到 Hive 的 lib 目录,以支持 Hive/MySQL 交互。([cnblogs.com][1])
sudo yum install -y mysql-community-server
sudo systemctl start mysqld
cp mysql-connector-java-8.0.30.jar $HIVE_HOME/lib/
3. 评论采集实现
这一部分的核心任务是:根据输入的 BV号,先换取对应视频的 aid,再分页请求评论接口,把评论内容组织成结构化数据保存下来。原文示例中保存了 comment_id、user_id、username、用户等级、会员信息、评论内容、点赞数、回复数、时间戳和页码等字段。([cnblogs.com][1])
下面是整理后的版本:
import requests
import json
import time
import pandas as pd
from datetime import datetime
class BiliCommentSpider:
def __init__(self):
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Referer": "https://www.bilibili.com"
}
def fetch_aid(self, bvid):
api = f"https://api.bilibili.com/x/web-interface/view?bvid={bvid}"
resp = requests.get(api, headers=self.headers, timeout=10)
if resp.status_code == 200:
data = resp.json()
return data["data"]["aid"]
return None
def crawl_comments(self, bvid, max_pages=10):
aid = self.fetch_aid(bvid)
if not aid:
return []
result = []
for pn in range(1, max_pages + 1):
params = {
"type": 1,
"oid": aid,
"pn": pn,
"ps": 20,
"sort": 1
}
resp = requests.get(
"https://api.bilibili.com/x/v2/reply",
headers=self.headers,
params=params,
timeout=10
)
data = resp.json()
if data.get("code") != 0:
break
replies = data.get("data", {}).get("replies", [])
if not replies:
break
for item in replies:
result.append({
"comment_id": item["rpid"],
"user_id": item["member"]["mid"],
"username": item["member"]["uname"],
"user_level": item["member"]["level_info"]["current_level"],
"vip_type": item["member"]["vip"]["vipType"],
"vip_status": item["member"]["vip"]["vipStatus"],
"content": item["content"]["message"],
"like_count": item["like"],
"reply_count": item["count"],
"create_time": item["ctime"],
"page": pn
})
time.sleep(1)
return result
def save_file(self, comments, bvid):
now = datetime.now().strftime("%Y%m%d_%H%M%S")
csv_name = f"comment_{bvid}_{now}.csv"
json_name = f"comment_{bvid}_{now}.json"
pd.DataFrame(comments).to_csv(csv_name, index=False, encoding="utf-8-sig")
with open(json_name, "w", encoding="utf-8") as f:
json.dump(comments, f, ensure_ascii=False, indent=2)
if __name__ == "__main__":
spider = BiliCommentSpider()
bv = input("请输入视频BV号:").strip()
comments = spider.crawl_comments(bv)
if comments:
spider.save_file(comments, bv)
print(f"采集完成,共获取 {len(comments)} 条评论")
else:
print("未获取到评论数据")
运行方式
python3 bilibili_crawler.py
4. 数据预处理
由于 Hive 更适合直接读取格式规整的文本数据,所以这里需要把 JSON 数据转换成 制表符分隔 的文本文件。原文这一部分的思路是:逐条读取 JSON 记录,然后把字段拼成一行,顺便替换掉制表符和换行符,避免 Hive 读入异常。([cnblogs.com][1])
可以写成下面这样:
import json
import sys
input_file = sys.argv[1]
output_file = sys.argv[2]
with open(input_file, "r", encoding="utf-8") as f:
records = json.load(f)
with open(output_file, "w", encoding="utf-8") as f:
for row in records:
line = "\t".join([
str(row.get("comment_id", "")),
str(row.get("user_id", 0)),
str(row.get("username", "")).replace("\t", " ").replace("\n", " "),
str(row.get("user_level", 0)),
str(row.get("vip_type", 0)),
str(row.get("vip_status", 0)),
str(row.get("content", "")).replace("\t", " ").replace("\n", " "),
str(row.get("like_count", 0)),
str(row.get("reply_count", 0)),
str(row.get("create_time", 0)),
str(row.get("page", 0))
])
f.write(line + "\n")
执行命令:
python3 preprocess_data.py data.json processed.txt
5. 上传到 HDFS 并在 Hive 中建表
完成文本转换后,就可以上传到 HDFS,之后通过 Hive 外部表进行映射。原文这里也是先建目录、上传文件,再创建数据库和原始表。([cnblogs.com][1])
5.1 上传数据
hdfs dfs -mkdir -p /user/hadoop/bilibili/input
hdfs dfs -put processed.txt /user/hadoop/bilibili/input
5.2 创建原始表
CREATE DATABASE IF NOT EXISTS bilibili_analysis;
USE bilibili_analysis;
CREATE EXTERNAL TABLE raw_comments (
comment_id STRING,
user_id BIGINT,
username STRING,
user_level INT,
vip_type INT,
vip_status INT,
content STRING,
like_count INT,
reply_count INT,
create_time BIGINT,
page INT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LOCATION '/user/hadoop/bilibili/input';
6. Hive 数据清洗
清洗阶段的重点是处理空值、非法值以及脏数据。原文中采用了这些思路:
comment_id、user_id、username等字段做空值补全;- 用户等级限定在合理区间;
- 评论内容去除控制字符;
- 点赞数、回复数出现负数时置为 0;
- 时间戳异常时替换成当前时间;
- 最后过滤掉空评论。([cnblogs.com][1])
SQL 可以整理成下面这样:
CREATE TABLE cleaned_comments AS
SELECT
COALESCE(comment_id, 'unknown') AS comment_id,
COALESCE(user_id, 0) AS user_id,
COALESCE(username, '匿名用户') AS username,
CASE
WHEN user_level < 0 OR user_level > 6 THEN 0
ELSE user_level
END AS user_level,
COALESCE(vip_type, 0) AS vip_type,
COALESCE(vip_status, 0) AS vip_status,
REGEXP_REPLACE(content, '[\\x00-\\x1F]', ' ') AS content,
CASE
WHEN like_count < 0 THEN 0
ELSE like_count
END AS like_count,
CASE
WHEN reply_count < 0 THEN 0
ELSE reply_count
END AS reply_count,
CASE
WHEN create_time > 0 AND create_time < UNIX_TIMESTAMP()
THEN create_time
ELSE UNIX_TIMESTAMP()
END AS create_time,
page
FROM raw_comments
WHERE content IS NOT NULL
AND content != '';
7. 同步到 MySQL
原文这里给了两种入库方式:
- Sqoop 导出,更偏向标准化同步流程;
- Hive 直接写 MySQL,适合没有 Sqoop 的情况。([cnblogs.com][1])
7.1 先在 MySQL 创建目标表
CREATE DATABASE IF NOT EXISTS bili_db;
USE bili_db;
DROP TABLE IF EXISTS cleaned_comments;
CREATE TABLE cleaned_comments (
comment_id VARCHAR(50) PRIMARY KEY,
user_id BIGINT,
username VARCHAR(100),
user_level INT,
vip_type INT,
vip_status INT,
content TEXT,
like_count INT,
reply_count INT,
create_time BIGINT,
page INT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
7.2 使用 Sqoop 导出
sqoop export \
--connect jdbc:mysql://localhost:3306/bili_db \
--username root \
--password your-password \
--table cleaned_comments \
--export-dir /user/hive/warehouse/bilibili_analysis.db/cleaned_comments \
--input-fields-terminated-by '\001' \
--input-null-string '\\N' \
--input-null-non-string '\\N'
7.3 不用 Sqoop 时的做法
CREATE TABLE hive_to_mysql (
comment_id STRING,
user_id BIGINT,
username STRING,
user_level INT,
vip_type INT,
vip_status INT,
content STRING,
like_count INT,
reply_count INT,
create_time BIGINT,
page INT
)
STORED BY 'org.apache.hive.storage.jdbc.JdbcStorageHandler'
TBLPROPERTIES (
"hive.jdbc.url" = "jdbc:mysql://localhost:3306/bili_db?useSSL=false&characterEncoding=utf8mb4",
"hive.jdbc.driver" = "com.mysql.cj.jdbc.Driver",
"hive.jdbc.user" = "root",
"hive.jdbc.password" = "your-password",
"hive.jdbc.write.batch.size" = "1000"
);
INSERT OVERWRITE TABLE hive_to_mysql
SELECT * FROM cleaned_comments;
8. 导出结果做本地分析
当清洗结果已经进入 MySQL 后,就可以继续导出为 CSV,供后续做统计图表、词频分析或者情感分析等。原文中使用的是 MySQL 的 INTO OUTFILE 导出方式。([cnblogs.com][1])
mysql -uroot -p -e "
USE bili_db;
SELECT * FROM cleaned_comments
INTO OUTFILE '/var/lib/mysql-files/bili_clean_result.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '\"'
LINES TERMINATED BY '\n';
"
9. 总结
通过这次小测,我把一条比较完整的数据处理链路跑通了:先从 B站抓取评论,再借助 Python 进行结构整理,接着上传到 HDFS,在 Hive 中完成基础清洗,最后同步到 MySQL 并导出结果。整个过程虽然不算复杂,但把采集、存储、清洗、入库、导出几个关键步骤串联起来后,更能体现大数据处理流程的完整性。原参考文章也是围绕这条主线展开,并给出了对应的代码和 SQL 实现。([cnblogs.com][1])

浙公网安备 33010602011771号