python怎么抢东西_让我来告诉你如何用Python秒抢B站一楼!(附源码)

B站的一楼自古都是战火纷飞,尤其是抢热门UP主的一楼更是困难,所以写了一个Python的小程序用来自动抢一楼。以下是教程,想直接用的跳到最后即可。

作者:小火

思路:记录当前UP主的视频数,每秒检测一次视频数是否增加;获取最新视频的av号,利用POST请求发送评论

获取视频数:

开始直接想爬取UP主空间的视频数,发现B站整个网页都是用JS渲染的,因为要想每秒获取一次视频数肯定爬取速度不能太慢,爬完用JS渲染页面势必会影响速度,而且会爬取很多无关内容,所以只能抓包分析。

打开 chrome -> 进入UP主空间(投稿页面) -> 按F12 -> 切换到network -> 刷新页面

u=1059882221,2924868033&fm=173&app=25&f=JPEG?w=640&h=322&s=89A09D1A8C787B8814FD19DF0300C0B3

截获的数据

一个一个往下看找到了一个 navnum 开头的请求,点 Preview 发现返回了一个类似JSON 的格式

u=79273149,2532103352&fm=173&app=25&f=JPEG?w=516&h=471&s=8CA67C33111ED5CC18D581DA000080B1

里面的 video 正是UP主的视频投稿数,但是多了个_jp1

观察链接的后半部分

navnum?mid=221648&jsonp=jsonp&callback=__jp1

mid就是UP主的id号,把后面的callback去掉,粘贴到地址栏访问,终于出来了纯的JSON数据,后来我试了下把jsonp去掉也可以。

Note:直接从这里获取视频数会有个BUG,后面在解释。

获取最新视频

继续往下查找发现了一个 getSubmitVideos 开头的请求,点开后是一个标准的JSON,对比一下发现里面 vlist 就是视频列表,其中列表的第一个的aid就是最新视频的av号

u=3083982878,148459956&fm=173&app=25&f=JPEG?w=640&h=460&s=9C0A7033591EC4CA4CC5B1DA0000C0B1

但是加载了很多其他视频的信息,我们只需要最新的视频,观察一下链接

getSubmitVideos?mid=221648&pagesize=30&tid=0&page=1&keyword=&order=pubdate

发现 pagesize 就是整个列表的个数,改成1再访问,果然这次只返回了1个最新的视频,

但是突然看到了一个 count 的数据竟然是视频数 -_-||。。。。,不过前一个请求数据量更小,所以应该会快一些(也只能这样安慰自己了)。

Note:BUG就在这里,当前一个获得了视频数与这里的不一致,原因是这个视频数的更新会慢一点,也就是有一些延迟,当检测到更新时直接获取最新的视频,得到的不是最新视频而是上一次的视频。解决方法就是统一换成从这里获取视频数。

提交评论

进入视频的评论区,F12,输入评论并提交,截获了一个叫add的POST请求,查看下表单的数据:

u=526645802,44305739&fm=173&app=25&f=JPEG?w=640&h=182&s=5A283C63037B40215A55A0DA0000C0B1

oid是视频av号,message是我的评论,csrf是 跨站请求伪造 (简单来说就是把表单做个唯一标记,保证是你提交的),然后看到了一大堆的cookie,用户验证应该只用到了几个,应该是B站的程序猿为了省事一起提交了。。。如果想要筛选cookie可以先清除B站的cookie,然后从 快速登录入口 调试登录,看看设置了哪些cookie再从里面删除一些看似不重要的,看看是否能评论。这里我直接写出来我筛选的结果,一共需要4个cookie:

"DedeUserID": 用户ID

"DedeUserID__ckMd5": 用户ID_MD5值

"SESSDATA": 会话

"bili_jct": crsf

bili_jct 经过比对就是表单中的 csrf 的值,这两个必须一样,否则会提交失败。cookie的有效期是1个月,一个月后需要重新获取。提交成功后会返回一个json,如果提交成功code==0。

震惊了...印尼学生光着脚踢火焰足球_运动_生活_bilibili_哔哩哔哩www.bilibili.com

u=1043841035,1320080563&fm=173&app=25&f=JPEG?w=180&h=120&s=B6082FEAC6352837704C85080300E0D3

