豆瓣作为国内领先的图书、电影、音乐评论网站,拥有海量的用户生成内容(UGC)。其中,书籍评论数据对于理解读者喜好、分析图书市场趋势、辅助书籍推荐等都具有重要的价值。本文将带领大家使用 Python 编写爬虫,深入解析豆瓣书籍评论,并利用可视化工具和自然语言处理技术,对评论数据进行评分数据可视化和情感倾向分析,最终实现对书籍评论的深度理解和应用。
在学习爬虫之前,我们需要先搭建好 Python 开发环境。推荐使用 Anaconda 或 Miniconda,它们集成了 Python 解释器和常用的科学计算库,并提供了一个方便的包管理器 conda。
python --version
或者
python3 --version
如果看到版本信息输出,则说明 Python 环境搭建成功。
本教程将使用以下 Python 库:
conda install requests beautifulsoup4 lxml pandas matplotlib seaborn jieba nltk scikit-learn
或者使用 pip 安装:
pip install requests beautifulsoup4 lxml pandas matplotlib seaborn jieba nltk scikit-learn
网络爬虫(Web Crawler)是一个自动化的程序,它遵循一定的规则,从互联网上下载网页,并提取所需的信息。爬虫的基本原理如下:
在进行爬虫编写之前,我们需要对目标网站进行详细的分析,了解其 URL 结构、数据加载方式、页面结构等信息。
以豆瓣《三体》这本书的评论页面为例,其 URL 为:
https://book.douban.com/subject/6518605/comments/
通过观察可以发现,豆瓣书籍评论的 URL 通常遵循以下格式:
https://book.douban.com/subject//comments/
其中
是书籍的唯一标识符。例如,《三体》的 book_id 为 6518605
。
进一步观察发现,评论页面存在分页,每页显示 20 条评论。分页的 URL 格式为:
https://book.douban.com/subject//comments/hot?p=
其中
是页码,从 1 开始。
打开《三体》的评论页面,使用浏览器的开发者工具(F12)查看页面源代码。可以发现评论数据被包含在 class 为 comment-item
的 div
标签中。
<div class="comment-item" data-cid="191419207">
<div class="comment">
<h3>
<span class="comment-info">
<a href="https://www.douban.com/people/xxxxx/" class="comment-info-a">xxxxxa>
<span class="user-stars allstar50 rating" title="力荐">span>
<span class="comment-time " title="2023-10-27 23:11:09">
<span title="2023-10-27 23:11:09">2023-10-27 23:11:09span>
span>
span>
h3>
<p class="comment-content">
<span class="short">非常好的书,强烈推荐!span>
p>
<div class="comment-vote">
<a href="javascript:;" class="vote-btn" data-cid="191419207">有用a>
<span class="vote-count">(12)span>
div>
div>
div>
从这段 HTML 代码中,我们可以提取出以下信息:
a
标签的文本内容。span
标签的 title
属性值。span
标签的 class
属性中 allstar
后面的数字,例如 allstar50
表示 5 星。span
标签的 class
为 short
的文本内容。span
标签的 class
为 vote-count
的文本内容(去掉括号)。为了模拟浏览器访问,我们需要设置请求头(Headers)。可以在浏览器开发者工具的 Network 选项中查看请求头信息。
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Referer": "https://book.douban.com/subject/6518605/comments/",
}
根据 URL 结构分析,我们可以构造请求 URL。
book_id = "6518605"
start_page = 1
max_page = 10 # 假设我们爬取前 10 页的评论
urls = [f"https://book.douban.com/subject/{book_id}/comments/hot?p={page}" for page in range(start_page, max_page + 1)]
使用 requests
库发送请求,并获取响应内容。
import requests
def get_html(url):
try:
response = requests.get(url, headers=headers, timeout=5)
response.raise_for_status()
return response.text
except requests.RequestException as e:
print(e)
return None
使用 BeautifulSoup
库解析 HTML 页面,提取评论数据。
from bs4 import BeautifulSoup
def parse_comments(html):
soup = BeautifulSoup(html, "lxml")
comment_items = soup.find_all("div", class_="comment-item")
comments = []
for item in comment_items:
nickname = item.find("a", class_="comment-info-a").get_text(strip=True)
rating = item.find("span", class_=lambda x: x and x.startswith("user-stars"))["class"][0]
rating = int(rating[-2:]) / 10 # 将 allstar50 转换为 5
comment_time = item.find("span", class_="comment-time")["title"]
comment_content = item.find("span", class_="short").get_text(strip=True)
vote_count = item.find("span", class_="vote-count").get_text(strip=True)
vote_count = int(vote_count[1:-1]) # 去掉括号并转换为整数
comments.append({
"nickname": nickname,
"rating": rating,
"comment_time": comment_time,
"comment_content": comment_content,
"vote_count": vote_count
})
return comments
将提取的评论数据存储到 CSV 文件中。
import pandas as pd
def save_to_csv(comments, filename):
df = pd.DataFrame(comments)
df.to_csv(filename, index=False, encoding="utf_8_sig")
将以上代码整合,得到完整的爬虫代码。
import requests
from bs4 import BeautifulSoup
import pandas as pd
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Referer": "https://book.douban.com/subject/6518605/comments/",
}
def get_html(url):
try:
response = requests.get(url, headers=headers, timeout=5)
response.raise_for_status()
return response.text
except requests.RequestException as e:
print(e)
return None
def parse_comments(html):
soup = BeautifulSoup(html, "lxml")
comment_items = soup.find_all("div", class_="comment-item")
comments = []
for item in comment_items:
nickname = item.find("a", class_="comment-info-a").get_text(strip=True)
rating = item.find("span", class_=lambda x: x and x.startswith("user-stars"))["class"][0]
rating = int(rating[-2:]) / 10 # 将 allstar50 转换为 5
comment_time = item.find("span", class_="comment-time")["title"]
comment_content = item.find("span", class_="short").get_text(strip=True)
vote_count = item.find("span", class_="vote-count").get_text(strip=True)
vote_count = int(vote_count[1:-1]) # 去掉括号并转换为整数
comments.append({
"nickname": nickname,
"rating": rating,
"comment_time": comment_time,
"comment_content": comment_content,
"vote_count": vote_count
})
return comments
def save_to_csv(comments, filename):
df = pd.DataFrame(comments)
df.to_csv(filename, index=False, encoding="utf_8_sig")
def main():
book_id = "6518605"
start_page = 1
max_page = 10 # 假设我们爬取前 10 页的评论
all_comments = []
for page in range(start_page, max_page + 1):
url = f"https://book.douban.com/subject/{book_id}/comments/hot?p={page}"
html = get_html(url)
if html:
comments = parse_comments(html)
all_comments.extend(comments)
print(f"Page {page} crawled.")
else:
print(f"Failed to crawl page {page}.")
save_to_csv(all_comments, "douban_comments.csv")
print("Comments saved to CSV.")
if __name__ == "__main__":
main()
运行以上代码,即可将《三体》书籍的前 10 页评论数据爬取下来,并保存到 douban_comments.csv
文件中。
豆瓣网站具有一定的反爬虫机制,例如检测请求头、IP 地址、请求频率等。如果爬虫程序被识别,豆瓣可能会返回验证码页面或者禁止访问。
为了应对反爬虫机制,可以采取以下措施:
爬取下来的数据往往存在一些噪声和缺失值,需要进行数据清洗和预处理,才能进行后续的分析。
使用 pandas 库加载 CSV 文件中的数据。
import pandas as pd
df = pd.read_csv("douban_comments.csv")
print(df.head())
检查数据中是否存在无用信息,例如 HTML 标签、特殊字符等,并进行清理。
import re
def clean_text(text):
text = re.sub(r"<.*?>", "", text) # 去除 HTML 标签
text = re.sub(r"\s+", " ", text) # 去除多余的空格
text = text.strip() # 去除首尾空格
return text
df["comment_content"] = df["comment_content"].apply(clean_text)
检查数据中是否存在缺失值,并根据情况进行处理,例如删除缺失值、填充缺失值等。
print(df.isnull().sum())
# 删除缺失值
df = df.dropna()
# 或者填充缺失值
# df = df.fillna({"column_name": "default_value"})
为了进行情感分析,我们需要对评论内容进行分词。
import jieba
def segment(text):
return " ".join(jieba.cut(text))
df["comment_content_segmented"] = df["comment_content"].apply(segment)
根据分析目的,提取所需的特征。例如,我们可以提取评论星级、评论内容等特征。
features = ["rating", "comment_content_segmented"]
X = df[features]
如果需要进行机器学习分析,可能需要对数据进行标准化处理。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
我们将使用 matplotlib 和 seaborn 库进行数据可视化。
使用 seaborn 的 countplot
函数绘制评分分布直方图。
import seaborn as sns
import matplotlib.pyplot as plt
sns.countplot(x="rating", data=df)
plt.title("Rating Distribution")
plt.show()
将评论时间转换为日期格式,并绘制评分随时间变化的趋势图。
df["comment_time"] = pd.to_datetime(df["comment_time"])
plt.figure(figsize=(12, 6))
sns.lineplot(x="comment_time", y="rating", data=df, ci=None)
plt.title("Rating Trend Over Time")
plt.xticks(rotation=45)
plt.show()
情感倾向分析(Sentiment Analysis)是指利用自然语言处理(NLP)技术,对文本数据进行分析,判断文本所表达的情感倾向,例如积极、消极或中性。
常见的情感倾向分析方法包括:
常用的中文情感词典包括:
使用情感词典进行情感分析的基本步骤如下:
# 加载情感词典
positive_words = set()
negative_words = set()
with open("positive_words.txt", "r", encoding="utf-8") as f:
for line in f:
positive_words.add(line.strip())
with open("negative_words.txt", "r", encoding="utf-8") as f:
for line in f:
negative_words.add(line.strip())
# 计算情感分数
def calculate_sentiment_score(text):
words = text.split()
positive_score = sum(1 for word in words if word in positive_words)
negative_score = sum(1 for word in words if word in negative_words)
return positive_score - negative_score
df["sentiment_score"] = df["comment_content_segmented"].apply(calculate_sentiment_score)
# 判断情感倾向
def classify_sentiment(score):
if score > 0:
return "positive"
elif score < 0:
return "negative"
else:
return "neutral"
df["sentiment"] = df["sentiment_score"].apply(classify_sentiment)
将文本数据转换为机器学习算法可以理解的数值特征。常用的特征工程方法包括:
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features=1000)
X = vectorizer.fit_transform(df["comment_content_segmented"])
使用监督学习算法,例如朴素贝叶斯、逻辑回归、支持向量机等,进行模型训练和评估。
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, df["sentiment"], test_size=0.2, random_state=42)
# 训练模型
model = MultinomialNB()
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
# 评估模型
print(classification_report(y_test, y_pred))
使用训练好的模型对新的评论数据进行情感分析。
def predict_sentiment(text):
text = segment(text)
text_vector = vectorizer.transform([text])
return model.predict(text_vector)[0]
# 测试
new_comment = "这本书写得真好,强烈推荐!"
print(predict_sentiment(new_comment))
本文以豆瓣书籍评论为例,详细介绍了 Python 爬虫的实现方法,包括环境搭建、目标网站分析、爬虫代码编写、数据清洗与预处理、评分数据可视化和情感倾向分析。通过本文的学习,读者可以掌握 Python 爬虫的基本原理和技巧,并能够运用所学知识进行实际的项目开发。