一.选题背景
1.背景:爬虫是从互联网上抓取对于我们有价值的信息。选择此题正是因为随着信息化的发展,大数据时代对信息的采需求和集量越来越大,相应的处理量也越来越大,正是因为如此,爬虫相应的岗位也开始增多,因此,学好这门课也是为将来就业打下扎实的基础。bilibili在当今众多视频网站中,有许多年轻人都在使用这个软件,通过爬取其中热门视频的弹幕可以了解最近年轻人都在看些什么,可以进一步了解现阶段年轻人的观看喜好。
2.预期目标:爬取这个视频的视频、音频、评论和弹幕,并将弹幕可视化之后再进行数据清理和持久化保持。
二.主题式网络爬虫设计方案
1.主题式网络爬虫名称:
爬取b站热门视频的视频、音频、一部分评论和弹幕
2.主题式网络爬虫爬取的内容与数据特征分析
内容:爬取b站热门视频的视频、音频、一部分评论和弹幕,并将弹幕进行可视化
特征分析:对弹幕进行计数,然后进行可视化
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
思路:爬取弹幕,计算次数,进行可视化。
难点:进行可视化会出现错误
三、主题页面的结构特征分析
1.主题页面的结构与特征分析
2.Htmls 页面解析
3.节点(标签)查找方法与遍历方法(必要时画出节点树结构)
遍历方法:(1)遍历输出内容并保存到文件
(2)统计词频
(3)进行情感极性分析,并统计不同情感类别的弹幕数量
(4)去除重复弹幕
四、网络爬虫程序设计
(一).爬取视频和音频
1.导入库
1 # 导入requests库,用于发送HTTP请求 2 3 import requests 4 5 # 导入re库,用于正则表达式操作 6 7 import re 8 9 # 导入json库,用于处理JSON数据 10 11 import json 12 13 # 导入pprint模块,用于美化输出 14 15 from pprint import pprint
2.确定请求url地址
1 url = 'https://www.bilibili.com/video/BV1gN411C7Dn'
3.防伪
1 # 把python代码伪装成浏览器 2 3 headers = { 4 5 # 设置请求头Referer字段 6 7 'Referer': 'https://www.bilibili.com/video/', 8 9 # 浏览器基本身份标识 10 11 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.199.400 QQBrowser/11.8.5300.400' 12 13 }
4.提取视频和音频
1 # 发送请求 2 3 response = requests.get(url=url, headers=headers) 4 5 # 获取标题 6 7 title = re.findall('"title":"(.*?)","pubdate"', response.text)[0] 8 9 # 获取视频数据信息 10 11 html_data = re.findall('<script>window.__playinfo__=(.*?)</script>', response.text)[0] 12 13 json_data = json.loads(html_data) 14 15 # 获取音频的二进制 16 17 audio_url = json_data['data']['dash']['audio'][0]['baseUrl'] 18 19 # 获取视频的二进制 20 21 video_url = json_data['data']['dash']['video'][0]['baseUrl'] 22 23 print(title) 24 25 print(audio_url) 26 27 print(video_url) 28 29 # 获取音频内容 30 31 audio_content = requests.get(url=audio_url, headers=headers).content 32 33 # 获取视频内容 34 35 video_content = requests.get(url=video_url, headers=headers).content 36 37 # 保存音频内容 38 39 with open('video\\' + title + '.mp3', mode='wb') as audio: 40 audio.write(audio_content) 41 42 # 保存视频内容 43 44 with open('video\\' + title + '.mp4', mode='wb') as video: 45 video.write(video_content) 46 # 获取音频内容以及视频画面内容
(二).爬取一部分评论
1.导入库
1 # 导入时间模块 2 3 import time 4 5 # 导入请求模块 6 7 import requests 8 9 # 导入re模块,用于正则表达式匹配 10 11 import re
2.设置循环执行次数
1 # 循环执行10次 2 3 for page in range(1, 11): 4 # 每次循环暂停1秒 5 6 time.sleep(1)
3.确定请求url地址
1 # 评论接口的URL 2 3 url = f'https://api.bilibili.com/x/v2/reply/main?csrf=a52df2167caabb4b136e5a176129e6e1&mode=3&oid=486825901&pagination_str=%7B%22offset%22:%22%7B%5C%22type%5C%22:1,%5C%22direction%5C%22:1,%5C%22data%5C%22:%7B%5C%22pn%5C%22:2%7D%7D%22%7D&plat=1&type=1' 4 5 # 请求头信息 6 7 headers = { 8 9 'cookie': 'buvid3=B0EB5F80-D2B0-14A3-EB3A-87CFA804787250106infoc; b_nut=1685541450; i-wanna-go-back=-1; _uuid=1098D47DD-3A9C-EE54-410C9-3B83B2781A9650989infoc; FEED_LIVE_VERSION=V8; home_feed_column=5; nostalgia_conf=-1; CURRENT_FNVAL=4048; rpdid=|(u)lu|k)uR|0J\'uY)llRuR~u; header_theme_version=CLOSE; browser_resolution=1492-728; SESSDATA=6bf2b085%2C1701519221%2C8f4aa%2A61; bili_jct=a52df2167caabb4b136e5a176129e6e1; DedeUserID=404298709; DedeUserID__ckMd5=5ad8c592423d2b17; PVID=1; fingerprint=99c2f32d86e8c07d1ade297f990f81d8; buvid_fp_plain=undefined; b_ut=5; b_lsid=DDE53241_1888F81F06B; bsource=search_sougo; buvid4=8AE136D9-03A8-2D62-E8CA-A1EB8746EBD551924-023053121-+9JvYED62PxRAFmHznBmEg%3D%3D; sid=ousk7to2; buvid_fp=B0EB5F80-D2B0-14A3-EB3A-87CFA804787250106infoc', 10 11 'origin': 'https://www.bilibili.com', 12 13 'referer': 'https://www.bilibili.com/video/', 14 15 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.199.400 QQBrowser/11.8.5300.400' 16 }
4.爬取部分评论
1 # 发送请求 2 3 response = requests.get(url=url, headers=headers) 4 5 # 从响应中提取评论内容 6 7 content_list = [i['content']['message'] for i in response.json()['data']['replies']] 8 9 # 打印评论内容列表 10 11 print(content_list) 12 13 # 遍历输出内容 14 15 for content in content_list: 16 with open('评论数据.txt', mode='a', encoding='utf-8') as f: 17 18 # 将评论内容写入文本文件 19 20 f.write(content) 21 22 # 写入换行符,以便每条评论占一行 23 24 f.write('\n') 25 26 # 打印每条评论内容 27 28 print(content)
(三).爬取弹幕
1.导入库
1 # 导入requests库,用于发送HTTP请求 2 import requests 3 # 导入re库,用于正则表达式匹配 4 import re 5 # 导入font_manager模块,用于设置字体 6 from matplotlib import font_manager 7 # 导入matplotlib.pyplot模块,用于绘图 8 import matplotlib.pyplot as plt 9 # 导入Counter类,用于统计词频 10 from collections import Counter 11 # 导入seaborn库,用于绘制统计图表 12 import seaborn as sns 13 # 导入WordCloud类,用于生成词云图 14 from wordcloud import WordCloud
2.设置字体
1 # 设置全局字体 2 my_font=font_manager.FontProperties(fname="C:\Windows\Fonts\STSONG.TTF") 3 plt.rcParams['font.family'] = 'STSong' 4 # 替换成所选的中文字体
3.确定url和防伪
1 # 发送HTTP请求,获取弹幕数据的URL,并使用requests库发送GET请求获取响应 2 3 url = 'https://api.bilibili.com/x/v1/dm/list.so?oid=1150981775' 4 5 headers = { 6 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37' 7 }
4.爬取弹幕
1 # 发送GET请求获取响应 2 response = requests.get(url=url, headers=headers) 3 # 设置响应的编码方式为UTF-8,以解决乱码问题。 4 response.encoding = 'utf-8' 5 # 获取数据 6 data = response.text 7 8 # 解析数据 9 content_list = re.findall('<d p=".*?">(.*?)</d>', data) 10 11 12 # 遍历输出内容并保存到文件 13 with open('弹幕.txt', mode='w', encoding='utf-8') as f: 14 for content in content_list: 15 f.write(content) 16 f.write('\n') 17 print(content)
5.生产词云图并保持
1 # 将弹幕内容列表转换为字符串 2 text = ' '.join(content_list) 3 # 使用WordCloud库生成词云对象 4 wordcloud = WordCloud(font_path='C:\Windows\Fonts\msyh.ttc').generate(text) 5 6 # 将弹幕内容列表转换为字符串,并使用WordCloud库生成词云对象。 7 plt.imshow(wordcloud, interpolation='bilinear') 8 plt.axis('off') 9 # 保存词云图 10 plt.savefig('词云图.png') 11 plt.show()
6.统计词频
1 # 使用Counter类统计词频 2 word_counts = Counter(content_list) 3 # 获取词频最高的前10个词 4 top_words = word_counts.most_common(10) 5 # 获取词频最高的词的标签 6 top_words_labels = [word[0] for word in top_words] 7 # 获取词频最高的词的计数 8 top_words_counts = [word[1] for word in top_words]
7.生成柱状图并保存
1 # 生成柱状图 2 plt.bar(top_words_labels, top_words_counts) 3 plt.xlabel('Words') 4 plt.ylabel('Counts') 5 plt.title('Top 10 Words in Danmaku') 6 plt.xticks(rotation=45) 7 # 保存柱状图 8 plt.savefig('柱状图.png') 9 plt.show()
8.生成饼图并保存
1 # 生成饼图 2 labels = top_words_labels 3 sizes = top_words_counts 4 plt.pie(sizes, labels=labels, autopct='%1.1f%%') 5 plt.title('Top 10 Words Distribution in Danmaku') 6 plt.axis('equal') 7 # 保存饼图 8 plt.savefig('饼图.png') 9 plt.show()
9.生成折线图并保存
1 # 生成折线图 2 x_values = range(1, len(top_words_labels) + 1) 3 plt.plot(x_values, top_words_counts, marker='o') 4 plt.xlabel('Words') 5 plt.ylabel('Counts') 6 plt.title('Top 10 Words in Danmaku') 7 plt.xticks(x_values, top_words_labels, rotation=45) 8 # 保存折线图 9 plt.savefig('折线图.png') 10 plt.show()
10.生成漏斗图并保存
1 # 生成漏斗图 2 sns.set_style("whitegrid") 3 plt.figure(figsize=(8, 6)) 4 plt.title("Top 10 Words Funnel",fontproperties=my_font) 5 sns.barplot(x=top_words_counts, y=top_words_labels, palette="Blues_r") 6 plt.xlabel("Counts") 7 plt.ylabel("Words") 8 # 保存漏斗图 9 plt.savefig('漏斗图.png') 10 plt.show()
11.进行情感极性分析,并统计不同情感类别的弹幕数量
1 # 进行情感极性分析,并统计不同情感类别的弹幕数量 2 emotions = { 3 'positive': 0, 4 'negative': 0, 5 'neutral': 0 6 } 7 8 for item in content_list: 9 if SnowNLP(item).sentiments > 0.6: 10 emotions['positive'] += 1 11 elif SnowNLP(item).sentiments < 0.4: 12 emotions['negative'] += 1 13 else: 14 emotions['neutral'] += 1 15 16 # 生成柱状图 17 plt.bar(emotions.keys(), emotions.values()) 18 plt.xlabel('Emotions') 19 plt.ylabel('Counts') 20 plt.title('Emotion Distribution in Danmaku') 21 # 保存情感极性分析 22 plt.savefig('情感极性分析.png') 23 plt.show()
12.进行数据清洗
1 # 去除重复弹幕 2 content_list = list(set(content_list)) 3 # 遍历输出清理后的内容并保存到文件 4 with open('弹幕.0.txt', mode='w', encoding='utf-8') as f: 5 for content in content_list: 6 f.write(content) 7 f.write('\n') 8 print(content)
13.总代码
(1)爬取视频和音频
1 # 导入requests库,用于发送HTTP请求 2 3 import requests 4 5 # 导入re库,用于正则表达式操作 6 7 import re 8 9 # 导入json库,用于处理JSON数据 10 11 import json 12 13 # 导入pprint模块,用于美化输出 14 15 from pprint import pprint 16 17 # 确定请求url地址 18 19 url = 'https://www.bilibili.com/video/BV1gN411C7Dn' 20 21 # 把python代码伪装成浏览器 22 23 headers = { 24 25 # 设置请求头Referer字段 26 27 'Referer': 'https://www.bilibili.com/video/', 28 29 # 浏览器基本身份标识 30 31 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.199.400 QQBrowser/11.8.5300.400' 32 33 } 34 35 # 发送请求 36 37 response = requests.get(url=url, headers=headers) 38 39 # 获取标题 40 41 title = re.findall('"title":"(.*?)","pubdate"', response.text)[0] 42 43 # 获取视频数据信息 44 45 html_data = re.findall('<script>window.__playinfo__=(.*?)</script>', response.text)[0] 46 47 json_data = json.loads(html_data) 48 49 # 获取音频的二进制 50 51 audio_url = json_data['data']['dash']['audio'][0]['baseUrl'] 52 53 # 获取视频的二进制 54 55 video_url = json_data['data']['dash']['video'][0]['baseUrl'] 56 57 print(title) 58 59 print(audio_url) 60 61 print(video_url) 62 63 # 获取音频内容 64 65 audio_content = requests.get(url=audio_url, headers=headers).content 66 67 # 获取视频内容 68 69 video_content = requests.get(url=video_url, headers=headers).content 70 71 # 保存音频内容 72 73 with open('video\\' + title + '.mp3', mode='wb') as audio: 74 audio.write(audio_content) 75 76 # 保存视频内容 77 78 with open('video\\' + title + '.mp4', mode='wb') as video: 79 video.write(video_content) 80 # 获取音频内容以及视频画面内容
(2)爬取评论
1 # 导入时间模块 2 3 import time 4 5 # 导入请求模块 6 7 import requests 8 9 # 导入re模块,用于正则表达式匹配 10 11 import re 12 13 # 循环执行10次 14 15 for page in range(1, 11): 16 # 每次循环暂停1秒 17 18 time.sleep(1) 19 20 # 评论接口的URL 21 22 url = f'https://api.bilibili.com/x/v2/reply/main?csrf=a52df2167caabb4b136e5a176129e6e1&mode=3&oid=486825901&pagination_str=%7B%22offset%22:%22%7B%5C%22type%5C%22:1,%5C%22direction%5C%22:1,%5C%22data%5C%22:%7B%5C%22pn%5C%22:2%7D%7D%22%7D&plat=1&type=1' 23 24 # 请求头信息 25 26 headers = { 27 28 'cookie': 'buvid3=B0EB5F80-D2B0-14A3-EB3A-87CFA804787250106infoc; b_nut=1685541450; i-wanna-go-back=-1; _uuid=1098D47DD-3A9C-EE54-410C9-3B83B2781A9650989infoc; FEED_LIVE_VERSION=V8; home_feed_column=5; nostalgia_conf=-1; CURRENT_FNVAL=4048; rpdid=|(u)lu|k)uR|0J\'uY)llRuR~u; header_theme_version=CLOSE; browser_resolution=1492-728; SESSDATA=6bf2b085%2C1701519221%2C8f4aa%2A61; bili_jct=a52df2167caabb4b136e5a176129e6e1; DedeUserID=404298709; DedeUserID__ckMd5=5ad8c592423d2b17; PVID=1; fingerprint=99c2f32d86e8c07d1ade297f990f81d8; buvid_fp_plain=undefined; b_ut=5; b_lsid=DDE53241_1888F81F06B; bsource=search_sougo; buvid4=8AE136D9-03A8-2D62-E8CA-A1EB8746EBD551924-023053121-+9JvYED62PxRAFmHznBmEg%3D%3D; sid=ousk7to2; buvid_fp=B0EB5F80-D2B0-14A3-EB3A-87CFA804787250106infoc', 29 30 'origin': 'https://www.bilibili.com', 31 32 'referer': 'https://www.bilibili.com/video/', 33 34 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.199.400 QQBrowser/11.8.5300.400' 35 } 36 # 发送请求 37 38 response = requests.get(url=url, headers=headers) 39 40 # 从响应中提取评论内容 41 42 content_list = [i['content']['message'] for i in response.json()['data']['replies']] 43 44 # 打印评论内容列表 45 46 print(content_list) 47 48 # 遍历输出内容 49 50 for content in content_list: 51 with open('评论数据.txt', mode='a', encoding='utf-8') as f: 52 53 # 将评论内容写入文本文件 54 55 f.write(content) 56 57 # 写入换行符,以便每条评论占一行 58 59 f.write('\n') 60 61 # 打印每条评论内容 62 63 print(content)
(3)爬取弹幕
1 # 导入requests库,用于发送HTTP请求 2 import requests 3 4 # 导入re库,用于正则表达式匹配 5 import re 6 7 # 导入font_manager模块,用于设置字体 8 from matplotlib import font_manager 9 10 # 导入matplotlib.pyplot模块,用于绘图 11 import matplotlib.pyplot as plt 12 13 # 导入Counter类,用于统计词频 14 from collections import Counter 15 16 # 导入seaborn库,用于绘制统计图表 17 import seaborn as sns 18 19 # 导入WordCloud类,用于生成词云图 20 from wordcloud import WordCloud 21 22 # 设置全局字体 23 my_font=font_manager.FontProperties(fname="C:\Windows\Fonts\STSONG.TTF") 24 plt.rcParams['font.family'] = 'STSong' 25 # 替换成所选的中文字体 26 # 发送HTTP请求,获取弹幕数据的URL,并使用requests库发送GET请求获取响应 27 28 url = 'https://api.bilibili.com/x/v1/dm/list.so?oid=1150981775' 29 30 headers = { 31 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.37' 32 } 33 34 # 发送GET请求获取响应 35 response = requests.get(url=url, headers=headers) 36 37 # 设置响应的编码方式为UTF-8,以解决乱码问题。 38 response.encoding = 'utf-8' 39 40 # 获取数据 41 data = response.text 42 43 # 解析数据 44 content_list = re.findall('<d p=".*?">(.*?)</d>', data) 45 46 47 # 遍历输出内容并保存到文件 48 with open('弹幕.txt', mode='w', encoding='utf-8') as f: 49 for content in content_list: 50 f.write(content) 51 f.write('\n') 52 print(content) 53 54 55 # 将弹幕内容列表转换为字符串 56 text = ' '.join(content_list) 57 # 使用WordCloud库生成词云对象 58 wordcloud = WordCloud(font_path='C:\Windows\Fonts\msyh.ttc').generate(text) 59 60 # 将弹幕内容列表转换为字符串,并使用WordCloud库生成词云对象。 61 plt.imshow(wordcloud, interpolation='bilinear') 62 plt.axis('off') 63 64 # 保存词云图 65 plt.savefig('词云图.png') # 保存词云图 66 plt.show() 67 68 # 统计词频 69 70 # 使用Counter类统计词频 71 word_counts = Counter(content_list) 72 73 # 获取词频最高的前10个词 74 top_words = word_counts.most_common(10) 75 76 # 获取词频最高的词的标签 77 top_words_labels = [word[0] for word in top_words] 78 79 # 获取词频最高的词的计数 80 top_words_counts = [word[1] for word in top_words] 81 82 # 生成柱状图 83 plt.bar(top_words_labels, top_words_counts) 84 plt.xlabel('Words') 85 plt.ylabel('Counts') 86 plt.title('Top 10 Words in Danmaku') 87 plt.xticks(rotation=45) 88 89 # 保存柱状图 90 plt.savefig('柱状图.png') 91 plt.show() 92 93 # 生成饼图 94 labels = top_words_labels 95 sizes = top_words_counts 96 plt.pie(sizes, labels=labels, autopct='%1.1f%%') 97 plt.title('Top 10 Words Distribution in Danmaku') 98 plt.axis('equal') 99 100 # 保存饼图 101 plt.savefig('饼图.png') 102 plt.show() 103 104 # 生成折线图 105 x_values = range(1, len(top_words_labels) + 1) 106 plt.plot(x_values, top_words_counts, marker='o') 107 plt.xlabel('Words') 108 plt.ylabel('Counts') 109 plt.title('Top 10 Words in Danmaku') 110 plt.xticks(x_values, top_words_labels, rotation=45) 111 112 # 保存折线图 113 plt.savefig('折线图.png') 114 plt.show() 115 116 # 生成漏斗图 117 sns.set_style("whitegrid") 118 plt.figure(figsize=(8, 6)) 119 plt.title("Top 10 Words Funnel",fontproperties=my_font) 120 sns.barplot(x=top_words_counts, y=top_words_labels, palette="Blues_r") 121 plt.xlabel("Counts") 122 plt.ylabel("Words") 123 124 # 保存漏斗图 125 plt.savefig('漏斗图.png') 126 plt.show() 127 128 # 进行情感极性分析,并统计不同情感类别的弹幕数量 129 emotions = { 130 'positive': 0, 131 'negative': 0, 132 'neutral': 0 133 } 134 135 for item in content_list: 136 if SnowNLP(item).sentiments > 0.6: 137 emotions['positive'] += 1 138 elif SnowNLP(item).sentiments < 0.4: 139 emotions['negative'] += 1 140 else: 141 emotions['neutral'] += 1 142 143 # 生成柱状图 144 plt.bar(emotions.keys(), emotions.values()) 145 plt.xlabel('Emotions') 146 plt.ylabel('Counts') 147 plt.title('Emotion Distribution in Danmaku') 148 149 # 保存情感极性分析 150 plt.savefig('情感极性分析.png') 151 plt.show() 152 153 154 # 去除重复弹幕 155 content_list = list(set(content_list)) 156 157 # 遍历输出清理后的内容并保存到文件 158 with open('弹幕.0.txt', mode='w', encoding='utf-8') as f: 159 for content in content_list: 160 f.write(content) 161 f.write('\n') 162 print(content)
五、总结
1.经过对主题数据的分析与可视化,可以得到哪些结论?是否达到预期的目标?
在这个视频中除了哈哈哈,爷青回占比最多。爷青回的意思是爷的青春回来了。说明当代年轻人想要找回之前的热血和热情,想要看以前的视频。
有达到预期目标
2.在完成此设计过程中,得到哪些收获?以及要改进的建议?
我知道了,跟多的代码,复习了以前的代码,也知道了自己的不足。要完善自己的不足
标签:视频,plt,10,python,content,url,words,弹幕 From: https://www.cnblogs.com/kawdf/p/17463542.html