项目起因
其实我从很久之前看了B站相关的数据可视化视频之后就很想尝试一下,但是一直没有动力。正好最近在推vtuber,想着为圈子做些贡献,并且WHUer无学可上,闲着也是闲着。我就自学了一些网络爬虫和数据可视化,虽然不多但是勉强够用,于是就开始了这个项目。
项目设计
简单的来说这个项目可以分成三个部分:
1.根据uid访问用户关注页并获得其关注者的信息(uid)
2.根据获得的up主uid逐一访问他们的粉丝页并且找到粉丝数和播放量的api
3.整理数据并制作图表
下面我来分别介绍项目的三个部分。
项目实现
第一部分
之前我们已经实现了根据uid获得用户简介和名称。其实原理完全一样,只不过换了网页。但是不同之处在于这里我们要用selenium来模拟浏览器,不然无法看到相关信息。
from selenium import webdriver
from bs4 import BeautifulSoup
import re
user=input('请输入你的uid号:')
uid_href=''
href=[]
driver=webdriver.Firefox()
driver.get('https://space.bilibili.com/'+user+'/fans/follow')
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
tags=soup.find_all(attrs={'href':re.compile(r"//space.bilibili.com/(\d+)/")})
for tag in tags:
if 'href' in tag.attrs:
href+=tag.attrs['href']
uid_href=''.join(href)
pattern=re.compile(r'\d+')
uids=pattern.findall(uid_href)
uids=list(set(uids))
第二部分
这一步我们要获得up主的粉丝数和播放数。如果尝试过你就会发现:这两个数据不是静态的存在于当前页面的源代码中的,而是有一个api将数据传给当前页面的。我们经过观察可以发现API的url分别为:
‘https://api.bilibili.com/x/relation/stat?vmid=’+uid (粉丝)
和
‘https://api.bilibili.com/x/space/upstat?mid='+uid (播放)
接下来我们就获得里面的数据并存为列表就可以了。
#获得粉丝数
followers=[]
for i in range(0,len(uids)):
driver.get('https://api.bilibili.com/x/relation/stat?vmid='+uids[i])
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
data=soup.find('div',id='json')
data=data.string
data=data.split('"follower":')
follower=data[-1].split('}}')
followers+=follower
followers= [i for i in followers if i != '']
#获得播放量
views=''
for i in range(0,len(uids)):
driver.get('https://api.bilibili.com/x/space/upstat?mid='+uids[i])
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
data=soup.find('div',id='json')
data=data.string
data=data.split('{"code":0,"message":"0","ttl":1,"data":{"archive":{"view":')
data=data[1]
data=data.split('},"article"')
view=data[0]+','
views+=view
views=views.split(',')
当然为了制作包含名字而不是uid的图表,我们还需要获得up主的名称,这里可以直接用到上一篇文章的代码,这里就不再展示。
第三部分
最后我们制作图表就可以了,这里我们使用的是echarts的python版本pyecharts,这个工具可以生成动态图标而且有多个主题可以直接使用,很方便。
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
.add_xaxis(name)
.add_yaxis("粉丝数量", followers)
.add_yaxis("播放量", views)
.set_global_opts(
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=60)),
title_opts=opts.TitleOpts(title="hololive", subtitle="粉丝数和播放量"),
)
.render("hololive.html")
)
至此,项目全部完成,效果如下:
结语
其实我开始项目的五天前还完全不会任何爬虫,也不会数据可视化。学习并做到这些东西我拢共用了可能不到20个小时。这当然不是我有天分什么的。ted有一个演讲叫’How To Learn Anything You Want In Just 20 Hours‘,当然前提是1. Deconstruct the skill 2. Learn Enough to Self-Correct 3. Remove Practice Barriers 4. Practice at least 20 hours。
我觉得编程十分符合这些:1.编程的代码实现调用了许多第三方库,这些第三方库实际帮助你知道了代码的功能区块,帮助你分解了任务。2.代码的实现与否清晰可见。3.我用手机看视频,用电脑写代码,根本没有其他电子设备让我分神了…可能这就是我这段时间执行力比较高的原因吧。
代码展示(以爬取hololive为例)
from selenium import webdriver
import requests
import selenium
from bs4 import BeautifulSoup
import re
from selenium.webdriver.chrome.options import Options
import csv
import xlwt
def getuid(uid):
url='https://space.bilibili.com/'+str(uid)
r=requests.get(url,timeout=30)
return r.text
def cutuid(html):
soup=BeautifulSoup(html,'html.parser')
ls=soup.find_all('meta',content=re.compile('bilibili'))
#获得简介框(因为简介tag包含'bilibili')
content=str(ls)
small_content=re.split(',bilibili是国内知名的视频弹幕网站,这里有最及时的动漫新番,最棒的ACG氛围,最有创意的Up主。大家可以在这里找到许多欢乐。" name="description">\n</meta>',content)
a=small_content[0]
b=re.split('meta content="',a)
c=b[1]
final_content=re.split(',',c,1)
name=final_content[0]
return name
#获得hololive众人的uid,286700005是holo哥的uid
uid_href=''
href=[]
driver=webdriver.Firefox()
driver.get('https://space.bilibili.com/'+user+'/fans/follow')
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
tags=soup.find_all(attrs={'href':re.compile(r"//space.bilibili.com/(\d+)/")})
for tag in tags:
if 'href' in tag.attrs:
href+=tag.attrs['href']
uid_href=''.join(href)
pattern=re.compile(r'\d+')
uids=pattern.findall(uid_href)
uids=list(set(uids))
#获得名称
name=[]
for i in range(0,len(uids)):
html=getuid(uids[i])
name.append(cutuid(html))
#获得粉丝数
followers=[]
for i in range(0,len(uids)):
driver.get('https://api.bilibili.com/x/relation/stat?vmid='+uids[i])
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
data=soup.find('div',id='json')
data=data.string
data=data.split('"follower":')
follower=data[-1].split('}}')
followers+=follower
followers= [i for i in followers if i != '']
#获得播放量
views=''
for i in range(0,len(uids)):
driver.get('https://api.bilibili.com/x/space/upstat?mid='+uids[i])
html=driver.page_source
soup=BeautifulSoup(html,'html.parser')
data=soup.find('div',id='json')
data=data.string
data=data.split('{"code":0,"message":"0","ttl":1,"data":{"archive":{"view":')
data=data[1]
data=data.split('},"article"')
view=data[0]+','
views+=view
views=views.split(',')
print(uids)
print(name)
print(followers)
print(views)
#作图
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
.add_xaxis(name)
.add_yaxis("粉丝数量", followers)
.add_yaxis("播放量", views)
.set_global_opts(
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=60)),
title_opts=opts.TitleOpts(title="hololive", subtitle="粉丝数和播放量"),
)
.render("hololive.html")
)
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!