视频播放量的变化逻辑


前言

以此文记录爬虫逆向学习思路
代理ip+cookie来刷播放

缺陷:据说破站这方面的检测很严格了,这种刷播放的方式,不会真的观看视频,就是点播一下,如果很多播放量都是这种点播而且还都是游客播放b站是能检测到的,检测到就刷了也没用播放量也不会涨的。

一、播放量是怎么变化的?

可能一个网站就有一种变化方式,可能是专门发送请求给服务器进行播放量修改,也可能藏在某个不起眼的请求中,或者是JS代码中的某个参数值。

破站的播放量可以通过发h5请求进行增加。

怎么确定的?
目前也没什么好办法,毕竟一进入播放页浏览器请求一下就冒一大堆,只能一个一个的看,然后去试,看是不是这个请求让播放量增加的。
不过我想了一个思路,就是我刷新两次网页,看两次视频,那么就有2个播放量的增长,也就是两次请求到服务器修改播放量的值,完了我就专门看那些请求次数为2次的请求,去找刷播放量的。

怎么看出来这个请求就是改播放量的?
网上查+感觉+实践

二、抓包

就是它h5
在这里插入图片描述
看看它的请求参数和cookie:
为什么要看cookie?
cookie是可以代表用户身份的,要刷播放,肯定是模仿很多人在看视频,那么就需要知道这些cookie哪些是固定的,哪些是变化,变化的cookie是怎么来的。
在这里插入图片描述

h5请求参数怎么解决

1.先拿多个相同的请求做对比,以排除掉那些参数值一直定死的的参数。
2.看那些会变化的参数可能的具体含义(直接看出来最好办),是不是密文(是密文可能要探索加密逻辑,进行逆向)。

排除掉请求中的定死的参数,后推断出stime,ftime都是时间戳。
bvid是视频id,url中就有。

aidcid 是什么不知道,但是它的来源无非就是其他请求的返回值(cookie /response)或者js代码动态生成的。

拿着aid或者aid的值在浏览器中search就发现了目标:
在这里插入图片描述
那么要拿到这两个参数就只要:

    res = session.get("https://www.bilibili.com/video/BV1rw411X7AN/")
    data_list = re.findall(r'__INITIAL_STATE__=(.+);\(function', res.text) //小细节 \( 转义(是普通( 不是re中的()分组符号
    data_dict = json.loads(data_list[0]) //转为python对象
    aid = data_dict['aid']
    cid = data_dict['videoData']['cid']

COOKIE怎么搞?

和确定参数一点点不同:
1.先拿多个相同的请求做对比,以排除掉那些参数一直定死。
2.cookie的来源:JS代码生成或者其他请求返回

排除固定值的cookie参数后.
列出不固定值得cookie:
buvid3
b_lsid
_uuid
buvid4
sid

buvid3

选中cookie选项:
在这里插入图片描述
然后在h5请求的前面一个个的请求,都是比它先发出去的请求,一个个看:
建议直接↓键刷过去看。快一点,难得点

上图得请求中返回Response Cookies 中就返回了cookie–buvid3的值,搞定一个cookie值.

session可以自动维护非js生成的cookie,那么只要发个请求,这个buvid3值就被记录好了。

res = session.get("https://www.bilibili.com/video/BV1rw411X7AN/")

b_lsid

老办法,在h5请求的前面一个个的请求,都是比它先发出去的请求,一个个看:
建议直接↓键刷过去看。快一点,难得点
发现spi请求中Requests Cookies中带有b_lsid的值,但是在它之前的请求中都没有返回带有该cookie的Response Cookies,Respose中也没有这个参数,
那么就应该是JS代码生成的了

浏览器中search b_lsid或者b_lsid的值来查找JS代码生成逻辑:
细节:还可以搜索setCookie,因为要设定Cookie的值一般就要用这个函数。
细节:搜到后,在Response中右键点击open in source方便打断点

在这里插入图片描述
打断点在setCookie(“b_lsid”,t)发现b_lsid最后等于t,
然后在这个函数里看t的生成逻辑:
细节:cookie具有时效性,不一定会立马失效,既然在之前的请求中生成了cookie还没失效那么在刷新网页时就不用再生成cookie,那么这个断点就没用,因为生成该cookie的代码都不会运行。

怎么办?

打开无痕模式,可以打开一个干净的无cookie的窗口
点击网址栏上的锁清除cookie

value: function() {
        var e = this.splitDate()  //返回时间数据字典
          , t = (0, l.G$)(e.millisecond) //把时间戳向上取整转为16进制的文本后大写
          , r = "".concat((0, l.Q4)(8), "_").concat(t); //concat 字符串拼接 (0, l.Q4)(8)
    // 长度为8每个字符为16*[0,1)后取整转16进制字符串大写不足8位会在前面补0
        this.lsid = r,
        this.time.start = e.millisecond,
        this.time.day = e.day,
        s.Z.setCookie("b_lsid", r, 0, "current-domain") // b_lsid = r
    }

var e = this.splitDate()是干什么的,不知道,鼠标选中看它的值,返回的是时间数据,定位到该函数的内部:

