# 让弹幕飞一会儿——腾讯视频弹幕(39W+)爬取实战

#这就是我写爬虫所信奉的大碗宽面逻辑。

01 子弹（弹幕）轨迹规律探究

1、数据定位：

2、弹道（弹幕网址）规律分析：

`https://mfm.video.qq.com/danmu?otype=json&callback=jQuery19109123255549841207_1553922882824&timestamp=45&target_id=3753912718%26vid%3Dt00306i1e62&count=80&second_count=5&session_key=558401%2C8142%2C1553922887&_=1553922882831`

`https://mfm.video.qq.com/danmu?otype=json&timestamp=15&target_id=3753912718%26vid%3Dt00306i1e62&count=80`

`https://mfm.video.qq.com/danmu?otype=json&timestamp=45&target_id=3753912718%26vid%3Dt00306i1e62&count=80`

(PS：其实大碗宽面的逻辑下，我们这个时候应该再继续对比不同集数之间网址变化规律，并找到规律本身，但考虑到内容实操性与可读性，我们不妨把这一块往后稍稍）

02 解析单页弹幕内容

OK，接下来遍历提取我们需要的关键数据：

`#存储数据df = pd.DataFrame()#遍历获取目标字段for i in bs['comments']:    content = i['content']  #弹幕内容    name = i['opername']    #用户名    upcount = i['upcount']  #点赞数    user_degree =i['uservip_degree'] #会员等级    timepoint = i['timepoint']  #发布时间    comment_id = i['commentid']  #弹幕ID    cache = pd.DataFrame({'用户名':[name],'内容':[content],'会员等级':[user_degree],                          '评论时间点':[timepoint],'评论点赞':[upcount],'评论id':[comment_id]})    df = pd.concat([df,cache])`

03 不同集之间网址规律探究

`https://mfm.video.qq.com/danmu?otype=json&timestamp=15&target_id=3753912718%26vid%3Dt00306i1e62&count=80`

`https://mfm.video.qq.com/danmu?otype=json&timestamp=15&target_id=3753912717%26vid%3Dx003061htl5&count=80`

1、找到后缀ID

`#打开任意一集，1-30和31-46存储在两个网页part1_url = 'https://union.video.qq.com/fcgi-bin/data?otype=json&tid=682&appid=20001238&appkey=6c03bbe9658448a4&idlist=b0030velala,t00306i1e62,x003061htl5,b0030velala,w0030ilim7z,i0030r7v63u,z003044noq2,m0030sfinyr,c0030u884k7,k0030m5zbr7,l0030e5nglm,h0030b060vn,j003090ci7w,n0030falyoi,s00308u9kwx,p0030fohijf,g00303ob0cx,v0030960y6n,x0030bl84xw,v0030keuav1,t0030kups1i,n0030y2o52i,x0030s52mev,d0030xuekgw,o0030md1a2a,x0030peo3sk,d00303l5j4k,t0030aexmnt,a0030ybi45z,y0030wpe2wu&callback=jQuery19101240739643414368_1553238198070&_=1553238198071'part2_url = 'https://union.video.qq.com/fcgi-bin/data?otype=json&tid=682&appid=20001238&appkey=6c03bbe9658448a4&idlist=t0030epjqsi,g003035mi84,n00301fxqbh,h0030zivlrq,d0030qc1yu2,m0030q9ywxj,h0030j0eq19,j0030jks835,t0030owh5uu,e0030xbj246,a00308xw434,l0030tb319m,a0030mhntt6,t0030wnr3t9,l0030t7o64e,b0030i9bi3o,m0030yklk6j,z0030tgz3pp,r00307wgnly,o00306b4zax,k00309i6ul6,j00304eu73n,v08521l667a,u0851gzzoqi,a0852328197,k0852mb3ymt,v00308p65xf,z08527pia6g,z08520difig,z0852ybpxn0&callback=jQuery19101240739643414368_1553238198072&_=1553238198073'base_info  = pd.DataFrame()for url in [part1_url,part2_url]:    html = requests.get(url,headers = headers)    bs = json.loads(html.text[html.text.find('{'):-1])        for i in bs['results']:        #后缀ID        v_id = i['id']        #这一集的名字，比如“都挺好_01”        title = i['fields']['title']        #播放量        view_count = i['fields']['view_all_count']        #整型存储的集数，片花则为0        episode = int(i['fields']['episode'])        #去掉片花，只留下正片        if episode == 0:            pass        else:            cache = pd.DataFrame({'id':[v_id],'title':[title],'播放量':[view_count],'第几集':[episode]})            base_info = pd.concat([base_info,cache])`

OK，非常顺利。

2、死磕target_id

“一切过往，皆为序章”

3、思路梳理：

• 第一步，我们搞清楚了单集内部弹幕网址的动态变化，只需要改变timestamp的值即可循环爬取单集所有内容。
• 第二步，发现要自动爬取每一集，必须先找到构造网址的target_id和后缀的ID
• 第三步，任意一集网页中都能直接找到所有剧集的后缀ID（我们已经拿下了所有的后缀ID），但是却只能在一集中找到单集的一个target_id。
• 第四步，也就是接下来的一步，我们可以基于已经爬到的后缀ID，去循环访问每一集，拿到单集对应的target_id，这样就能构造出完整的弹幕网页所需的ID们了。

`#定义爬取单集target_id的函数#只需要向函数传入v_id（后缀ID）和headersdef get_episode_danmu(v_id,headers):    #target_id所在基础网址    base_url = 'https://access.video.qq.com/danmu_manage/regist?vappid=97767206&vsecret=c0bdcbae120669fff425d0ef853674614aa659c605a613a4&raw=1'    #传递参数，只需要改变后缀ID    pay = {"wRegistType":2,"vecIdList":[v_id],       "wSpeSource":0,"bIsGetUserCfg":1,       "mapExtData":{v_id:{"strCid":"wu1e7mrffzvibjy","strLid":""}}}        html = requests.post(base_url,data = json.dumps(pay),headers = headers)    bs = json.loads(html.text)    #定位元素    danmu_key = bs['data']['stMap'][v_id]['strDanMuKey']    #解析出target_id    target_id = danmu_key[danmu_key.find('targetid') + 9 : danmu_key.find('vid') - 1]    return [v_id,target_id]info_lst = []#循环获取后缀ID并传递for i in base_info['id']:    #得到每一集的后缀ID和target_id    info = get_episode_danmu(i,headers)    print(info)    info_lst.append(info)    time.sleep(3 + random.random())`

Skrrrrrrrrrrr~

PS：如果觉得有用可以点个“在看”，感恩~

```import requestsimport jsonimport pandas as pdimport osimport timeimport random

#页面基本信息解析，获取构成弹幕网址所需的后缀ID、播放量、集数等信息。def parse_base_info(url,headers):    df = pd.DataFrame()        html = requests.get(url,headers = headers)    bs = json.loads(html.text[html.text.find('{'):-1])        for i in bs['results']:        v_id = i['id']        title = i['fields']['title']        view_count = i['fields']['view_all_count']        episode = int(i['fields']['episode'])        if episode == 0:            pass        else:            cache = pd.DataFrame({'id':[v_id],'title':[title],'播放量':[view_count],'第几集':[episode]})            df = pd.concat([df,cache])    return df

#传入后缀ID，获取该集的target_id并返回def get_episode_danmu(v_id,headers):    base_url = 'https://access.video.qq.com/danmu_manage/regist?vappid=97767206&vsecret=c0bdcbae120669fff425d0ef853674614aa659c605a613a4&raw=1'    pay = {"wRegistType":2,"vecIdList":[v_id],       "wSpeSource":0,"bIsGetUserCfg":1,       "mapExtData":{v_id:{"strCid":"wu1e7mrffzvibjy","strLid":""}}}    html = requests.post(base_url,data = json.dumps(pay),headers = headers)    bs = json.loads(html.text)    danmu_key = bs['data']['stMap'][v_id]['strDanMuKey']    target_id = danmu_key[danmu_key.find('targetid') + 9 : danmu_key.find('vid') - 1]    return [v_id,target_id]

#解析单个弹幕页面，需传入target_id，v_id(后缀ID)和集数（方便匹配），返回具体的弹幕信息def parse_danmu(url,target_id,v_id,headers,period):    html = requests.get(url,headers = headers)    bs = json.loads(html.text,strict = False)    df = pd.DataFrame()    for i in bs['comments']:        content = i['content']        name = i['opername']        upcount = i['upcount']        user_degree =i['uservip_degree']        timepoint = i['timepoint']        comment_id = i['commentid']        cache = pd.DataFrame({'用户名':[name],'内容':[content],'会员等级':[user_degree],                              '弹幕时间点':[timepoint],'弹幕点赞':[upcount],'弹幕id':[comment_id],'集数':[period]})        df = pd.concat([df,cache])    return df

#构造单集弹幕的循环网页，传入target_id和后缀ID（v_id），通过设置爬取页数来改变timestamp的值完成翻页操作def format_url(target_id,v_id,end = 85):    urls = []    base_url = 'https://mfm.video.qq.com/danmu?otype=json&timestamp={}&target_id={}%26vid%3D{}&count=80&second_count=5'        for num in range(15,end * 30 + 15,30):        url = base_url.format(num,target_id,v_id)        urls.append(url)    return urls

def get_all_ids(part1_url,part2_url,headers):    #分别获取1-30，31-46的所有后缀ID（v_id）    part_1 = parse_base_info(part1_url,headers)    part_2 = parse_base_info(part2_url,headers)    df = pd.concat([part_1,part_2])    df.sort_values('第几集',ascending = True,inplace = True)    count = 1    #创建一个列表存储target_id    info_lst = []    for i in df['id']:        info = get_episode_danmu(i,headers)        info_lst.append(info)        print('正在努力爬取第 %d 集的target_id' % count)        count += 1        time.sleep(2 + random.random())     print('是不是发现多了一集？别担心，会去重的')    #根据后缀ID，将target_id和后缀ID所在的表合并    info_lst = pd.DataFrame(info_lst)    info_lst.columns = ['v_id','target_id']    combine = pd.merge(df,info_lst,left_on = 'id',right_on = 'v_id',how = 'inner')    #去重复值    combine = combine.loc[combine.duplicated('id') == False,:]    return combine

#输入包含v_id,target_id的表，并传入想要爬取多少集def crawl_all(combine,num,page,headers):    c = 1    final_result = pd.DataFrame()    #print('Bro,马上要开始循环爬取每一集的弹幕了')    for v_id,target_id in zip(combine['v_id'][:num],combine['target_id'][:num]):        count = 1        urls = format_url(target_id,v_id,page)        for url in urls:            result = parse_danmu(url,target_id,v_id,headers,c)            final_result = pd.concat([final_result,result])            time.sleep(2+ random.random())            print('这是 %d 集的第 %d 页爬取..' % (c,count))            count += 1        print('-------------------------------------')        c += 1    return final_result

if __name__ == '__main__':        #《都挺好》1-30集的网址，31-46集的网址    #如果要爬取其他电视剧，只需要根据文章的提示，找到存储后缀ID的原网址即可    part1_url = 'https://union.video.qq.com/fcgi-bin/data?otype=json&tid=682&appid=20001238&appkey=6c03bbe9658448a4&idlist=x003061htl5,t00306i1e62,x003061htl5,b0030velala,w0030ilim7z,i0030r7v63u,z003044noq2,m0030sfinyr,c0030u884k7,k0030m5zbr7,l0030e5nglm,h0030b060vn,j003090ci7w,n0030falyoi,s00308u9kwx,p0030fohijf,g00303ob0cx,v0030960y6n,x0030bl84xw,v0030keuav1,t0030kups1i,n0030y2o52i,x0030s52mev,d0030xuekgw,o0030md1a2a,x0030peo3sk,d00303l5j4k,t0030aexmnt,a0030ybi45z,y0030wpe2wu&callback=jQuery191020844423583354543_1554200358596&_=1554200358597'    part2_url = 'https://union.video.qq.com/fcgi-bin/data?otype=json&tid=682&appid=20001238&appkey=6c03bbe9658448a4&idlist=t0030epjqsi,g003035mi84,n00301fxqbh,h0030zivlrq,d0030qc1yu2,m0030q9ywxj,h0030j0eq19,j0030jks835,a00308xw434,l0030tb319m,x0030xogl32,g0030fju3w3,a0030vrcww0,l0030jzi1mi,c0030mq8yjr,u00302fdo8v,a0030w9g57k,n0030wnj6i8,j0030h91ouj,j00304eu73n,t00305kc1f5,i0030x490o2,u0030jtmlj2,d003031ey5h,w0850w594k6,l0854pfn9lg,f08546r7l7a,d0854s0oq1z,m08546pcd9k,p0854r1nygj&callback=jQuery191020844423583354543_1554200358598&_=1554200358599'    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}        #得到所有的后缀ID，基于后缀ID爬取target_id    combine = get_all_ids(part1_url,part2_url,headers)        #设置要爬取多少集（num参数），每一集爬取多少页弹幕（1-85页，page参数），这里默认是爬取第一集的5页弹幕    #比如想要爬取30集，每一集85页，num = 30,page = 85    final_result = crawl_all(combine,num = 1,page = 5,headers = headers)    #final_result.to_excel('xxx.xlsx') 可以输出成EXCEL格式的文件```

0 条评论

• ### Python 爬取40万条《都挺好》弹幕数据，发现弹幕比剧还精彩？

火到什么程度？微博热搜霸榜，办公室评弹声四起，大强轻松攻占表情包，甚至连 N 年不追剧的“瘦宅”们也开始沉迷其中，大呼真香。

• ### Python爬取394452条《都挺好》弹幕数据，比剧情还精彩？

火到什么程度？微博热搜霸榜，办公室评弹声四起，大强轻松攻占表情包，甚至连 N 年不追剧的“瘦宅”们也开始沉迷其中，大呼真香。

• ### Python爬虫解析当红网剧之《我是余欢水》

而今天小编要探讨的剧集则是有郭京飞、苗苗、高露等实力派演员参演的豆瓣评分7.4分的《我是余欢水》。

• ### 用Python分析《令人心动的offer2》的13万条弹幕，网友们都在吐槽什么？

综艺，是我们劳累了一天的放松方式，也是我们饭后的谈资。看着自己喜欢的综艺，时光足够美。而《令人心动的offer》，就是一个不错的综艺选择。

• ### 《都挺好》弹幕比剧还精彩？394452条弹幕数据来告诉你答案

火到什么程度？微博热搜霸榜，办公室评弹声四起，大强轻松攻占表情包，甚至连N年不追剧的瘦宅们也开始沉迷其中，大呼真香。

• ### 用Python分析《令人心动的offer2》的13万条弹幕，网友们都在吐槽什么？

综艺，是我们劳累了一天的放松方式，也是我们饭后的谈资。看着自己喜欢的综艺，时光足够美。而《令人心动的offer》，就是一个不错的综艺选择。

• ### 干货|Python爬取 201865 条《隐秘的角落》弹幕，发现看剧不如爬山？

? ? 本文不涉及剧透！请放心食用 最近又火了一部国产剧：《隐秘的角落》 如果你没看过，那可能会对朋友圈里大家说的“一起去爬山”、“小白船”、“还有机会吗”...

• ### 这些综艺是挺好看，就是弹幕有点…

? 本文创作：腾讯视频智能弹幕团队 弹（dàn）幕：21世纪互联网颠覆性发明之一。各类网络视频中从右到左横向飘过的评论性语句即为弹幕。不受时间约束，可随意...

• ### 爬取B站20万+条弹幕，我学会了如何成为B站老司机

B站(哔哩哔哩)是国内知名的视频弹幕网站，也是中国最大的年轻人聚集地之一，想要知道B站弹幕爱刷什么梗？不同分区UP主弹幕各有什么特点？如何快速成为B站弹幕老司机...