手把手教你如何用Python获取爱奇艺电视剧弹幕数据[Python基础]

python

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

以下文章来源于数据STUDIO ,作者龙哥带你飞

Python分析抖音用户行为数据视频讲解地址

https://www.bilibili.com/video/BV1yp4y1q7ZC/

数据获取是数据分析中的重要的一步,数据获取的途径多种多样,在这个信息爆炸的时代,数据获取的代价也是越来越小。因此如此,仍然有很多小伙伴们无法如何获取有用信息。此处以最近的热播排行榜第一名的《流金岁月》为例,手把手教你如何获取爱奇艺电视剧弹幕数据。

 

寻找弹幕信息

爱奇艺的弹幕数据已通过.z形式的压缩文件存在,先通过以下步骤找到弹幕url, tvid列表,再获取压缩文件。利用工具对获取的压缩文件进行解压,处理,存储及分析。

 

绝对,实行多页爬取,需要分析url规律,利用url规律循环请求并获取所需内容。

此弹幕文件url地址为
https://cmts.iqiyi.com/bullet/93/00/6024766870349300_300_1.z
其中tvid = 6024766870349300

url普适形式为
url ="https:
//cmts.iqiyi.com/bullet/{ }/{}/{ }_300_{}.z "其中第一个与第二个花括号内容是tvid后3、4位,,后1、2位。第三个花括号为tvid。第四个花括号为子文件序号,其不是一个无穷大的数,会根据不同的电视剧有不同的最大数。

 

获取弹幕文件

可以利用浏览器通过url直接请求,并获取结果。

 

输入网址可获取弹幕内容的压缩文件文件。

 

利用解压/压缩包zlib对下载下来的压缩文件进行解压查看。

import zlib

from bs4 import BeautifulSoup

with open(r"C:UsersHPDownloads6024766870349300_300_10.z", "rb") as fin:

content = fin.read()

btArr = bytearray(content)

xml=zlib.decompress(btArr).decode("utf-8")

bs = BeautifulSoup(xml,"xml")

bs

输出

 

因此tvid只要获得就能轻松获取该电视剧的弹幕文件数据。

import zlib

from bs4 import BeautifulSoup

import pandas as pd

import requests

def get_data(tv_name,tv_id):

"""

获取每集的tvid

:param tv_name: 集数,第1集、第2集...

:param tv_id: 每集的tvid

:return: DataFrame, 最终的数据

"""

base_url = "https://cmts.iqiyi.com/bullet/{}/{}/{}_300_{}.z"

# 新建一个只有表头的DataFrame

head_data = pd.DataFrame(columns=["uid","contentsId","contents","likeCount"])

for i in range(1,20):

url = base_url.format(tv_id[-4:-2],tv_id[-2:],tv_id,i)

print(url)

res = requests.get(url)

if res.status_code == 200:

btArr = bytearray(res.content)

xml=zlib.decompress(btArr).decode("utf-8") # 解压压缩文件

bs = BeautifulSoup(xml,"xml") # BeautifulSoup网页解析

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")]

data["contents"] = [i.text for i in bs.findAll("content")]

data["likeCount"] = [i.text for i in bs.findAll("likeCount")]

else:

break

head_data = pd.concat([head_data,data],ignore_index = True)

head_data["tv_name"]= tv_name

return head_data

获取tvid

上文已通过tvid获取到了弹幕文件数据,那么如何获取tvid又变成了一个问题。莫急,我们继续分析。直接Ctrl + F搜索tvid

 

因此可以直接从返回结果中通过正则表达式获取tvid。

from requests_html import HTMLSession, UserAgent

from bs4 import BeautifulSoup

import re

def get_tvid(url):

"""

获取每集的tvid

:param url: 请求网址

:return: str, 每集的tvid

"""

session = HTMLSession() #创建HTML会话对象

user_agent = UserAgent().random #创建随机请求头

header = {"User-Agent": user_agent}

res = session.get(url, headers=header)

res.encoding="utf-8"

bs = BeautifulSoup(res.text,"html.parser")

pattern =re.compile(".*?tvid.*?(d{16}).*?") # 定义正则表达式

text_list = bs.find_all(text=pattern) # 通过正则表达式获取内容

for t in range(len(text_list)):

res_list = pattern.findall(text_list[t])

ifnot res_list:

pass

else:

tvid = res_list[0]

return tvid

由此问题tvid。来每一集都有一个tvid,有多少集电视剧就可以获取多少个tvid。那么问题又来了:获取tvid时,是通过url发送请求,从返回结果中获取。而每一集的url又该如何获取呢。

获取每集url

通过元素选择工具定位到集数选择信息。通过硒模拟浏览器获取动态加载信息。

 