tips: console可以运行JS自带的代码,和浏览器发送请求运行过的代码。

var e = this.splitDate() //返回时间数据字典格式
//等价
value: function(e) {
var t = new Date(e || Date.now())  // 等价于 t = new Date(Date.now()) 等于Fri Dec 08 2023 13:23:10 GMT+0800 (中国标准时间)
  , r = t.getDate() //8 日
  , n = t.getHours() //13 时
  , o = t.getMinutes() //23 分钟
  , i = t.getTime(); //时间戳
return {
    day: r,
    hour: n,
    minute: o,
    second: Math.floor(i / 1e3), //取整
    millisecond: i
}
}
(0, l.G$)(e.millisecond)
//等价
a = function(e) {
                return Math.ceil(e).toString(16).toUpperCase()}
(0, l.Q4)(8)  //长度为8每个字符为随机取16*[0,1)中的值后取整转16进制字符串大写且不足8位会在前面补0
//等价
o = function(e) {
                for (var t = "", r = 0; r < e; r++)
                    t += a(16 * Math.random()); //16*[0,1)后取整转字符串大写 长度为8
                return i(t, e)
            }
a = function(e) {
    return Math.ceil(e).toString(16).toUpperCase()
}
i = function(e, t) {
    var r = "";
    if (e.length < t)
        for (var n = 0; n < t - e.length; n++)
            r += "0";
    return r + e
}

_uuid

步骤依旧:
这里就直接给Js代码分析了

// // uuid=n 标准的uuid码生成
// var n = function() {
//     var e = o(8)
//       , t = o(4)
//       , r = o(4)
//       , n = o(4)
//       , a = o(12)
//       , s = (new Date).getTime(); //时间戳
//
//     return e + "-" + t + "-" + r + "-" + n + "-" + a + i((s % 1e5).toString(), 5) + "infoc"
// }
//
// //
//  o = function(e) {
//                 for (var t = "", r = 0; r < e; r++)  
//生成长度为e每个字符由16*[0,1)的数取整转16进制字符后转大写的字符串t
//                     t += a(16 * Math.random());
//                 //返回字符串如果长度小于e就补前缀0
//                 return i(t, e)}
//
// a = function(e) {
//                 return Math.ceil(e).toString(16).toUpperCase()
//             }
//
//
// //
// i = function(e, t) {
//                 var r = "";
//                 if (e.length < t)
//                     for (var n = 0; n < t - e.length; n++)
//                         r += "0";
//                 return r + e
//             }

buvid4和sid

直接在spi请求中返回了,那么模拟请求就好了:
在这里插入图片描述
响应体返回buvid4:

def b_4():
    resp = requests.get("https://api.bilibili.com/x/frontend/finger/spi")
    data =resp.json()["data"]["b_4"] //b_4和buvid4的值相同,所以取b_4的值
    return data

响应cookies中返回sid:

    res = session.get(
    url='https://api.bilibili.com/x/player/v2',
    params={
        "cid": cid,  //cid 本文h5请求参数分析中得到了来源
        "aid": aid, //cid 本文h5请求参数分析中得到了来源
        "bvid": bvid, //cid 本文h5请求参数分析中得到了来源
    }
    )
    sid = res.cookies.get_dict()["sid"]
    session.cookies.set("sid", sid)

所有请求参数和cookie都搞定后,根据请求发送顺序和cookie的生成逻辑写python代码模拟请求发送
注意:不要忘了固定cookie值和固定请求参数值的给定,时间空间上不要出错。

然后就是ip,一个Ip上发送的很多h5请求可以被破站发现,一发现就可以查出来你在刷播放,可以直接拒绝你的代码请求。

所以花钱上隧道代理:
代理

def get_proxies():
    proxy_host = "tunnel2.qg.net:17955"
    proxy_username = "xxxxxxx"
    proxy_pwd = "xxxxxxxxxxx"

    return {
        "http": "http://{}:{}@{}".format(proxy_username, proxy_pwd, proxy_host),
        "https": "http://{}:{}@{}".format(proxy_username, proxy_pwd, proxy_host),
    }

最后再分享个api,可以监控视频播放量啥的的。

def get_video_id_info(video_url, proxies): //视频链接 接口
    session = requests.Session()
    bvid = video_url.rsplit('/')[-1]
    res = session.get(
        url="https://api.bilibili.com/x/player/pagelist?bvid={}&jsonp=jsonp".format(bvid),
        proxies=proxies
    )
    cid = res.json()['data'][0]['cid']

    res = session.get(
        url="https://api.bilibili.com/x/web-interface/view?cid={}&bvid={}".format(cid, bvid),
        proxies=proxies
    )
    res_json = res.json()
    aid = res_json['data']['aid']
    view_count = res_json['data']['stat']['view']
    duration = res_json['data']['duration']
    print("\n视频 {},平台播放量为:{}".format(bvid, view_count))
    session.close()
    return aid, bvid, cid, duration, int(view_count)
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋刀鱼_(:з」∠)_别急

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值