bilibili网站的视频

目录

效果图

完整代码

实现思路

步骤一: 测试哪个接口是增加播放量的

步骤二: 逆向分析请求携带的参数和cookie

步骤三:

步骤一实现

步骤二实现

请求参数

aid 和 cid

cookie

buvid3 和 b_nut

sid

b_lsid

_uuid

buvid4

步骤三实现

模拟h5请求

挂ip代理

启动函数


效果图

完整代码

  • 先上代码, 简单更改ip代理后可直接运行;
  • 采用的是单线程, 如果需求量大自己改多线程吧
  • reset_session() 函数需要改 添加自己的代理api
  • if __name__ == '__main__':  更改要刷的次数和视频url
  • 某站更新播放次数有1-2分钟左右的延迟, 如果正常运行 播放次数却没变化, 请等待几分钟再看
import re
import time
import uuid
import json
import random
import requestsdef reset_session():header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35'}tiquApiUrl = r'隧道IP接口'apiRes = requests.get(tiquApiUrl, timeout=5)# apiRes.text == ip; 例: 117.94.127.67:11236ipport = apiRes.textglobal sessionsession = requests.session()session.headers.update(header)session.proxies = {'http': ipport, 'https': ipport}def get_aid_cid(url):# 这个请求还返回了两个cookie: b_nut、buvid3 ; session会自动保存res = session.get(url)res_text = res.textstr_data = re.search(r'__INITIAL_STATE__=(.+?);\(func', res_text, flags=re.S).groups()[0]data_dict = json.loads(str_data)aid = data_dict['aid']cid = data_dict['videoData']['cid']# 当前播放量count = data_dict['videoData']['stat']['viewseo']return aid, cid, countdef set_cook_sid(aid, cid):url = r'https://api.bilibili.com/x/player/v2'p = {'aid': aid, 'cid': cid}session.get(url, params=p)def get_b_lsid():# 8位的16进制字符串.字母大写_时间戳的16进制.字母大写n = ''for i in range(8):n += hex(random.randint(1, 16))[2:].upper()t = str(hex(int(time.time()) * 1000)).upper()n = n + '_' + treturn ndef get_uuid():u = str(uuid.uuid4()).upper()# 因为time.time返回的是秒级别的时间戳; js中是毫秒级的, 1秒=1000毫秒,所以 * 1000u = u + str(int(time.time() * 1000 % 1e5)).rjust(5, '0') + 'infoc'return udef get_buvid4(b_lsid, _uuid):# 因为这个请求中携带了 b_lsid、_uuid、CURRENT_FNVAL、b_nut、buvid3 这几个cookie, 所以需要添加上# b_nut、buvid3 这两个是aid和cid的请求返回的session自动添加上了session.cookies.set('b_lsid', b_lsid)session.cookies.set('_uuid', _uuid)res = session.get(r'https://api.bilibili.com/x/frontend/finger/spi')buvid = re.search('"b_4":"(?P<buvid4>.+?)"}', res.text).group('buvid4')return buviddef request_h5(aid, cid, buvid4):url = r'https://api.bilibili.com/x/click-interface/click/web/h5'data = {'aid': aid,'cid': cid,'part': 1,'lv': 0,'ftime': str(int(time.time()) - random.randint(100, 500)),'stime': str(int(time.time())),'type': 3,'sub_type': 0,'refer_url': '','spmid': '333.788.0.0','from_spmid': '','csrf': '',}session.cookies.set('buvid4', buvid4)res = session.post(url, data=data)res_data = json.loads(res.json())if res_data['code'] == 0:return Trueelse:return Falsedef run(c, url):theory_count = 0for i in range(c):reset_session()aid, cid, count = get_aid_cid(url)if theory_count == 0:theory_count = countprint(f'当前播放量: {count}')set_cook_sid(aid, cid)b_lsid = get_b_lsid()_uuid = get_uuid()buvid4 = get_buvid4(b_lsid, _uuid)res = request_h5(aid, cid, buvid4)if res:theory_count += 1print(f'刷取成功, 理论播放量: {theory_count}')session.close()time.sleep(1)continueelse:print('未刷取成功, h5请求返回值不对')if __name__ == '__main__':url = 'https://www.bilibili.com/video/BV1tG41177xj/'# 要刷的播放量次数, 视频连接run(9999, url)

实现思路

步骤一: 测试哪个接口是增加播放量的

这边我测试出是名为 'h5'的接口; 主要是记录逆向, 所以就不细写怎么找的了

步骤二: 逆向分析请求携带的参数和cookie

知道是哪个接口增加播放量后, 开始逆向研究 'h5' 这个请求的参数和cookie是怎么来的

操作: 新建无痕浏览器窗口--按F12--点击'网络'选项卡--在地址栏输入链接并回车

任务一:  找 aid 和 cid

任务二: 找cookie中的 buvid3、b_nut、b_lsid、_uuid、sid、buvid4

CURRENT_FNVAL 通过测试发现是固定值,所以不用找

buvid_fp 通过测试发现不携带也是可以增加播放量的, 所以也不用找

分析 aid、cid 和 cookie

aid、cid 和cookie的来源可能分为如下几种:

  • 固定的
  • 前期请求返回的数据:
    1. cookie
    2. 响应头
    3. 响应体
  • JS算法内部生成的

步骤三:

任务一: 模拟 'h5' 请求

任务二: 判断是否刷播放量成功

每次刷播放量后 理论当前播放量手动+1, 对比实际播放量, 看是否刷新成功

步骤一实现

浏览器设置别自动播放, 新建无痕浏览器, 然后f12点到网络, 清空请求, 再然后播放视频, 就有几个请求, 实在看不出来就用最笨的方法 全部模拟 一个一个试

步骤二实现

请求参数

aid 和 cid

直接在第一个请求里就找到了, 还是比较幸运的

编写代码获取 aid和cid;  ps: 搜索的时候发现当前播放量也在这个json里, 所以就一起带着获取了

def get_aid_cid(url):# 这个请求还返回了两个cookie: b_nut、buvid3 ; session会自动保存res = session.get(url)res_text = res.textstr_data = re.search(r'__INITIAL_STATE__=(.+?);\(func', res_text, flags=re.S).groups()[0]data_dict = json.loads(str_data)aid = data_dict['aid']cid = data_dict['videoData']['cid']# 当前播放量count = data_dict['videoData']['stat']['viewseo']

cookie

buvid3 和 b_nut

同样很幸运, 还是在第一个请求, 找到了 buvid3 和 b_nut

因为session保持会话连接 会自动保存返回的cookie信息, 所以这两个我们不需要进行处理


sid

然后继续一个一个向下找; 又发现了一个sid

编写代码 这是个get请求; 并且传参了aid和cid;  用session访问一次, 自动保存sid

def set_cook_sid(aid, cid):url = r'https://api.bilibili.com/x/player/v2'p = {'aid': aid, 'cid': cid}session.get(url, params=p)

b_lsid

继续向下, 发现这个spi请求多了两个cookie; 并且在之前的响应头 和 响应体中 并没有这两个值的身影, 通过测试 发现也不是固定的, 所以 初步推断出是 内部JS生成的;

通过 搜索 找到 JS中setCookie的位置

先把这段代码拷贝出来; 可以看到 setCookie("b_lsid", t, 0, "current-domain"), 可以确定 t 就是要找的值

function() {var e = this.splitDate(), t = Object(f.b)(e.millisecond), t = "".concat(Object(f.c)(8), "_").concat(t);this.lsid = t,this.time.start = e.millisecond,this.time.day = e.day,c.a.setCookie("b_lsid", t, 0, "current-domain")}

要分析这个 't' 是怎么来的, 所以提取出了这三行要分析的代码

// 首先执行这个函数得到了 变量e
var e = this.splitDate()
// 又执行了 f.b() 把e当作参数传进去了
t = Object(f.b)(e.millisecond)
// 空字符串拼接(f.c(8))
t = "".concat(Object(f.c)(8), "_").concat(t);
c.a.setCookie("b_lsid", t, 0, "current-domain")

第一行: var e = this.splitDate()

在资源面板打开这个JS文件 然后打断点 

跳转到 this.splitDate() 这个函数

拷贝出来

function(e) {
// 3.  t = 实例化了一个时间对象var t = new Date(e || Date.now()), n = t.getDate(), r = t.getHours(), e = t.getMinutes()
//  4. 到这里可以知道 第二行分析的代码 e.millisecond == 时间戳, t = t.getTime();
// 1.先看返回值 返回了一个对象return {day: n,hour: r,minute: e,second: Math.floor(t / 1e3),
// 2.因为上面我们要分析的第二行代码是获取这个对象里的millisecond属性,所以直接看t怎么来的millisecond: t

总结 第一行作用: 创建变量 e = 时间戳

第二行:  t = Object(f.b)(e.millisecond)

现在 参数e.millisecond 知道是时间戳, 然后开始分析f.b函数

一样的操作 定位到函数位置

看到了这个函数; 这个函数有个参数e;  我们知道是 时间戳

function(e) {return Math.ceil(e).toString(16).toUpperCase()}// Math.ceil(e) 时间戳 向上取整(删除小数并+1, 无小数则不变)
// toString(16) 转换成16进制字符串
// toUpperCase() 小写字母转大写

总结 第二行作用: 变量 t = 时间戳的16进制, 16进制中的字母是大写

第三行:  t = "".concat(Object(f.c)(8), "_").concat(t);

老样子 先定位函数, 这里传了个参数 8 进去

// ================== 一 =============
// 1.已知 e == 8
function(e) {
//     2.已知 循环8次, t = ""for (var t = "", n = 0; n < e; n++)
// 3.先分析参数 16 * Math.random() == 16以下的小数 不包含16
// 4. 再看o, 打断点 同样的方式 找到o函数
// 7. 已知 t = 8个 字母大写的 16进制 字符串t += o(16 * Math.random());
// 8. 这里返回了一个函数s 并传参了 t 和 e; 两个参数都已知了, 继续打断点 看s
// 14. 现在 已知 返回了 8位的16进制字符串, 其中的字母都大写return s(t, e)}// Math.random() 随机生成一个 0-1 之间的小数// ================== o函数 =============// 5.已知e == 16以下的小数
o = function(e) {
// 6.  这里返回了16进制(字母大写)的1-16之间的某个数字 (包含1和16)return Math.ceil(e).toString(16).toUpperCase()}// Math.ceil(e) 向上取整
// toString(16) 转换成16进制 字符串
// toUpperCase() 小写字母转大写// ================== s函数 =============
// 9.注意这里 e和t接收参数的位置; 已知e == 16进制字符串  和 t == 8
s = function(e, t) {var n = "";
// 10.如果字符串长度 < 8if (e.length < t)
// 11.循环 8-字符串长度 的次数for (var r = 0; r < t - e.length; r++)
// 12. n拼接0; n += "0";
// 13. 返回了 循环次数的 0, 拼接上 16进制字符串; 也就是说 如果16进制字符串不足8位 左侧补0return n + e}

小总结: Object(f.c)(8) == 8位的16进制字符串.字母大写

再看第三行代码 t = "".concat(Object(f.c)(8), "_").concat(t);

总结 第三行代码作用:  t = 8位的16进制字符串.字母大写_时间戳的16进制.字母大写


上述分析后,  得知b_lsid = 8位的16进制字符串.字母大写_时间戳的16进制.字母大写

python进行还原

def get_b_sid():n = ''for i in range(8):n += hex(random.randint(1, 16))[2:].upper()t = str(hex(int(time.time()) * 1000)).upper()n = n + '_' + treturn n

_uuid

先看一下是不是其他请求的 响应体 和 响应头里发现都没有, 于是通过搜索发现了还是在刚才的这个js文件里

// 0. uuid通用格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12). 其中每个 x 是 0-9 或  a-f 范围内的一个十六进制的数字// 1.跳转到这里可以看到 他们都调用了 a函数 并分别传参了 8、4、4、4、12
// 这里可以确定就是UUID格式, 所以 a函数 可以直接跳过
var r = function() {var e = a(8), t = a(4), n = a(4), r = a(4), o = a(12)
// 2.这里 i = 时间戳, i = (new Date).getTime();
// 3. uuid + s(时间戳 % 1e5, 5)并转换成字符串; 看s函数是什么, 打断点跳转
// 5.  返回 uuid + 时间戳 % 1e5 且 长度为5的字符串 + 'infoc'return e + "-" + t + "-" + n + "-" + r + "-" + o + s((i % 1e5).toString(), 5) + "infoc"}// ==============4. s函数==================// 已知e == 时间戳% 1e5; t == 5
s = function(e, t) {var n = "";
// 如果 时间戳长度 < 5if (e.length < t)for (var r = 0; r < t - e.length; r++)n += "0";
// 返回 时间戳% 1e5, 长度不足5位 左侧补0return n + e}

总结: _uuid = uuid + 时间戳 % 1e5 且 长度为5的字符串 + 'infoc'

现在需要做的就是模拟算法:

1. uuid 直接就可以通过python的uuid模块随机生成

2. 时间戳 % 1e5 , 不足5位左侧补0

3. 拼接 infoc

上代码

def get_uuid():u = str(uuid.uuid4()).upper()# 因为time.time返回的是秒级别的时间戳; js中是毫秒级的, 1秒=1000毫秒,所以 * 1000u = u + str(int(time.time() * 1000 % 1e5)).rjust(5, '0') + 'infoc'return u

buvid4

继续向下点 在这个请求里多了个buvid4,  那么就向上一个一个点, 看是不是其他请求返回的

发现spi这个请求返回值中 b_4的值和 buvid4的值是一样的

那么直接模拟这个请求, 然后获取他的返回值; 上代码

def get_buvid4(b_lsid, _uuid):# 因为这个请求中携带了 b_lsid、_uuid、CURRENT_FNVAL、b_nut、buvid3 这几个cookie, 所以需要添加上# b_nut、buvid3 这两个是aid和cid的请求返回的session自动添加上了session.cookies.set('b_lsid', b_lsid)session.cookies.set('_uuid', _uuid)res = session.get(r'https://api.bilibili.com/x/frontend/finger/spi')buvid = re.search('"b_4":"(?P<buvid4>.+?)"}', res.text).group('buvid4')return buvid

步骤三实现

模拟h5请求

def request_h5(aid, cid, buvid4):url = r'https://api.bilibili.com/x/click-interface/click/web/h5'data = {'aid': aid,'cid': cid,'part': 1,'lv': 0,'ftime': str(int(time.time()) - random.randint(100, 500)),'stime': str(int(time.time())),'type': 3,'sub_type': 0,'refer_url': '','spmid': '333.788.0.0','from_spmid': '','csrf': '',}session.cookies.set('buvid4', buvid4)res = session.post(url, data=data)print(res.text)

挂ip代理

def reset_session():header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35'}tiquApiUrl = r'隧道IP接口'apiRes = requests.get(tiquApiUrl, timeout=5)# apiRes.text == ip; 例: 117.94.127.67:11236ipport = apiRes.textglobal sessionsession = requests.session()session.headers.update(header)session.proxies = {'http': ipport, 'https': ipport}

启动函数

def run(c, url):theory_count = 0for i in range(c):reset_session()aid, cid, count = get_aid_cid(url)if theory_count == 0:theory_count = countprint(f'当前播放量: {count}')set_cook_sid(aid, cid)b_lsid = get_b_lsid()_uuid = get_uuid()buvid4 = get_buvid4(b_lsid, _uuid)res = request_h5(aid, cid, buvid4)if res:theory_count += 1print(f'刷取成功, 理论播放量: {theory_count}')session.close()time.sleep(1)continueelse:print('未刷取成功, h5请求返回值不对')
if __name__ == '__main__':url = 'https://www.bilibili.com/video/BV1tG41177xj/'# 要刷的播放量次数, 视频连接run(9999, url)

某站增加视频播放量-逆向分析相关推荐

  1. 微信视频号逆向分析+核心爬虫代码

    基于微信7.0.12版本,请自寻下载对应微信版本.打开jadx反编译工具自行比对,主要怕你以为我骗你.至于这个爬虫代码如何运行,请关注我的逆向工作台hooker项目:https://github.co ...

  2. 推特开发者账号 V2【推特开发者文档V2系列1】——获取推特视频播放量

    关于推特开发者账号 elevated academic 请看此贴: 推特开发者账号申请权限 或 搜索微信公众号 twitterDeveloper 获得帮助 当我们在浏览推文的时,总能看见有些推文中包含 ...

  3. 【爬虫之路】A站文章围观量B站视频播放量的简单爬虫想法

    众所周知,acfun与bilibili一直是国内受到广泛关注的宅社区以及二次元社区,一直以来我有一个想法,便是如何获知两个网站里最有意思的作品,仅仅依靠官方的推荐并不足以满足个人化的需求. 于是这只小 ...

  4. JS逆向 -- 分析某站aid、cid、w_rid和sid的加密过程

    接上节课内容 JS逆向 -- 分析某站buvid3和_uuid的加密过程 JS逆向 -- 分析某站b_lsid值加密过程 一.清除cookie信息,刷新网页,ctrl+f搜索sid,这样找到的数据是在 ...

  5. 爬取B站视频播放量及数据可视化

    爬取B站视频播放量及数据可视化 1.爬取数据 运行 运行结果 2.数据分析 2.1读取数据 2.2数据预处理 2.3数据可视化 (1)发布数量及播放数量折线图 (2)不同分区的视频发布数量所占百分比, ...

  6. 2019年末逆向复习系列之淘宝M站Sign参数逆向分析

    郑重声明:本项目的所有代码和相关文章, 仅用于经验技术交流分享,禁止将相关技术应用到不正当途径,因为滥用技术产生的风险与本人无关. 这篇文章是<2019年末逆向复习系列>的第一篇:< ...

  7. 【迪大学院】X64X86游戏安全逆向分析相关所有视频链接

    说明:为了方便粉丝们查阅,这里顾把所有视频链接整合了下 1.传奇M多开器演示和最新课程介绍-CSDN直播 2.X86X64游戏安全逆向分析之剑灵2M之背包遍历数据分析-CSDN直播 3.X86X64游 ...

  8. 我的第一个爬虫:request+pyquery爬取B站热门视频标题与播放量

    爬虫步骤 发起请求: 获取响应内容: 解析内容: 保存数据. 具体实现 在写爬虫之前,我们先来看一下要爬取的网页. 上图是B站热门视频排行榜,需要的数据已经在图中标出,即视频名称和播放量. 接下来是具 ...

  9. JS逆向分析新浪某站登录处RSA加密

    文章目录 前言 RSA加解密 核心思想 Pyhon实现 NoPadding 新浪网实战 JS加密分析 JS函数调试 Py调用脚本 BurCrypto爆破 插件介绍 实战案例 总结 前言 在渗透测试过程 ...

最新文章

  1. 获取结构体中变量的偏移量
  2. 吴恩达老师深度学习视频课笔记:多隐含层神经网络公式推导(二分类)
  3. JavaFX项目jar使用javafxpackager生成exe
  4. windchill 可交付成果 文档_敏捷等于没有文档吗?敏捷项目管理VS传统项目管理区别在哪里?...
  5. 亚马逊Rekognition发布针对人脸检测、分析和识别功能的多项更新
  6. linux内核分为子系统,Linux内核内存管理子系统分析【转】
  7. 给大家推荐一款高大上的代码高亮插件(sublime,github风格)——highlight.js
  8. java map 优化_java.util.map和java.util.set的优化实现?
  9. 关于·nowrap与width
  10. C++实现的Miller-Rabin素性测试程序
  11. 获取spring 框架源码方式
  12. 通达信自动交易软件步骤分析
  13. BP神经网络算法基本原理,bp神经网络算法详解
  14. 使用stm32控制驱动步进电机
  15. saltstackmysql return报错
  16. PowerDesigner破解版下载及安装教程
  17. 法语学习笔记——语音
  18. 刀马旦计算机音乐,刀马旦 MIDI File Download :: MidiShow
  19. Python爬虫爬小说《诡秘之主》
  20. arcos的matlab定义,基于MATLAB编程软的齿轮设计

热门文章

  1. python儿童游戏_python 实现儿童算术游戏
  2. Proteus的串口通信仿真实例(八路数据采集系统)
  3. 谷歌云端硬盘 转存_如何合并多个Google云端硬盘和Google相册帐户
  4. Windows文件自动增量备份工具,解放你的双手!
  5. 广东有哪些计算机自主招生的大专学校,广东2017年高职自主招生参与院校28所
  6. 字节跳动文件服务器是什么,字节跳动智能化服务端接口测试解决方案(25页)-原创力文档...
  7. 05组-选题与需求分析报告
  8. Django模型——聚合函数的练习代码
  9. 区块链电子签名技术及方案
  10. 一个简单的影像切片工具,生成xyz格式