u=3743049770,504810273&fm=173&app=25&f=JPEG?w=639&h=166&s=8EF0E4124B6347245AE184DA000080B2

运行截图

代码

因为之前的那个BUG在运行的时候才发现,为了省事就简单改了下,获取视频数和av号可以合并成一个函数减少冗余;headers直接放在函数里比较好;cookie应该放在外面方便更改;还有些小细节没遵守PEP8;代码仅供参考,最好自己写写。

# -*- coding: utf-8 -*-

import requests

import time

headers = {

'User-Agent': 'Mozilla/5.0'

}

def get_videos_nums(mid):

# 获取视频数

videos_url = "https://space.bilibili.com/ajax/member/"

"getSubmitVideos?mid={}&pagesize=1&page=1&order=pubdate".format(mid)

resp = requests.get(videos_url, headers=headers)

try:

resp_json = resp.json()

except ValueError:

print("json 解析失败:{}".format(resp.text))

else:

return resp_json['data']['count']

return None

def get_video_aid_title(mid):

# 获取av号和标题

videos_url = "https://space.bilibili.com/ajax/member/"

"getSubmitVideos?mid={}&pagesize=1&page=1&order=pubdate".format(mid)

resp = requests.get(videos_url, headers=headers)

resp.raise_for_status()

resp.encoding = 'utf-8'

try:

resp_json = resp.json()

except ValueError:

print("json 解析失败:{}".format(resp.text))

else:

aid = resp_json['data']['vlist'][0]['aid']

title = resp_json['data']['vlist'][0]['title']

return aid, title

return None

def post_comment(aid, message):

# 提交评论

reply_url = "https://api.bilibili.com/x/v2/reply/add"

cookie = {

"DedeUserID": "", # 用户ID

"DedeUserID__ckMd5": "", # 用户ID_MD5值

"SESSDATA": "", # 会话cookie

"bili_jct": "" # crsf cookie

}

request_headers = {

"Cookie": "DedeUserID={DedeUserID}; "

"DedeUserID__ckMd5={DedeUserID__ckMd5}; "

"SESSDATA={SESSDATA}; "

"bili_jct={bili_jct}; ".format(DedeUserID=cookie["DedeUserID"],

DedeUserID__ckMd5=cookie["DedeUserID__ckMd5"],

SESSDATA=cookie["SESSDATA"],

bili_jct=cookie['bili_jct']),

"User-Agent": "Mozilla/5.0",

}

form_data = {

"oid": aid,

"type": 1,

"message": message,

"plat": 1,

"jsonp": "jsonp",

"csrf": cookie["bili_jct"]

}

try:

resp = requests.post(reply_url, headers=request_headers, data=form_data)

resp.raise_for_status()

resp_json = resp.json()

except requests.HTTPError:

print("网络错误")

except ValueError:

print("json 解析失败")

else:

if resp_json.get('code', None) is not None:

if resp_json['code'] == 0:

print("评论成功:{}".format(message))

return True

else:

print("评论失败:{}".format(message))

else:

print("json 格式错误")

return False

if __name__ == '__main__':

mid = 221648 # UP主ID号

message = "怒抢第一" # 留言内容(必须在3-1000个字符以内)

print("执行中")

try:

current_videos_num = get_videos_nums(mid)

target_num = current_videos_num + 1

while target_num != get_videos_nums(mid):

time.sleep(1) # 访问时间间隔(秒)

aid, title = get_video_aid_title(mid)

if post_comment(aid, message):

print("视频{}评论成功".format(title))

else:

print("视频{}评论失败".format(title))

except requests.HTTPError:

print("网络错误")

总结

对于不能直接爬取的页面,抓包分析就显得尤为重要了,目前这个程序只能抢一个UP主的楼,利用多线程可以实现同时抢多个UP主的楼,grequests是一个多线程的requests库,还可以设定抢固定楼层,例如:2333楼,如果各位有兴趣后面再出个多线程版本。

正因为我们自己踩过这样的坑,深知面对一堆专业术语却看不懂的迷茫与挣扎、找了一堆资料却没有一个能把事说明白的痛苦与无奈。所以我想告诉大家学习编程的时候,一个领路人是多么的重要。

期待为你带来改变!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值