前面三节,我们介绍了如何获取动态列表,如何判断抽奖动态是否开奖,如何删除动态,并创建了三个函数,现在我们将三个函数组合调用就能实现自动删除已开奖的官方抽奖动态了。
一、使用data.py剥离保存通用参数
因为我们每次发起请求都会带cookie和headers两组参数,每个人的参数都不一样。另外,因为不同用户的host_mid值不同,在第一步获取动态列表的时候也需要对host_mid做变更,查询动态开奖状态和删除动态时带有的csrf也需要变化,因此,我将需要变动的数据抽离出来放在一个单独的data.py文件里,以便读者使用我的代码时自己替换参数。
#data.py文件,将需变动的数据存放在此,便于替换
cookies = {
#待补充,直接将通过脚本生成的cookies和此处做替换即可
}
headers = {
#待补充,直接将通过脚本生成的headers和此处做替换即可
}
csrf =''#待补充,此处是字符串,比如'21de42957e8840dd09d8bdb2c08c3c2a'
host_mid = #待补充,此处是数值,比如:126369440
现在讲讲如何获取替换上述值
- cookies、hearders和csrf建议可以通过删除动态的api接口脚本获取,不知道怎么获取的可以回顾哔哩哔哩自动批量删除抽奖动态解析篇(三),直接复制粘贴进去就可以
- host_mid点击自己动态列表页就能在网址上看到,将其复制下来即可
二、完整代码文件removeDynamic,py
到这一步我们的代码就基本实现了,现在我们来看看全部的代码文件removeDynamic,py
import datetime
import random
import time
import requests
from data import cookies,headers,csrf,host_mid
#创建Id_str类,保存id_str和orig_id_str值,因为后续还想再提升代码,可能用到更多参数,所以创建类方便一点,有新的属性直接在类中追加即可
class Idstr():
def __init__(self,id_str,orig_id_str):
self.id_str = id_str
self.orig_id_str = orig_id_str
#获取动态列表
def getid_strList():
#获取首次动态列表
response = requests.get(
f'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset&host_mid={host_mid}&timezone_offset=-480&platform=web&features=itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,decorationCard,forwardListHidden,ugcDelete,onlyfansQaCard&web_location=333.999&dm_img_list=[%7B%22x%22:1254,%22y%22:1465,%22z%22:0,%22timestamp%22:69,%22k%22:83,%22type%22:0%7D,%7B%22x%22:1192,%22y%22:-222,%22z%22:6,%22timestamp%22:328,%22k%22:123,%22type%22:0%7D]&dm_img_str=V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ&dm_cover_img_str=QU5HTEUgKEludGVsLCBJbnRlbChSKSBVSEQgR3JhcGhpY3MgKDB4MDAwMDhBNTYpIERpcmVjdDNEMTEgdnNfNV8wIHBzXzVfMCwgRDNEMTEpR29vZ2xlIEluYy4gKEludGVsKQ&dm_img_inter=%7B%22ds%22:[%7B%22t%22:0,%22c%22:%22%22,%22p%22:[57,19,19],%22s%22:[39,5076,5194]%7D],%22wh%22:[3660,5940,36],%22of%22:[54,108,54]%7D&x-bili-device-req-json=%7B%22platform%22:%22web%22,%22device%22:%22pc%22%7D&x-bili-web-req-json=%7B%22spm_id%22:%22333.999%22%7D&w_rid=8e093107e54b60fd35b846430c892e8e&wts=1726583398',
cookies=cookies,
headers=headers,
).json()
data = response['data']
id_strList = [] #保存动态列表参数值
flag = True
while flag:
items = data['items']
for item in items:
if item.get('orig'):#因为抽奖动态都是转发的,我们原创的动态属于非转发,不会有orig数据,在此过滤掉,不做删除
id_str = item['id_str']
orig_id_str = item['orig']['id_str']
new_idstr = Idstr(id_str,orig_id_str)#生成id_str对象
id_strList.append(new_idstr)#将对象保存进列表
offset = data['offset']#获取offset的值,以便获得后续的动态链接
response = requests.get(
f'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset={offset}&host_mid={host_mid}&timezone_offset=-480&platform=web&features=itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,decorationCard,forwardListHidden,ugcDelete,onlyfansQaCard&web_location=333.999&dm_img_list=[%7B%22x%22:1254,%22y%22:1465,%22z%22:0,%22timestamp%22:69,%22k%22:83,%22type%22:0%7D,%7B%22x%22:1192,%22y%22:-222,%22z%22:6,%22timestamp%22:328,%22k%22:123,%22type%22:0%7D]&dm_img_str=V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ&dm_cover_img_str=QU5HTEUgKEludGVsLCBJbnRlbChSKSBVSEQgR3JhcGhpY3MgKDB4MDAwMDhBNTYpIERpcmVjdDNEMTEgdnNfNV8wIHBzXzVfMCwgRDNEMTEpR29vZ2xlIEluYy4gKEludGVsKQ&dm_img_inter=%7B%22ds%22:[%7B%22t%22:0,%22c%22:%22%22,%22p%22:[57,19,19],%22s%22:[39,5076,5194]%7D],%22wh%22:[3660,5940,36],%22of%22:[54,108,54]%7D&x-bili-device-req-json=%7B%22platform%22:%22web%22,%22device%22:%22pc%22%7D&x-bili-web-req-json=%7B%22spm_id%22:%22333.999%22%7D&w_rid=8e093107e54b60fd35b846430c892e8e&wts=1726583398',
cookies=cookies,
headers=headers,
).json()
data = response['data']
if data['has_more']:#判断是否是最后一批动态数据,如果不是,循环继续,直到has_more为false
continue
else:
flag = False #当循环为false时,说明是最后一批动态数据了,我们将本次获得的动态数据加入列表就能退出循环了
items = data['items']
for item in items:
if item.get('orig'):
id_str = item['id_str']
orig_id_str = item['orig']['id_str']
new_idstr = Idstr(id_str, orig_id_str)
id_strList.append(new_idstr)
sleep_time = random.randint(1, 4)#随机生成数字1,2,3,4
time.sleep(sleep_time)#由于爬虫速度较快,短时间发送大量请求极易被服务器判定为恶意攻击,因此随机停顿1~4秒模拟是人工操作
return id_strList
#判断抽奖动态是否未开奖,默认返回True
def isAlive(orig_id_str):
params = {
'business_id': orig_id_str,
'business_type': '1',
'csrf': csrf,
'web_location': '333.1330',
}
res = requests.get(
'https://api.vc.bilibili.com/lottery_svr/v1/lottery_svr/lottery_notice',
params=params,
cookies=cookies,
headers=headers,
).json()
sleep_time = random.randint(1, 4)#随机生成1-4秒延迟,避免过快访问接口而被封杀
time.sleep(sleep_time)
data = res['data']
timestamp =data.get('lottery_time')
if timestamp:
lefttime = datetime.datetime.fromtimestamp(timestamp)#格式化时间戳
now = datetime.datetime.now()#获取当前时间
lefts = lefttime - now#时间戳是一段int值,其实我们也可以获取现在的时间戳,两个数值相减效率可能更快,但是我想看具体开奖时间,所以用了格式化方式
return lefts > datetime.timedelta(0)#比较时间差是否大于0
return True#非官方抽奖工具动态默认返回True,避免删除
#删除动态
def remove(id_str):
sleep_time = random.randint(1, 4)#随机停滞1-4秒
time.sleep(sleep_time)
params = {
'platform': 'web',
'csrf': csrf,
}
json_data = {
'dyn_id_str': id_str,
'dyn_type': 1,
'rid_str': id_str,
}
response = requests.post(
'https://api.bilibili.com/x/dynamic/feed/operate/remove',
params=params,
cookies=cookies,
headers=headers,
json=json_data,
)
#main函数组装调用各个函数
def main():
id_strList = getid_strList()
id_len = len(id_strList)
print('您转发的总动态数为:',id_len)
id_len = id_len-1#让删除动态从末置位开始往前删除
while id_len>=0:
id_item = id_strList[id_len]
if not isAlive(id_item.orig_id_str):
print(id_item.orig_id_str,"抽奖动态已开奖","正在删除您的动态:",id_item.id_str)
remove(id_item.id_str)
id_len = id_len-1#不管动态是否需要删除,都更新id_len的值,因为我们是根据索引获取id_str的值,如果不递减,会陷入死循环
print(id_len)
if __name__ == '__main__':
main()
这里我们看下main()函数,首先我们获取动态列表,因为抽奖动态多的情况下,新的抽奖动态一般还没开奖,历史越久远的越可能开奖了,所以我通过列表索引从后往前遍历列表,判断动态是否开奖了并删除已开奖的转发动态,当然从前往后遍历也是一样的,但是刚开始执行你可能看不出效果,从后往前删一下子就能看到效果,满足感是不一样的。
三、总结感言
到这里我们使用python自动批量删除已开奖的抽奖动态到这里就简单完成了,因为也是刚接触,编写的代码可能不符合开发者规范要求,也没对代码运行异常等功能做处理报错,比如
未更新cookies,headers,csrf等值直接执行代码,虽然获取动态列表应该没有问题,但是查询动态状态和删除动态时代码可能能正常运行,不会报错,但是动态就是没有删除。这些只能后续继续学习并完善代码。
四、改进目标
1、cookies、headers、csrf、host_mid都是能通过前端JavaScript代码自动获取和更新的,现在完成的版本需要通过手动配置参数,对于一些新手读者不太友好,下一步可以往代码运行后,只需要读者登录B站,就能自动获取对应参数并执行,这才是理想状态
2、完善现有代码执行过程中捕获异常并抛出对应异常信息的能力,使代码更加健全
3、编写代码的过程中,刚开始代码都能正常运行,执行多次后,估计是被判定爬虫了,开始限制我过快访问api接口,没办法只能使用time.sleep()函数动态休眠几秒,下一步可以尝试隐藏自己的IP地址,没钱开代理服务器,计划用python的Tor模块实现
4、尝试使用多线程的方式删除动态提高效率
码云代码链接
哔哩哔哩自动批量删除抽奖动态——使用篇
哔哩哔哩自动批量删除抽奖动态解析篇(一)
哔哩哔哩自动批量删除抽奖动态解析篇(二)
哔哩哔哩自动批量删除抽奖动态解析篇(三)
哔哩哔哩自动批量删除抽奖动态解析篇(四)