[Python] 纯文本查看 复制代码
import http.cookiejar
import math
import time
from tkinter import Button, Radiobutton, Entry, StringVar, Tk, IntVar, Checkbutton, messagebox
import matplotlib.pyplot as plt
import requests
session1 = requests.session()
session1.cookies = http.cookiejar.LWPCookieJar(filename = './config/bzcookie-lxswtt.txt') # 需要加载有效的cookie信息文件,自行研究。
session1.cookies.load(ignore_discard = True)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 '
'Edg/116.0.1938.69', 'Referer': "https://www.bilibili.com/"
}
def len_str(string):
count = 0
for ch in string:
if ch >= '\u007f':
count += 1
return count
def get_follow_info(uid, page): # 获取最新关注用户UID,uid为目标up主的uid,page为查询页码,最大20页,一页50个,因此最多可查最新关注的1000粉丝
now_time = time.time()
sub_dic = {}
sub_list = []
mid_list = []
for i in range(1, page):
url = f'https://api.bilibili.com/x/relation/followers?vmid={uid}&pn={i}' # 拼接url,循环查询目标页数的所有粉丝信息
resp2 = session1.get(url = url, headers = headers).json()
if not len(resp2['data']['list']):
print('粉丝数为0')
return 0
if resp2['code'] == 22118:
print('由于该用户隐私设置,粉丝列表不可见')
return 0
sub_list += [li for li in resp2['data']['list']] # 将粉丝信息添加到一个列表中
time.sleep(0.1)
print(f'{i}/{page - 1}')
root.update()
for lists in sub_list: # 从粉丝信息列表提取出有用信息,生成uid列表和关键信息字典
if (now_time - int(lists['mtime'])) > 24 * 3600 and c2.get(): # 实现查询最新24h的粉丝关注情况功能,想要修改时间可以修改数字大小
break
mid = lists['mid']
mid_list.append(str(mid))
sub_dic[f'{mid}'] = {
'uname': lists['uname'], 'sub_time': time.strftime('%Y-%m-%d %X', time.localtime(lists['mtime'])), 'mtime': lists['mtime'], 'uid': mid,
'vip': lists['vip']['vipType']
} # 保存关键信息,用户昵称,关注时间,uid,会员状态
with open('mid.txt', 'w', encoding = 'utf-8') as f: # 保存uid列表
f.write(str(mid_list))
get_follow_level(mid_list, sub_dic) # 根据uid列表获取每个用户的等级
sort(mid_list, sub_dic) # 对数据进行统计
# 绘制涨粉趋势图
init = sub_dic[mid_list[-1]]['mtime']
x_key = []
y_value = []
num = 1
mid_list.reverse()
for mid in mid_list:
int1 = int(sub_dic[mid]['mtime']) - init
x_key.append(int1 / 3600)
y_value.append(num)
num += 1
x_key = [i - x_key[-1] for i in x_key]
plt.plot(x_key, y_value)
plt.show()
def get_follow_level(uid_all, all_dic): # 实现获取用户等级功能
vips = 0
num = 0
c = len(uid_all) // 50
uid_lists = [uid_all[50 * i:50 * (i + 1)] for i in range(len(uid_all) // 50)] # 将uid列表分割为50一组
if len(uid_all) % 50 != 0:
uid_lists.append(uid_all[50 * c:len(uid_all)])
for uid in uid_lists:
strs = ','.join(uid) # 将50一组的uid列表用‘,’合并成一条字符串
url = f'https://api.vc.bilibili.com/account/v1/user/cards?uids={strs}' # 该api可以批量查询B站用户信息,最大50个,需要用','分割
dic_temp = requests.get(url = url, headers = headers).json()
for j in range(len(dic_temp['data'])):
mid = dic_temp['data'][j]['mid']
if dic_temp['data'][j]['name'] != '账号已注销':
all_dic[f'{mid}']['level'] = dic_temp['data'][j]['level'] # 获取用户等级
for k in range(len(dic_temp['data'])): # 将用户信息打印到控制台中
num += 1
width = 36 - len_str(all_dic[uid_all[num - 1]]['uname'])
if all_dic[uid_all[num - 1]]['uname'] != '账号已注销':
print(
f"{num:<4}:{all_dic[uid_all[num - 1]]['uname']:^{width}}Lv:{all_dic[uid_all[num - 1]]['level']:<10}{all_dic[uid_all[num - 1]]['sub_time']:<20} {all_dic[uid_all[num - 1]]['vip']}")
if all_dic[uid_all[num - 1]]['vip']:
vips += 1
else:
print(f"\033[31m{num:<4}:{all_dic[uid_all[num - 1]]['uid']:^36}账号已注销!\033[0m")
time.sleep(0.06) # 设置延时,防止查询过快触发B站风控,尽量不要更改此参数
root.update()
with open('sub_dic.txt', 'w', encoding = 'utf-8') as f: # 保存用户信息
f.write(str(all_dic))
print(f'有大会员记录的粉丝个数为:{vips}') # 打印开过大会员的粉丝用户个数
def sort(uid_all, all_dic): # 对用户信息进行统计
sums = {6: 0, 5: 0, 4: 0, 3: 0, 2: 0, 1: 0, 0: 0}
sum_per = {}
new_sum = {}
for uid in uid_all:
if all_dic[f'{uid}']['uname'] != '账号已注销':
key = all_dic[f'{uid}']['level']
sums[key] = sums.get(key, 0) + 1
for key in sums.keys():
new_sum[f'Lv{key}'] = sums[key]
sum_per[key] = round(sums[key] / len(uid_all), 4)
new_sum['sum'] = len(uid_all)
keys = list(new_sum.keys())
print('\033[31m{:=^86}\033[0m'.format("等级统计"))
print('{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}'.format(keys[0], keys[1], keys[2], keys[3], keys[4], keys[5], keys[6], keys[7]))
print('\033[33m{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}{:^11}\033[0m'.format(sums[6], sums[5], sums[4], sums[3], sums[2], sums[1], sums[0],
new_sum['sum']))
print('\033[32m{:^11.2%}{:^11.2%}{:^11.2%}{:^11.2%}{:^11.2%}{:^11.2%}{:^11.2%}\033[0m'.format(sum_per[6], sum_per[5], sum_per[4], sum_per[3],
sum_per[2], sum_per[1], sum_per[0]))
def start(): # 开始函数
if v1.get(): # v1为查询粉丝数个数,最大值为1000,
page = math.ceil(int(v1.get()) / 50) + 1 # 将粉丝个数转化成页数
if page > 21:
page = 21
else:
page = 21
c2.set(1) # 如果粉丝数输入框为空,则默认查询20页粉丝信息,同时自动勾选24h内的粉丝数
if c1.get(): # c1为单选框变量值,如选择任意,则为0,即查询uid输入框的粉丝信息
get_follow_info(c1.get(), page) # 查询单选框目标的粉丝信息
elif v2.get():
get_follow_info(int(v2.get()), page) # 如果UID输入框不为空,则查询输入框的UID目标的粉丝信息
else:
messagebox.showinfo(title = '提示', message = '请输入UID或勾选某个目标')
return 0
if __name__ == '__main__':
receiver = [{'name': '恬豆', 'uid': 1660392980}, {'name': '梨安', 'uid': 1900141897}, {'name': '又一', 'uid': 1217754423},
{'name': '沐霂', 'uid': 1878154667}, {'name': '星瞳', 'uid': 401315430}, {'name': '露早', 'uid': 1669777785},
{'name': '米诺', 'uid': 1778026586}, {'name': '柚恩', 'uid': 1795147802}, {'name': '莞儿', 'uid': 1875044092},
{'name': '虞莫', 'uid': 1811071010}, {'name': '思诺', 'uid': 3537115310721781}, {'name': '心宜', 'uid': 3537115310721181},
{'name': '嘉然', 'uid': 672328094}, {'name': 'asaki', 'uid': 194484313}, {'name': '任意', 'uid': 0}, ] # 初始设置15个选项,可自行更改里面的数据,需注意UID对应关系
root = Tk()
root.geometry('360x140')
root.title("新关注查询")
c1, c2, v1, v2 = IntVar(), IntVar(), StringVar(), StringVar()
Entry(root, textvariable = v1, width = 10).grid(row = 2, column = 4, rowspan = 1, columnspan = 1) # 创建查询粉丝个数输入框,最大值1000
Entry(root, textvariable = v2, width = 50).grid(row = 1, column = 1, rowspan = 1, columnspan = 5) # 创建UID输入框
for j in range(3):
for i in range(5):
rbtn = Radiobutton(root, text = receiver[j * 5 + i]['name'], value = receiver[j * 5 + i]['uid'], variable = c1)
rbtn.grid(row = 3 + j, column = 1 + i, rowspan = 1, columnspan = 1, sticky = 'S')
Button(root, height = 1, width = 30, text = '查询', command = start).grid(row = 2, column = 1, rowspan = 1, columnspan = 3) # 按照目标列表创建单选框组件
Checkbutton(root, text = "24h内", variable = c2, onvalue = 1, offvalue = 0).grid(row = 2, column = 5, sticky = "S") # 创建查询24h新关注的复选框
root.mainloop()