因为一部遮天,我用三种语言实现了腾讯国漫评分系统(一)

前言

"仙路尽头谁为峰,一见无始道成空。"

2013年初读遮天,十年后遮天的动漫正式上线。依稀记得高中记忆力"三十年河东三十年河西"的萧炎和独断万古的荒天帝。不知道当年经典绝伦的小说,如今改成动漫口碑如何。

于是就打开腾讯视频看看评分,每个视频都要点开才能看到评分和介绍。随即就萌生了用技术整合国漫评分内容的想法。最后历经一周,完成了一个简单的评分展示系统。

静态展示:

动态展示:

一. 国漫数据采集

分析评分数据

首先进入一个动漫的播放页,页面主要有左侧的评分数据,和右侧的简介数据。

评分数据获取

json 复制代码
POST https://pbaccess.video.qq.com/trpc.message.grade_adapter.GradeService/GetGradeDetail?video_appid=3000010&vplatform=2

{
  "cid": "mcv8hkc8zk8lnov"
}

先研究一下评分数据如何获取,在控制台可以找到从后台请求的数据内容。

从请求返回的数据可以看到,可以获取到评分、点评人数、推荐比例等数据。接着对url进行分析,看如何才能获取到这些数据。

可以看到GetGradeDetail 的url,只有一个cid参数。

简介数据获取

json 复制代码
POST https://pbaccess.video.qq.com/trpc.universal_backend_service.page_server_rpc.PageServer/GetPageData?video_appid=3000010&vplatform=2&vversion_name=8.2.97
{
  "req_from": "web",
  "cid": "mzc00200s86alsp",
  "vid": "a0047tbsjbs",
  "lid": "",
  "page_type": "detail_operation",
  "page_id": "detail_page_introduction"
}

这里需要两个参数,cid和vid,根据我的理解,cid就是cartoon_id,是一部动漫的唯一标识,vid是video_id,是每部动漫每一集的唯一标识。那么就来看cid和vid是如何来获取。

我是通过国漫列表页跳转到播放页的,所以就去列表页看看如何获取cid。

国漫列表

进入腾讯视频的国漫列表,看一下国漫列表。

这种有侧边栏的网站,基本上都是异步请求数据,然后渲染到展示区域。下拉动漫列表:

可以看到动漫区域一直在刷新,这样就肯定了之前的想法。

cid

1. 分析请求

F12进入开发者工具,通过搜索能功能找到对应的url。

这里可以看到每部动漫的cid。然后对playload进行分析,查看请求的参数信息。

参数是一个json串,有很多参数,我们通过查看js源码,来确定这些参数是如何生成的。

2. 分析参数

通过搜索来找到对应的请求部分源码:

可以看到请求参数里面有:x、l、R、n、video_guid几个可变参数。通过分析和debug最后得知,每次请求的变化的只有x,即page_index和page,其他的参数都是固定值。

这里就举例一下:比如channel_id对应的n为什么是100119。

最后一行有个vS()方法,就是调用了上面的请求,i.value对应的就是形参n。i的生成可以在第五行代码中看到,用了一个lambda函数,遍历过滤n.channelListData.channleList。打印此变量:

过滤条件就是是channel_ename == t.channelId,这里的t.channelId通过打印发现是"cartoon",可以看到channel_ename为cartoon对应的channel_id为100119.

那么t是怎么来的呢,t是setup的参数,而setup是用来解构props的,所以t就是props,props在vue中用来接收父组件传值。

所以t就是父组件传给渲染动漫列表的组件一个参数值,其中包含channel_id。接下来的工作就是获取vid。

3. 获取cid

上面已经分析完请求了,接着就是利用python的requests模块,构建请求.通过对返回的json分析,获取目标数据。

从最后一行代码可以看到,数据在CardList[1]中获取,然后层层解构,遍历获取cid。

这样就将第一页前30个国漫的cid获取到了。当我修改变量获取第二页数据,即index = 1的时候,程序开始报下标越界的错误,那么应该是没有获取到数据,我们debug一下。

可以看到第一页数据,是从CardList[1] 获取,第二页数据就变成了CardList[0]。这是因为请求第一页的时候,需要返回筛选条件列表,放在了CardList[0]中。到了第二页就不需要了,所以这里要修改代码做判断。

然后就是对爬取的index做一个限制,目前设置为20次,即爬取20页,爬取每一页sleep(3)。这样就可以获取所有动漫的cid。

vid

