python爬取b站403_python3——爬取B站弹幕

在简书发现一篇有趣的文章:爬虫,走起,用Excel实现5min抓取B站弹幕及初步处理

讲到了如何根据开发者工具,获得B站视频的弹幕信息,不过有个不足就是手动保存弹幕信息。而通过python我们可以轻松地自动存储。

很容易就猜想到弹幕的网址格式就是:

http://comment.bilibili.com/数字.xml ,我们可以尝试着修改一下数字,发现确实如此。

那么如何确定数字“17168035”,就是我们自动获取弹幕列表的关键。

我们在视频网页的html搜索“17168035”

天啊,竟然有。那问题就太简单了。用正则表达式一下子就拿出来了:

danmu_id = re.findall(r'cid=(\d+)&', html)[0]

直接看下代码吧,没什么难的。

import requests, re

from bs4 import BeautifulSoup as BS

#打开网页函数

def open_url(url):

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.103 Safari/537.36'}

response = requests.get(url=url, headers=headers)

response.encoding = 'utf-8'

html = response.text

return html

#获取弹幕url中的数字id号

def get_danmu_id(html):

#用try防止有些av号没视频

try:

soup = BS(html, 'lxml')

#视频名

title = soup.select('div.v-title > h1')[0].get_text()

#投稿人

author = soup.select('meta[name="author"]')[0]['content']

#弹幕的网站代码

danmu_id = re.findall(r'cid=(\d+)&', html)[0]

print(title, author)

return danmu_id

except:

print('视频不见了哟')

return False

video_url ='http://www.bilibili.com/video/av10394940/'

video_html = open_url(video_url)

danmu_id = get_danmu_id(video_html)

if danmu_id:

danmu_url = 'http://comment.bilibili.com/{}.xml'.format(danmu_id)

danmu_html = open_url(url=danmu_url)

soup = BS(danmu_html, 'lxml')

all_d = soup.select('d')

for d in all_d:

#把d标签中P的各个属性分离开

danmu_list = d['p'].split(',')

#d.get_text()是弹幕内容

danmu_list.append(d.get_text())

print(danmu_list)

显示结果如下,可以再把这些个列表保存起来。

注意:

后来发现有一些B站网址还是不行, 比如埃罗芒阿老师这种网址,不是传统的av号形式(http://bangumi.bilibili.com/anime/5997/play#103921 )。

静态页面是实现不了,不过在开发者工具中还是能找到弹幕对应的数字号的,因此可以考虑之前说过的selenium+Chrome或PhantomJS的组合。

很好奇P中的各个数值都代表了什么,查了下。

引自:https://zhidao.baidu.com/question/1430448163912263499.html

前排占位置

p这个字段里面的内容:

0,1,25,16777215,1312863760,0,eff85771,42759017

中几个逗号分割的数据

第一个参数是弹幕出现的时间 以秒数为单位。

第二个参数是弹幕的模式1..3 滚动弹幕 4底端弹幕 5顶端弹幕 6.逆向弹幕 7精准定位 8高级弹幕

第三个参数是字号, 12非常小,16特小,18小,25中,36大,45很大,64特别大

第四个参数是字体的颜色 以HTML颜色的十进制为准

第五个参数是Unix格式的时间戳。基准时间为 1970-1-1 08:00:00

第六个参数是弹幕池 0普通池 1字幕池 2特殊池 【目前特殊池为高级弹幕专用】

第七个参数是发送者的ID,用于“屏蔽此弹幕的发送者”功能

第八个参数是弹幕在弹幕数据库中rowID 用于“历史弹幕”功能。

第一个参数,可以按照如下转换成时间(没找到对应的函数):

seconds = eval('1306.3900146484')

#商,余数 = divmod(被除数, 除数)

m, s = divmod(seconds, 60)

h, m = divmod(m, 60)

print ("%02d:%02d:%02d" % (h, m, s))

运行结果

00:21:46

-----------------------------------------------------------------------------------

-----------------------------------------------------------------------------------

其中第四个参数,我们怎么知道具体的颜色是什么呢

比如输出反复出现的16777215是什么颜色。我们可以进行以下的转换:

十进制->十六进制->RGB颜色表示

十进制数16777215换成十六进制数FFFFFF,也就是255,255,255。白色!

知道方法后,我们可以在在线调色板(点我进入)就能知道任意数字的颜色了,比如那个41194(十六进制00A0EA)。

原来是蓝色呀。

-----------------------------------------------------------------------------------

第五个参数,我们可以把它转换下:

import time

print(time.ctime(1494238353))

输出结果:

Mon May 8 18:12:33 2017

后续更新了下程序,修正了某些网址不能用静态获取弹幕数字号的问题。

import requests, re, time, csv

from bs4 import BeautifulSoup as BS

from selenium import webdriver

#打开网页函数

def open_url(url):

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.103 Safari/537.36'}

response = requests.get(url=url, headers=headers)

response.encoding = 'utf-8'

html = response.text

return html

#获取弹幕url中的数字id号

#当requests行不通时,采用selenium的方法。

def sele_get(url):

SERVICE_ARGS = ['--load-images=false', '--disk-cache=true']

driver = webdriver.PhantomJS(service_args = SERVICE_ARGS)

driver.get(url)

time.sleep(2)

danmu_id = re.findall(r'cid=(\d+)&', driver.page_source)[0]

return danmu_id

def get_danmu_id(html, url):

try:

soup = BS(html, 'lxml')

#视频名

title = soup.select('title[data-vue-meta="true"]')[0].get_text()

#投稿人

author = soup.select('meta[name="author"]')[0]['content']

#弹幕的网站代码

try:

danmu_id = re.findall(r'cid=(\d+)&', html)[0]

#danmu_id = re.findall(r'/(\d+)-1-64', html)[0]

#print(danmu_id)

except:

danmu_id = sele_get(url)

print(title, author)

return danmu_id

except:

print('视频不见了哟')

return False

#秒转换成时间

def sec2str(seconds):

seconds = eval(seconds)

m, s = divmod(seconds, 60)

h, m = divmod(m, 60)

time = "%02d:%02d:%02d" % (h, m, s)

return time

#csv保存函数

def csv_write(tablelist):

tableheader = ['出现时间', '弹幕模式', '字号', '颜色', '发送时间' ,'弹幕池', '发送者id', 'rowID', '弹幕内容']

with open('danmu.csv', 'w', newline='', errors='ignore') as f:

writer = csv.writer(f)

writer.writerow(tableheader)

for row in tablelist:

writer.writerow(row)

video_url ='http://www.bilibili.com/video/av5038338/'

video_html = open_url(video_url)

danmu_id = get_danmu_id(video_html, video_url)

all_list = []

if danmu_id:

danmu_url = 'http://comment.bilibili.com/{}.xml'.format(danmu_id)

danmu_html = open_url(url=danmu_url)

soup = BS(danmu_html, 'lxml')

all_d = soup.select('d')

for d in all_d:

#把d标签中P的各个属性分离开

danmu_list = d['p'].split(',')

#d.get_text()是弹幕内容

danmu_list.append(d.get_text())

danmu_list[0] = sec2str(danmu_list[0])

danmu_list[4] = time.ctime(eval(danmu_list[4]))

all_list.append(danmu_list)

print(danmu_list)

all_list.sort()

csv_write(all_list)

你可能感兴趣的:(python爬取b站403)