有小伙伴会说,可以直接直接从返回内容中获取此href网址啊,你可以自己动手尝试下。

云朵君尝试后得到的结果是href="javascript:void(0);",因此解决这一问题的方法之一是运用硒模拟浏览器获取js动态加载信息。

def get_javascript0_links(url, class_name, class_name_father, sleep_time=0.02):

"""

Selenium模拟用户点击爬取url

:param url: 目标页面

:param class_name: 模拟点击的类

:param class_name_father: 模拟点击的类,此类为class_name的父类

:param sleep_time: 留给页面后退的时间

:return: list, 点击class为class_name进去的超链接

"""

def wait(locator, timeout=15):

"""等到元素加载完成"""

WebDriverWait(driver, timeout).until(EC.presence_of_element_located(locator))

options = Options()

# options.add_argument("--headless") # 无界面,若你需要查看界面内容,可以将此行注释掉

driver = webdriver.Chrome(options=options)

driver.get(url)

locator = (By.CLASS_NAME, class_name)

wait(locator)

element = driver.find_elements_by_class_name(class_name_father)

elements = driver.find_elements_by_class_name(class_name)

link = []

linkNum = len(elements)

for j in range(len(element)):

wait(locator)

driver.execute_script("arguments[0].click();", element[j]) # 模拟用户点击

for i in range(linkNum):

print(i)

wait(locator)

elements = driver.find_elements_by_class_name(class_name) # 再次获取元素,预防StaleElementReferenceException

driver.execute_script("arguments[0].click();", elements[i]) # 模拟用户点击

time.sleep(sleep_time)

link.append(driver.current_url)

time.sleep(sleep_time)

driver.back()

driver.quit()

return link

if__name__ == "__main__":

url = "https://www.iqiyi.com/v_1meaw5kgh3s.html"

class_name = "qy-episode-num"

link = get_javascript0_links(url, class_name, class_name_father="tab-bar")

for i, _link in enumerate(link):

print(i, _link)

主函数

接下来通过主函数将所有步骤串起。

def main(sleep_second=0.02):

url = "https://www.iqiyi.com/v_1meaw5kgh3s.html"

class_name = "select-item"

class_name_father = "bar-li"

links = get_javascript0_links(url, class_name, class_name_father)

head_data = pd.DataFrame(columns=["tv_name","uid","contentsId","contents","likeCount"])

for num, link in enumerate(links):

tv_name = f"第{num+1}集"

tv_id = get_tvid(url=link)

data = get_data(tv_name,tv_id)

head_data = pd.concat([head_data,data],ignore_index = True)

time.sleep(sleep_second)

return head_data

获取到的数据结果如下:

>>> data = main()

>>> data.info()

"""

<class "pandas.core.frame.DataFrame">

RangeIndex: 246716 entries, 0 to 246715

Data columns (total 5 columns):

# Column Non-Null Count Dtype

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

0 tv_name 246716 non-null object

1 uid 246716 non-null object

2 contentsId 246716 non-null object

3 contents 246716 non-null object

4 likeCount 246716 non-null object

dtypes: object(5)

memory usage: 9.4+ MB

"""

>>> data.sample(10)

 

词云图

  • 先分词

运用中文分词库jieba分词,并去除撤销词。

def get_cut_words(content_series):

"""

:param content_series: 需要分词的内容

:return: list, 点击class为class_name进去的超链接

"""

# 读入停用词表

import jieba

stop_words = []

with open("stop_words.txt", "r", encoding="utf-8") as f:

lines = f.readlines()

for line in lines:

stop_words.append(line.strip())

# 添加关键词

my_words = ["倪妮", "刘诗诗", "锁锁", "蒋三岁", "陈道明"]

for i in my_words:

jieba.add_word(i)

# 自定义停用词

my_stop_words = ["哈哈哈","哈哈哈哈", "真的"]

stop_words.extend(my_stop_words)

# 分词

word_num = jieba.lcut(content_series.str.cat(sep=""), cut_all=False)

word_num_selected = [i for i in word_num if i notin stop_words and len(i)>=2] # 条件筛选

return word_num_selected

  • 后画图

运用升级版词云图库stylecloud可视化弹幕结果。

import stylecloud

from IPython.display import Image

text1 = get_cut_words(content_series=data.contents)

stylecloud.gen_stylecloud(text="".join(text1), collocations=False,

font_path=r"‪C:WindowsFontsmsyh.ttc",

icon_name="fas fa-rocket",size=400,

output_name="流金岁月-词云.png")

Image(filename="流金岁月-词云.png")

以上是 手把手教你如何用Python获取爱奇艺电视剧弹幕数据[Python基础] 的全部内容, 来源链接: utcz.com/z/530443.html

回到顶部