我们在国漫列表页点击连接进入播放页的时候,是先进入v.qq.com/x/cover/[ci...

我们先对cid.html页面进行分析。

在html网页中发现了vid的列表信息,对于网页中数据的提取一般使用正则表达式。这样在我们获取了cid之后,就能获取vid。

至此,cid和vid都获取到了。

获取评分和简介

首先构建请求参数,cid和vid设置为空字符。

将cid放到参数中,发起评分grade_url请求。

来获取image_url(封面图片url)、热度、评分、推荐区间比例等数据。接着将cid、vid(从vids列表中任取一个即可)放到动漫简介请求参数中,发起请求。

从返回值可以获取到各种标签数据,对json解析,获取自己需要的数据。

封面图片处理

从获取的image_url中可以下载封面图片,图片存储我准备了三种方案:

  1. 将image_url直接存入,通过url直接引用
  2. 将图片下载到本地目录,然后通过命名的方式与动漫信息关联
  3. 将图片转换成base64存入到MySQL中

方案一可能会在请求的时候出现跨域等问题,而且必须联网,从而请求失败。方案二将图片下载到本地,比较方便。方案三就是会对服务器网络和MySQL的IO造成压力,这里是测试,所以问题不大,这里我选用了方案三。

从image_url中获取图片bytes,然后经过一些工具类转换成base64字符串。

python 复制代码
urllib.request.urlretrieve(url=image_url, filename='tmp.jpg')
image_source = Image.open('tmp.jpg')
byte_source = BytesIO()
image_source.save(byte_source, format="JPEG")
byte_data = byte_source.getvalue()
base64_str = base64.b64encode(byte_data).decode("ascii")

从image_url请求的是avif的bytes,这里我直接使用urllib将图片下载保存成jpg格式。然后利用Image和BytesIO模块将二进制转换成base64的字符串。

在img标签中,通过src引入base64和引入图片路径是一样的效果。

但是这个方案在最后又被否决了,原因就是:转换成base64之后,MySQL中的varchar和Text都装不下,所以我又选择了方案二,将图片按照cid命名下载到了本地。

数据存储

设计一个存储模块,将上面的评分数据和简介数据存储到MySQL中,这里先根据定义表、数据字段。

建表

sql 复制代码
create table cartoon(
  cid varchar(35) not null primary key,
  name varchar(50),
  title varchar(100),
  score varchar(5),
  promoter_score varchar(20),
  evaluate_number varchar(30),
  type_ varchar(4) comment '类型id',
  year varchar(10),
  tag_text varchar(10) comment 'VIP' ,
  main_genres varchar(20) comment '类型',
  hotval varchar(20) comment '热度',
  episode_all int(8) comment '全集',
  dimension varchar(100) comment '评分比例',
  update_notify_desc varchar (100) comment '更新周期',
  update_time varchar(20) comment '自定义数据修改日期',
  cover_description text comment '描述'
) default charset='utf8';

进入MySQL执行建表语句

开发程序

利用python的pymysql开发数据存储模块,这里一共简单实现了两个功能:

  1. 根据cid判断数据库中有没有这条数据存在
python 复制代码
sql = f"select cid from cartoon where cid = '{cid}'"
cursor = conn.cursor()
cursor.execute(sql)
result = cursor.fetchone()
if result:
    # 可以更新评分、热度、时间等字段
    print(name, '已经存在于数据库中...')
    continue

如果存在于数据库的话,可以执行update更新评分、热度等信息,这里先不实现,只是使用continue跳出循环,然后采集下一条数据。在程序的运行过程中,如果出现异常,重新启动程序,这些数据就可以避免再重新获取。

  1. 数据存储到MySQL
python 复制代码
sql = f'''insert into cartoon (cid, name, title, score, promoter_score, evaluate_number, type_, year, tag_text, main_genres, hotval, episode_all, dimension, update_notify_desc, update_time, cover_description) 
     values ('{cid}', '{name}', '{title}', '{score}', '{promoter_score}', '{evaluate_number}', '{type_}', '{year}', '{tag_text}', '{main_genres}', '{hotval}', '{episode_all}', '{dimension}', '{update_notify_desc}', '{update_time}', '{cover_description}')'''
cursor = conn.cursor()
cursor.execute(sql)
conn.commit()

启动程序,开始爬取数据。

最后在数据库中查看爬取的国漫信息。

数据采集优化

上面请求的数据都是json格式,因为不是所有的json返回的都是全字段,很多的json都没有一些字段。所以在爬取过程中,需要根据报错信息一直调整自己的代码。

例如在解析字符串的时候,判断json里是否有这个字段,json中的json是否是NoneType,否则都会报错。下面就是针对于评分数据json的处理:

从图中可以看到,动漫信息可能是从enough 或者lack字段获取,而且还有是NoneType。我对这种情况的处理就是:如果没有评分数据,通过continue跳出这个国漫信息的爬取。

结语

本篇文章详细介绍了,如何使用python爬虫获取腾讯国漫信息,从程序开发思路和程序设计的脚步逐步深入,采集数据放到了MySQL中。下一篇文章会讲讲使用vue如何开发评分系统的前端页面。

相关推荐
brzhang8 分钟前
别再梭哈 Curosr 了!这 AI 神器直接把需求、架构、任务一条龙全干了!
前端·后端·架构
安妮的心动录22 分钟前
安妮的2025 Q2 Review
后端·程序员
程序员爱钓鱼22 分钟前
Go语言数组排序(冒泡排序法)—— 用最直观的方式掌握排序算法
后端·google·go
Victor3561 小时前
MySQL(140)如何解决外键约束冲突?
后端
Victor3561 小时前
MySQL(139)如何处理MySQL字符编码问题?
后端
007php0073 小时前
服务器上PHP环境安装与更新版本和扩展(安装PHP、Nginx、Redis、Swoole和OPcache)
运维·服务器·后端·nginx·golang·测试用例·php
武子康5 小时前
Java-72 深入浅出 RPC Dubbo 上手 生产者模块详解
java·spring boot·分布式·后端·rpc·dubbo·nio
椰椰椰耶7 小时前
【Spring】拦截器详解
java·后端·spring
橡晟8 小时前
深度学习入门:让神经网络变得“深不可测“⚡(二)
人工智能·python·深度学习·机器学习·计算机视觉