目录
背景
前几天看了隐秘的角落,觉得这剧真心不错,于是乎就像看看大家是否和我的看法一致,找了一圈没找到完整的爬虫代码,都藏着掖着的干啥啊,能恰饭吗!!!算了,利用他们提供的部分信息自己写一个吧。
爬虫分析
傻瓜式分析
打开一看,弹幕的格式是固定在DIV里面的,但是会实时更新,所以傻瓜式的操作别想了。
那咋办,小神童的我能放弃么? Ctrl+Shift+C 直接打开审查面板,切换到Network界面 ,Ctrl+R刷新一下,响应请求就开始了。
进阶式分析
根据残缺不全的指引,搜索了bullet(弹幕的英文翻译),诶嘿,一个标识映入眼帘,多打开几个看看,对比对比有没有啥规律,巧了,还真的有。
初步判断完毕,一复制该网址就会下载一个压缩包,压缩包里面就是弹幕,下面我只要把每集的弹幕压缩包都下载下来就行!!!这里还有两个问题
- 第一尝试直接下载解压压缩包是不行的,需要解析,这里详见StackFlow解决办法
- 既然要分集数爬取,自然要判断每个集数的id,上面初步判断电视剧id标错了,真实的电视剧id是albumid,直接在面板搜索albumid进行查找,果然有这个东西。
傻瓜式复制到新窗口里看看是不是(这里就是凭借着我聪慧的小脑瓜判断),拿到json格式数据基本就可以宣告胜利了。
万事具备,只欠东风,一个字,干!!!
实战代码
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@Author : {Jack Zhao}
@Time : 2020/6/29 10:39
@Contact : {[email protected]}
@Desc : 隐秘的角落弹幕爬取复现
'''
import json
import zlib
import pandas as pd
import requests
from bs4 import BeautifulSoup
from threading import Thread
def get_IQ_data(tv_index,tv_id):
'''由上文分析可知,只需要知道tvid,即可下载对应的弹幕压缩包'''
url = 'https://cmts.iqiyi.com/bullet/{}/{}/{}_300_{}.z'
datas = pd.DataFrame(columns=['uid','contentsId','contents','likeCount'])
for index in range(1,20):
# 这里每一集的时长所对应的弹幕有好多个压缩包,为压缩包连续编号,最好从头看到尾,这里我没耐心看盲猜小于20个
# 后分析发现,弹幕文件每5分钟(300秒)向服务器请求一次,故每集弹幕文件数量等于视频时间除以300之后向上取整,实际编程时这里可以简单处理
myUrl = url.format(tv_id[-4:-2],tv_id[-2:],tv_id,index)
# print(myUrl)
res = requests.get(myUrl)
if res.status_code == 200:
btArr = bytearray(res.content) # 需要解码
xml = zlib.decompress(btArr).decode('utf-8')
bs = BeautifulSoup(xml,"xml") # 解析xml文档
data = pd.DataFrame(columns=['uid','contentsId','contents','likeCount'])
data['uid'] = [i.text for i in bs.findAll('uid')] # 用户编号
data['contentsId'] = [i.text for i in bs.findAll('contentId')] # 弹幕对应ID
data['contents'] = [i.text for i in bs.findAll('content')] # 内容
data['likeCount'] = [i.text for i in bs.findAll('likeCount')] # 他人点赞该弹幕的数量
else:
break
datas = pd.concat([datas,data],ignore_index = True) # 一集中所有弹幕数据录入一个df,不设置ignore的话会出现index重复
datas['tv_name'] = str(tv_index) # 增加一列作为集数标识
return datas
def get_TV_Id(aid):
'''每一集的tvid其实是由albumid生成的,具体Find - album找到info即可'''
tv_id_list = []
for page in range(1,2):
url = 'https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid=' \
+ aid + '&page='\
+ str(page) + '&size=30'
res = requests.get(url).text
res_json = json.loads(res)
# 视频列表
movie_list = res_json['data']['epsodelist']
for j in movie_list:
tv_id_list.append(j['tvId'])
return tv_id_list
if __name__ == '__main__':
# album id
my_aid = '252449101'
my_tv_id_list = get_TV_Id(my_aid) # 获得电视剧集数
print("下面是TV_ID列表:")
print(my_tv_id_list)
data_all = pd.DataFrame(columns=['uid', 'contentsId', 'contents', 'likeCount','tv_name']) # 同样设置一个总表作为产出
for index,i in enumerate(my_tv_id_list):
#data = get_data('隐秘的角落第'+index+'集',str(i))
# 下一步可Thread改造成多进程
data = pd.DataFrame(get_IQ_data(index, str(i)))
data.to_csv('./'+str(index+1)+'.csv')
data_all = pd.concat([data_all, data], ignore_index=True) # 存入总表
print("12集弹幕已经存入csv文件中")
data_all.to_csv('data_all.csv')
print('总表已经合并完成,已存为csv')
结果展示
多线程操作很简单的,详见多线程教学。
最后的数据大概有20w条左右吧,等有时间再用Pyecharts分析分析,顺便复习一下基操,see you 呐啦。