基于python的微博热搜爬取及数据分析
刚学python爬虫,用爬虫爬取新浪微博热搜,看看效果如何,也是对这段时间学习python的总结。
一、目的:
抓取新浪微博2020年1月3日星期五的热搜榜,将抓取到的数据进行动态展示,并生成当天的微博热点词云及微博热搜频度较高的前20个关键词的条形图。
二、思路:
- 分析新浪微博热搜榜网页https://s.weibo.com/top/summary,分析网页结构
- 对网页进行解析,获取当前热点的话题、名次、话题讨论量、当前抓取的时间
- 由于微博热搜动态刷新,选取20-30分钟抓取一次数据,时间范围为9:30-21:00
- 将最后抓取到的所有的数据导入到实现数据动态显示的模块中,并进行相关调整
- 利用结巴分词对获取到数据进行分词,用WordCloud显示当天热搜的热点词云
三、相关实现步骤
1.网页解析
定义请求头来进行模拟浏览器,并随机生成一个请求头,方法def get_header():
header1 = { "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0" } header2 = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362" } header3 = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" } header_list = [header1,header2,header3] index = random.randint(0,1) return header_list[index]
解析网站方法:def get_data(url,headers)
访问
req = requests.get(url=url, headers=headers)
req.encoding = "utf-8"
通过lxml解析网页
bf = BeautifulSoup(html, "lxml")
通过观察,每一条热搜都是在tr class=””下,因此只需遍历所有的class=””
就能得到每一条热搜
div_content = bf.find_all("tr", class_="")
遍历div_content,获得每条热搜的名次,主题,讨论量
for item in div_content:
去掉置顶的那一条信息,在循环外加个变量t = 1
if (t == 1): t = 0 continue
tr下有三条td信息,分别代表名次、热搜主题和浏览量、标签表情,前两条信息是我们想要获取的
获取当前热搜名次
num_content = item.select("td")[0].string
热搜主题和浏览量分别在td-02的a标签和span标签下
获取当前热搜主题
content = item.select("td")[1].select("a")[0].string
获取当前热搜主题讨论量
num = item.select("td")[1].select("span")[0].string
获取当前系统时间,需要在前面导入from time import strftime
current_time = strftime("%Y-%m-%d %H:%M")
将当前热搜名次、当前热搜主题、当前热搜主题讨论量、当前系统时间放入list,以便存储数据
list = [content,num_content,num,current_time]
将list整个再放入一个list中
list_content.append(list)
2.存储数据
将爬取到的数据存储起来,存储方法def store_Excel(list):
写入文件,编码方式为utf_8_sig,生成的csv文件不会乱码,不换行操作为newline=””
with open("微博实时热搜.csv","a",encoding="utf_8_sig",newline="")as file:
csv_writer = csv.writer(file)
对列表进行遍历,写入
for item in list: csv_writer.writerow(item)
关闭文件
file.close()
3.生成词云
思路:
- 整合一天爬取到的所有数据
2,通过累加的方式进行列表的遍历累加,把列表变成长字符串
3,把字符串通过结巴分词的方式进行拆分空格分词
4,找到一张轮廓清晰的图片打开并用numpy进行轮廓获取
5,用WordCloud来生成当天微博热搜热点的词云。
导入生成词云的库
rom wordcloud import WordCloud import Image import numpy import jieba
定义字符串来进行字符串存储
str = ""
读取热搜热点表格
with open("微博实时热搜test.csv","r",encoding="utf_8_sig",newline="") as file: csv_reader = csv.reader(file)
遍历列表
for item in csv_reader:
去掉第一条无用信息,在循环外定义变量t=1
if t == 1: t = 0 continue
字符串拼接,热搜热点话题在第一列
str += item[0]
关闭文件
file.close()
通过结巴分词进行分词
jieba_content = jieba.cut(str)
join方法进行空格拼接
join_content=" ".join(jieba_content)
打开图片
wei_bo = Image.open("logo.jpg")
找轮廓
wei_bo_image = numpy.array(wei_bo)
制作生成词云
word_cloud = WordCloud(font_path="font1.TTF",background_color="white",mask = wei_bo_image).generate(join_content) word_cloud.to_file("微博热搜.jpg")
最终词云展示:
词云是由微博logo图片勾勒出来的,字体大小代表热度,字体越大,代表热度越高,字体越小,热度越低
4.分析数据
思路:
1.将微博热搜主题存储在txt文件中
2.读取txt文件,用jieba分词进行分词操作,生成关键词
3.对关键词进行频度统计
4.将统计好的关键词按照频度从大到小进行排序
5.将排序过的结果存储在csv文件中,以便进行后续操作
定义字典
word_dic = {}
打开文件,读取数据
with open("1.txt", "r", encoding="utf-8") as file:
txt = file.read()
file.close()
jieba分词切分数据
words = jieba.lcut(txt)
循环遍历数据
for word in words:
如果关键字数为1,不统计
if len(word) == 1:
continue
否则频度增1
else:
word_dic[word] = word_dic.get(word, 0) + 1
字典数据转换成元祖数据,用zip实现
word_zip = zip(word_dic.values(), word_dic.keys())
对元祖里面的数据按照value从大到小进行排序
word_sort = list(sorted(word_zip, reverse=True))
定义两个list进行数据的存储
list_1 = ["name", "count_name"]
list_2 = []
list_2.append(list_1)
for item in word_sort:
# 词频数
count = item[0]
# 关键字
name = item[1]
list_1 = [name, count]
list_2.append(list_1)
写入文件
with open("微博热搜关键词词频统计.csv", "w", encoding="utf_8_sig", newline="")as file:
csv_writer = csv.writer(file)
遍历list_2,写入每行
for i in list_2:
csv_writer.writerow(i)
5.生成绘图
思路:根据排序好的热搜关键字的文件,提取前20个频率高的数据进行条形图的绘制
导入绘图工具包
import pandas as pd
import matplotlib.pyplot as plt
定义绘图风格及颜色
plt.style.use('ggplot')
colors1 = '#6D6D6D'
读取排序好的文件
df = pd.read_csv("微博热搜关键词词频统计.csv",encoding="utf-8")
提取排名前20的关键词和频度
name1 = df.name[:20]
count1 = df.count_name[:20]
绘制条形图,用range()能保持x轴正确顺序
plt.bar(range(20),count1,tick_label = name1)
设置纵坐标范围
plt.ylim(0,90)
显示中文字体标签
plt.rcParams['font.sans-serif'] = ['SimHei']
标题
plt.title('微博热搜关键词词频统计',color = colors1)
x轴标题、y轴标题
plt.title('微博热搜关键词词频统计',color = colors1)
plt.xlabel('关键词')
为每个条形图添加数值标签
for x,y in enumerate(list(count1)):
plt.text(x,y+1,'%s'%round(y,90),ha = 'center',color = colors1)
x轴关键字旋转300度
plt.xticks(rotation = 300)
自动控制空白边缘,以全部显示x轴坐标
plt.tight_layout()
保存图片
plt.savefig('微博热搜关键词词频统计top20.png')
显示图片
plt.show()
绘图结果展示:
- 数据动态显示:
本次爬虫共抓取大约20多组数据,每组数据对应50条热搜榜单,抓取时间为2020年1月1日9:30-21:00,每次抓取时间间隔为20-30分钟。抓取这么多组数据主要是为了做数据的动态效果,展示一天来微博热搜的动态变化情况
数据动态展示效果图:
完整数据动态效果视频详见微博热搜数据动态展示.mp4