python b站动态转发、动态评论区抽奖(已打包成exe,可以下载食用)

前言

更新日志

2022-5-28 由于发现b站api变更,更新新版本v3.6进行适配
2022-8-1 更新兼容视频动态版本v3.7
2022-9-20 基于ttk库优化UI,发布版本v3.8

简述

b站动态评论+视频评论区 抽奖2合1 JS版本发布后,计划了这次的python版本,本来的预期是实现同功能的python版并挂我服务器上免费提供抽奖服务来着。不过写着写着突然发现了之前对API的解析有所漏洞,导致我发现了一个新bug。。。(居然没人提醒我)
在这里插入图片描述
旧程序将全部的自发型动态归为type=11,今天测试时发现居然还有type=17和1的情况
请添加图片描述
于是乎 我就把原来的JS版的也改了,顺便把python的动态评论区抽奖给写了。动态转发也根据Hack Inn大佬之前提供的源码,进行了python3版本的简单适配,因为我懒了0.0
python版本:3.8.5
工程构建:pycharm

代码/exe下载

代码下载:GitHub 码云
exe程序下载:GitHub 码云(温馨提示:请勿随意执行来历不明的程序)
在这里插入图片描述
在这里插入图片描述

效果图

GUI版-v3.8

在这里插入图片描述

GUI版-v3.7

请添加图片描述

cmd版本

在这里插入图片描述

【b站抽奖】Python实现 动态转发、动态评论抽奖,实际程序演示+粗略讲解

使用说明

GUI版本使用方法类似

1、双击运行bat文件

在这里插入图片描述

2、输入抽奖类型(数字) 然后“回车”

(1评论 0转发)
在这里插入图片描述

3、粘贴入 动态页面的链接 然后“回车”

因为动态又改版了,?后面的东西都不要复制了
注意,链接后的 ?tab=2 也需要复制过来,因为做了动态类型的识别,这也做为关键参数需要检测。
在这里插入图片描述

4、输入中奖人数(要是数字) 然后“回车”

因为我没做校验(懒)
直接就运行完成了。会爬取所有评论人的数据到数据库(自动去重)
数据库文件在同一文件夹下“user_data.db
然后会直接抽取中奖用户并打印,复制中奖信息即可。
最后输入数字1,退出程序。
在这里插入图片描述

所有评论人员数据查看

评论人员数据存储于同一文件夹的“user_data.db”中
在这里插入图片描述
sqlite数据库,我使用 sqlitebrowser打开这个db文件
可以看到我们的user表
在这里插入图片描述
点击“浏览数据”,选择我们要查看的user表,即可看到所有用户数据
在这里插入图片描述
当然你也可以用网上的 随机数程序生成随机数,然后进行抽奖,问题不大0.0

源码

GUI版本-v3.8

# -*- coding: utf-8 -*-
import json
import time
import random
import urllib.request
import urllib.parse
import sqlite3
import tkinter
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
from ttkbootstrap.scrolled import ScrolledText

# python版本:3.8.12
# 打包 pyinstaller -F 1.py

# 获取抽奖类型
global draw_type
global referer
# 中奖人数
global lucky_num
global dynamic_id
global text_str
# 动态类型
global api_type

api_type = 11
draw_type = 1
dynamic_id = ""
# 打印文本框
text_str = ''

# 数据集合
id_set = set()
name_set = set()
lucky_set = set()

headers1 = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Content-Type': 'text/plain;charset=UTF-8',
    'Referer': 'https://t.bilibili.com',
    'origin': 'https://t.bilibili.com',
    # 'cookie': 'l=v',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 '
                  'Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400 '
}


# 字符串是否是数字
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass

    return False


# 配置数据库
def config_db():
    global con, cur
    global text_str
    # print("开始创建数据库...")
    text_str = "开始创建数据库...\n"
    text.insert(END, text_str)
    text.update()
    con = sqlite3.connect("user_data.db")
    cur = con.cursor()
    # 创建表user
    sql = "CREATE TABLE IF NOT EXISTS user(mid TEXT PRIMARY KEY,uname TEXT,message TEXT)"
    cur.execute(sql)
    # 情况表数据
    sql = "delete from user"
    cur.execute(sql)


# 获取oid、转发数、评论数函数
def get_oid():
    global text_str
    global dynamic_id
    global api_type
    global text

    if referer[8] == 't':
        # print('解析为动态页面')
        text_str = "解析为动态页面\n"
        text.insert(END, text_str)
        text.update()
    else:
        # print('解析为视频页面')
        text_str = "解析为视频页面\n"
        text.insert(END, text_str)
        text.update()

    tab_type = "2"

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    # if referer[-6:-1] == "?tab=":
    #     dynamic_id = referer[23:len(referer) - 6]
    #     tab_type = referer[-1]
    # else:
    #     dynamic_id = referer[23:len(referer)]

    temp = referer.split('?')
    temp2 = temp[0].split('/')
    dynamic_id = temp2[3]

    # print("dynamic_id=" + dynamic_id)
    text_str = "dynamic_id=" + dynamic_id + "\n"
    text.insert(END, text_str)
    text.update()

    if len(dynamic_id) == 0:
        # print("dynamic_id异常,程序终止,请检查您的输入是否有误!")
        text_str = "dynamic_id异常,程序终止,请检查您的输入是否有误!\n"
        text.insert(END, text_str)
        text.update()
        base_info = {'ret': False}
        return base_info

    # payload = {'dynamic_id': dynamic_id}
    payload = {'timezone_offset': '-480', 'id': dynamic_id}
    data = urllib.parse.urlencode(payload)
    # print(data)

    req = urllib.request.urlopen('https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?%s' % data)
    # req = urllib.request.urlopen('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?%s' % data)
    ret = req.read().decode()

    # print(ret)
    json1 = json.loads(ret)
    oid = json1["data"]["item"]["basic"]["comment_id_str"]
    repost = json1["data"]["item"]["modules"]["module_stat"]["forward"]["count"]
    # oid = json1["data"]["card"]["desc"]["rid"]
    # repost = json1["data"]["card"]["desc"]["repost"]

    comment = 0
    # 非视频动态
    if tab_type == "2":
        comment = json1["data"]["item"]["modules"]["module_stat"]["comment"]["count"]
    else:
        comment = 0
    # 判断动态类型
    api_type = json1["data"]["item"]["basic"]["comment_type"]
    # print("oid=" + str(oid))
    base_info = {'ret': True, 'oid': oid, 'repost': repost, 'comment': comment}
    # print(base_info)
    return base_info


# 获取用户信息函数
def get_user_info(base_info):
    global text_str
    global api_type
    global text

    # print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(END, text_str)
    text.update()
    if int(api_type) == 17:
        # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
        if referer[-6:-1] == "?tab=":
            base_info["oid"] = referer[23:len(referer) - 6]
        else:
            base_info["oid"] = referer[23:len(referer)]
    end = 0
    for i in range(int((base_info["comment"] - 1) / 20) + 1):
        if i == 0:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))
        else:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=" + str(i + 1) + "&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))

        if i == int((base_info["comment"] - 1) / 20):
            end = 1
        get_data(url, end)
        time.sleep(0.5)


# 获取数据函数
def get_data(url, end):
    print(url)
    global text_str
    global text

    req = urllib.request.urlopen(url)
    ret = req.read().decode()
    # print(ret)
    json1 = json.loads(ret)
    # json1["data"]["replies"]有可能为null
    if json1["data"]["replies"] is not None:
        len1 = len(json1["data"]["replies"])
        for i in range(len1):
            mid = json1["data"]["replies"][i]["member"]["mid"]
            uname = json1["data"]["replies"][i]["member"]["uname"]
            message = json1["data"]["replies"][i]["content"]["message"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(mid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (mid, uname, message))
            con.commit()

        # print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(END, text_str)
        text.update()

    # print("插入一组数据组")

    if end == 1:
        # print("数据获取完毕!\n")
        text_str = "数据获取完毕!\n"
        text.insert(END, text_str)
        text.update()
        # print(name_set)
        # print(id_set)
        while len(lucky_set) < int(lucky_num):
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
            # print(lucky_set)
        # id_list = list(id_set)
        # name_list = list(name_set)
        # for i in range(int(lucky_num)):
        #     print("昵称:" + name_list[i] + "  id:" + id_list[i] + "\n")

        for i in range(int(lucky_num)):
            lucky_list = list(lucky_set)
            # print("lucky_num=" + str(lucky_list[i]))
            sql = "select * from user limit " + str(lucky_list[i]) + ",1"
            cur.execute(sql)
            rows = cur.fetchall()
            for row in rows:
                # print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
                text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
                text.insert(END, text_str)
                text.update()

        text_str = '\n\n'
        text.insert(END, text_str)
        text.update()


# 获取转发用户的数据
def get_repost_user_info(base_info):
    global text_str
    global dynamic_id
    global text

    print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(END, text_str)
    text.update()

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    # if referer[-6:-1] == "?tab=":
    #     dynamic_id = referer[23:len(referer) - 6]
    # else:
    #     dynamic_id = referer[23:len(referer)]

    temp = referer.split('?')
    temp2 = temp[0].split('/')
    dynamic_id = temp2[3]

    temp_num = 0
    # 根据转发数进行循环
    while temp_num < int(base_info["repost"]):
        url = "https://api.live.bilibili.com/dynamic_repost/v1/dynamic_repost/view_repost?dynamic_id=" + \
              str(dynamic_id) + "&offset=" + str(temp_num)
        req = urllib.request.urlopen(url)
        ret = req.read().decode()

        # print(url)
        # print(ret)

        json1 = json.loads(ret)
        len1 = 0
        if "comments" in ret:
            len1 = len(json1["data"]["comments"])
            # print(len1)
        else:
            print("可获取的数据结束!\n")
            text_str = "可获取的数据结束!\n"
            text.insert(END, text_str)
            text.update()
            break
        for i in range(len1):
            uid = json1["data"]["comments"][i]["uid"]
            uname = json1["data"]["comments"][i]["uname"]
            comment = json1["data"]["comments"][i]["comment"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(uid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (uid, uname, comment))
            con.commit()

        temp_num += 20
        # print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(END, text_str)
        text.update()
        time.sleep(0.5)
    print("数据获取完毕!\n")
    text_str = "数据获取完毕!\n"
    text.insert(END, text_str)
    text.update()
    while len(lucky_set) < int(lucky_num):
        num = 0
        if len(id_set) > 1:
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
        else:
            print('用户数据不足2个,数据异常,程序结束')
            text_str = "用户数据不足2个,数据异常,程序结束\n"
            text.insert(END, text_str)
            text.update()
            return
    for i in range(int(lucky_num)):
        lucky_list = list(lucky_set)
        # print("lucky_num=" + str(lucky_list[i]))
        sql = "select * from user limit " + str(lucky_list[i]) + ",1"
        cur.execute(sql)
        rows = cur.fetchall()
        for row in rows:
            print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
            text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
            text.insert(END, text_str)
            text.update()

    text_str = '\n\n'
    text.insert(END, text_str)
    text.update()


# 单选框点击
def radio_click():
    global draw_type
    draw_type = radio.get()
    # print("draw_type:" + str(draw_type))


# 开始抽奖按钮点击
def start_btn():
    global referer
    global lucky_num
    global text_str
    global text

    id_set.clear()
    name_set.clear()
    lucky_set.clear()

    referer = StringVar1.get()
    if len(StringVar2.get()) != 0:
        lucky_num = int(StringVar2.get())
    # print('referer:' + referer)
    # print('lucky_num:' + str(lucky_num))
    if not referer.startswith('https://t.bilibili.com'):
        # print("动态链接地址不正确,请重新输入")
        text_str = "动态链接地址不正确,请重新输入!!!\n"
        text.insert(END, text_str)
        text.update()
        return
    if not is_number(lucky_num):
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(END, text_str)
        text.update()
        return
    if int(float(lucky_num)) <= 0:
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(END, text_str)
        text.update()
        return

    # 配置数据库
    config_db()
    # 获取oid、转发数、评论数
    base_info = get_oid()

    if base_info["ret"]:
        # print("oid=" + str(base_info["oid"]))
        # print("转发数=" + str(base_info["repost"]))
        # print("评论数=" + str(base_info["comment"]))

        text_str = "oid=" + str(base_info["oid"]) + "\n"
        text_str = text_str + "转发数=" + str(base_info["repost"]) + "\n"
        text_str = text_str + "评论数=" + str(base_info["comment"]) + "\n"
        text.insert(END, text_str)
        text.update()

        # 根据抽奖类型进行抽奖 1评论 0转发
        if int(draw_type) == 1:
            if int(lucky_num) > int(base_info["comment"]):
                text_str = "请输入正确的中奖人数!!!\n"
                text.insert(END, text_str)
                text.update()
                # 关闭游标
                cur.close()
                # 断开数据库连接
                con.close()
                return
            # 获取用户信息并抽取幸运用户
            get_user_info(base_info)
        else:
            if int(lucky_num) > int(base_info["repost"]):
                text_str = "请输入正确的中奖人数!!!\n"
                text.insert(END, text_str)
                text.update()
                # 关闭游标
                cur.close()
                # 断开数据库连接
                con.close()
                return
            get_repost_user_info(base_info)

        # 关闭游标
        cur.close()
        # 断开数据库连接
        con.close()


app = ttk.Window(title='b站动态抽奖程序', themename='litera', iconphoto='', size=[700, 600], position=None, minsize=None)
root = ttk.Frame(app, padding=10)
style = ttk.Style()

tframe = ttk.Frame(root)
tframe.pack(padx=3, fill=X, side=TOP)

bframe = ttk.Frame(root)
bframe.pack(padx=7, fill=BOTH, side=BOTTOM)

lframe = ttk.Frame(tframe)
lframe.pack(padx=8, side=LEFT, fill=BOTH, expand=YES)

rframe = ttk.Frame(tframe, padding=5)
rframe.pack(padx=2, side=RIGHT, fill=BOTH, expand=YES)

btframe = ttk.Frame(root)
btframe.pack(fill=BOTH, side=TOP)

text = ScrolledText(master=btframe, height=100, width=50, autohide=True, padding=10)
text.pack(side=LEFT, anchor=NW, pady=5, fill=BOTH, expand=YES)

input_group = ttk.Labelframe(
    master=lframe, text="配置输入", padding=10
)
input_group.pack(fill=BOTH, expand=YES)

l1 = ttk.Label(input_group, text="动态链接:")
l1.grid(row=0, column=0)

load = tkinter.StringVar()

StringVar1 = ttk.StringVar()
StringVar1.set("")
entry = ttk.Entry(input_group, width=50, textvariable=StringVar1)
entry.grid(row=0, column=1, padx='4px', pady='5px')
entry.insert(END, "例如:https://t.bilibili.com/123456789012345678")

l2 = ttk.Label(input_group, text="中奖人数:")
l2.grid(row=1, column=0)

StringVar2 = ttk.StringVar()
StringVar2.set("")
spinbox = ttk.Spinbox(master=input_group, from_=1, to=500, textvariable=StringVar2)
spinbox.grid(row=1, column=1, sticky='w', padx='4px', pady='5px')
spinbox.set(1)

rb_group = ttk.Labelframe(
    rframe, text="抽奖类型", padding=10
)
rb_group.pack(fill=X, pady=10, side=TOP)

radio = ttk.IntVar()
radio1 = ttk.Radiobutton(rb_group, text="评论", value=1, variable=radio, command=radio_click)
radio1.pack(side=LEFT, expand=YES, padx=5)
radio1.invoke()

radio2 = ttk.Radiobutton(rb_group, text="转发", value=0, variable=radio, command=radio_click)
radio2.pack(side=LEFT, expand=YES, padx=5)

cb = ttk.Button(
    master=rframe,
    text="开始抽奖",
    bootstyle=(SUCCESS, TOOLBUTTON),
    command=start_btn
)
# 调用与按钮关联的命令
# cb.invoke()
cb.pack(fill=X, pady=5)

lframe_inner = ttk.Frame(lframe)
lframe_inner.pack(fill=BOTH, expand=YES, padx=10)

root.pack(fill=BOTH, expand=YES)
app.mainloop()

GUI版本-v3.7

# -*- coding: utf-8 -*-
import json
import time
import random
import urllib.request
import urllib.parse
import sqlite3
import tkinter
from tkinter import END, messagebox

# python版本:3.8.12
# 打包 pyinstaller -F 1.py

# 获取抽奖类型
global draw_type
global referer
# 中奖人数
global lucky_num
global dynamic_id
global text_str
# 动态类型
global api_type

api_type = 11
draw_type = 1
dynamic_id = ""
# 打印文本框
text_str = ''

# 数据集合
id_set = set()
name_set = set()
lucky_set = set()

headers1 = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Content-Type': 'text/plain;charset=UTF-8',
    'Referer': 'https://t.bilibili.com',
    'origin': 'https://t.bilibili.com',
    # 'cookie': 'l=v',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400'
}


# 字符串是否是数字
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass

    return False


# 配置数据库
def config_db():
    global con, cur
    global text_str
    # print("开始创建数据库...")
    text_str = "开始创建数据库...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    con = sqlite3.connect("user_data.db")
    cur = con.cursor()
    # 创建表user
    sql = "CREATE TABLE IF NOT EXISTS user(mid TEXT PRIMARY KEY,uname TEXT,message TEXT)"
    cur.execute(sql)
    # 情况表数据
    sql = "delete from user"
    cur.execute(sql)


# 获取oid、转发数、评论数函数
def get_oid():
    global text_str
    global dynamic_id
    global api_type
    if referer[8] == 't':
        # print('解析为动态页面')
        text_str = "解析为动态页面\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
    else:
        # print('解析为视频页面')
        text_str = "解析为视频页面\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

    tab_type = "2"

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    # if referer[-6:-1] == "?tab=":
    #     dynamic_id = referer[23:len(referer) - 6]
    #     tab_type = referer[-1]
    # else:
    #     dynamic_id = referer[23:len(referer)]

    temp = referer.split('?')
    temp2 = temp[0].split('/')
    dynamic_id = temp2[3]

    # print("dynamic_id=" + dynamic_id)
    text_str = "dynamic_id=" + dynamic_id + "\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()

    if len(dynamic_id) == 0:
        # print("dynamic_id异常,程序终止,请检查您的输入是否有误!")
        text_str = "dynamic_id异常,程序终止,请检查您的输入是否有误!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        base_info = {'ret': False}
        return base_info

    # payload = {'dynamic_id': dynamic_id}
    payload = { 'timezone_offset': '-480', 'id': dynamic_id}
    data = urllib.parse.urlencode(payload)
    # print(data)

    req = urllib.request.urlopen('https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?%s' % data)
    # req = urllib.request.urlopen('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?%s' % data)
    ret = req.read().decode()

    # print(ret)
    json1 = json.loads(ret)
    oid = json1["data"]["item"]["basic"]["comment_id_str"]
    repost = json1["data"]["item"]["modules"]["module_stat"]["forward"]["count"]
    # oid = json1["data"]["card"]["desc"]["rid"]
    # repost = json1["data"]["card"]["desc"]["repost"]

    comment = 0
    # 非视频动态
    if tab_type == "2":
        comment = json1["data"]["item"]["modules"]["module_stat"]["comment"]["count"]
    else:
        comment = 0
    # 判断动态类型
    api_type = json1["data"]["item"]["basic"]["comment_type"]
    # print("oid=" + str(oid))
    base_info = {'ret': True, 'oid': oid, 'repost': repost, 'comment': comment}
    # print(base_info)
    return base_info


# 获取用户信息函数
def get_user_info(base_info):
    global text_str
    global api_type
    # print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    if int(api_type) == 17:
        # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
        if referer[-6:-1] == "?tab=":
            base_info["oid"] = referer[23:len(referer) - 6]
        else:
            base_info["oid"] = referer[23:len(referer)]
    end = 0
    for i in range(int((base_info["comment"] - 1) / 20) + 1):
        if i == 0:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))
        else:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=" + str(i + 1) + "&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))

        if i == int((base_info["comment"] - 1) / 20):
            end = 1
        get_data(url, end)
        time.sleep(0.5)


# 获取数据函数
def get_data(url, end):
    print(url)
    global text_str
    req = urllib.request.urlopen(url)
    ret = req.read().decode()
    # print(ret)
    json1 = json.loads(ret)
    # json1["data"]["replies"]有可能为null
    if json1["data"]["replies"] is not None:
        len1 = len(json1["data"]["replies"])
        for i in range(len1):
            mid = json1["data"]["replies"][i]["member"]["mid"]
            uname = json1["data"]["replies"][i]["member"]["uname"]
            message = json1["data"]["replies"][i]["content"]["message"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(mid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (mid, uname, message))
            con.commit()

        # print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

    # print("插入一组数据组")

    if end == 1:
        # print("数据获取完毕!\n")
        text_str = "数据获取完毕!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        # print(name_set)
        # print(id_set)
        while len(lucky_set) < int(lucky_num):
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
            # print(lucky_set)
        # id_list = list(id_set)
        # name_list = list(name_set)
        # for i in range(int(lucky_num)):
        #     print("昵称:" + name_list[i] + "  id:" + id_list[i] + "\n")

        for i in range(int(lucky_num)):
            lucky_list = list(lucky_set)
            # print("lucky_num=" + str(lucky_list[i]))
            sql = "select * from user limit " + str(lucky_list[i]) + ",1"
            cur.execute(sql)
            rows = cur.fetchall()
            for row in rows:
                # print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
                text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
                text.insert(tkinter.INSERT, text_str)
                text.update()

        text_str = '\n\n'
        text.insert(tkinter.INSERT, text_str)
        text.update()


# 获取转发用户的数据
def get_repost_user_info(base_info):
    global text_str
    global dynamic_id
    print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    # if referer[-6:-1] == "?tab=":
    #     dynamic_id = referer[23:len(referer) - 6]
    # else:
    #     dynamic_id = referer[23:len(referer)]

    temp = referer.split('?')
    temp2 = temp[0].split('/')
    dynamic_id = temp2[3]

    temp_num = 0
    # 根据转发数进行循环
    while temp_num < int(base_info["repost"]):
        url = "https://api.live.bilibili.com/dynamic_repost/v1/dynamic_repost/view_repost?dynamic_id=" + \
              str(dynamic_id) + "&offset=" + str(temp_num)
        req = urllib.request.urlopen(url)
        ret = req.read().decode()

        # print(url)
        # print(ret)

        json1 = json.loads(ret)
        len1 = 0
        if "comments" in ret:
            len1 = len(json1["data"]["comments"])
            # print(len1)
        else:
            print("可获取的数据结束!\n")
            text_str = "可获取的数据结束!\n"
            text.insert(tkinter.INSERT, text_str)
            text.update()
            break
        for i in range(len1):
            uid = json1["data"]["comments"][i]["uid"]
            uname = json1["data"]["comments"][i]["uname"]
            comment = json1["data"]["comments"][i]["comment"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(uid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (uid, uname, comment))
            con.commit()

        temp_num += 20
        # print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        time.sleep(0.5)
    print("数据获取完毕!\n")
    text_str = "数据获取完毕!\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    while len(lucky_set) < int(lucky_num):
        num = 0
        if len(id_set) > 1:
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
        else:
            print('用户数据不足2个,数据异常,程序结束')
            text_str = "用户数据不足2个,数据异常,程序结束\n"
            text.insert(tkinter.INSERT, text_str)
            text.update()
            return
    for i in range(int(lucky_num)):
        lucky_list = list(lucky_set)
        # print("lucky_num=" + str(lucky_list[i]))
        sql = "select * from user limit " + str(lucky_list[i]) + ",1"
        cur.execute(sql)
        rows = cur.fetchall()
        for row in rows:
            print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
            text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
            text.insert(tkinter.INSERT, text_str)
            text.update()

    text_str = '\n\n'
    text.insert(tkinter.INSERT, text_str)
    text.update()


# 关于弹窗提示
def about():
    # 弹出对话框
    messagebox.showinfo(title='关于', message='欢迎使用 UP:Love丶伊卡洛斯 开发的b站抽奖程序 本程序开源免费\n'
                                            '请勿使用非本人仓库下载的程序,否则无法保证安全,未知程序谨慎使用\n'
                                            '本程序目前只支持动态转发、评论的抽奖,视频评论区抽奖有待开发。。。\n'
                                            '使用注意:因为涉及本地文件的操作,如果失败,则需要\"超级管理员\"权限运行\n'
                                            '温馨提示:如果以下内容输错,请重新运行程序,异常数据处理懒得做了0.0')


# 单选框点击
def radio_click():
    global draw_type
    draw_type = radio.get()
    # print("draw_type:" + str(draw_type))


# 开始抽奖按钮点击
def start_btn():
    global referer
    global lucky_num
    global text_str

    id_set.clear()
    name_set.clear()
    lucky_set.clear()

    referer = StringVar1.get()
    if len(StringVar2.get()) != 0:
        lucky_num = int(StringVar2.get())
    # print('referer:' + referer)
    # print('lucky_num:' + str(lucky_num))
    if not referer.startswith('https://t.bilibili.com'):
        # print("动态链接地址不正确,请重新输入")
        text_str = "动态链接地址不正确,请重新输入!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return
    if not is_number(lucky_num):
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return
    if int(float(lucky_num)) <= 0:
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return

    # 配置数据库
    config_db()
    # 获取oid、转发数、评论数
    base_info = get_oid()

    if base_info["ret"]:
        # print("oid=" + str(base_info["oid"]))
        # print("转发数=" + str(base_info["repost"]))
        # print("评论数=" + str(base_info["comment"]))

        text_str = "oid=" + str(base_info["oid"]) + "\n"
        text_str = text_str + "转发数=" + str(base_info["repost"]) + "\n"
        text_str = text_str + "评论数=" + str(base_info["comment"]) + "\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

        # 根据抽奖类型进行抽奖 1评论 0转发
        if int(draw_type) == 1:
            # 获取用户信息并抽取幸运用户
            get_user_info(base_info)
        else:
            get_repost_user_info(base_info)

        # 关闭游标
        cur.close()
        # 断开数据库连接
        con.close()


# 清空输入框按钮点击
def clear_in():
    e2.delete(0, END)
    e3.delete(0, END)


# 清空输出框按钮点击
def clear_out():
    text.delete(0.0, tkinter.END)


window = tkinter.Tk()
window.title("b站动态抽奖程序")
window.geometry("1000x900+200+100")
# 菜单栏
menu = tkinter.Menu(window)
# Open放在菜单栏中,就是装入容器
menu.add_command(label='关于', command=about)
# 创建菜单栏完成后,配置让菜单栏menu显示出来
window.config(menu=menu)

# 创建一个主frame,长在主window窗口上
frame = tkinter.Frame(window)
frame.pack()

# 创建第二层框架frame,长在主框架frame上面
# 上
frame_t = tkinter.Frame(frame)
# 下
frame_b = tkinter.Frame(frame)

# frame_t.pack(side=tkinter.TOP)
# frame_b.pack(side=tkinter.BOTTOM)
frame_t.grid(row=0, column=0)
frame_b.grid(row=1, column=0)

# 创建标签
l1 = tkinter.Label(frame_t, text='抽奖类型:', width=10, font=('microsoft yahei', 16))
l2 = tkinter.Label(frame_t, text='动态链接:', width=10, font=('microsoft yahei', 16))
l3 = tkinter.Label(frame_t, text='中奖人数:', width=10, font=('microsoft yahei', 16))

radio = tkinter.IntVar()
radio.set(1)
radio1 = tkinter.Radiobutton(frame_t, text="评论", font=('microsoft yahei', 16), width=10, justify='left', value=1,
                             variable=radio, command=radio_click, padx=1)
radio1.grid(row=0, column=1)
radio2 = tkinter.Radiobutton(frame_t, text="转发", font=('microsoft yahei', 16), width=10, justify='left', value=0,
                             variable=radio, command=radio_click, padx=1)
radio2.grid(row=0, column=2)
button1 = tkinter.Button(frame_t, text="开始抽奖", command=start_btn, font=('microsoft yahei', 12), width=16, height=1)
button1.grid(row=0, column=3)

StringVar1 = tkinter.StringVar()
StringVar1.set("")
e2 = tkinter.Entry(frame_t, show=None, width=42, textvariable=StringVar1, font=('microsoft yahei', 16))
StringVar2 = tkinter.StringVar()
StringVar2.set("1")
e3 = tkinter.Entry(frame_t, show=None, width=42, textvariable=StringVar2, font=('microsoft yahei', 16))

button2 = tkinter.Button(frame_t, text="清空输入框", command=clear_in, font=('microsoft yahei', 12), width=16, height=1)
button2.grid(row=1, column=2)
button3 = tkinter.Button(frame_t, text="清空输出框", command=clear_out, font=('microsoft yahei', 12), width=16, height=1)
button3.grid(row=2, column=2)

l1.grid(row=0, column=0)
l2.grid(row=1, column=0)
e2.grid(row=1, column=1)
l3.grid(row=2, column=0)
e3.grid(row=2, column=1)

# 创建滚动条
scroll = tkinter.Scrollbar(frame_b)
text = tkinter.Text(frame_b, font=('microsoft yahei', 14), width=80, height=30)
# side放到窗体的那一侧
scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)
text.pack(side=tkinter.LEFT, fill=tkinter.Y)
# text.grid(row=3, column=0)
# scroll.grid(row=3, column=1)
# 关联
scroll.config(command=text.yview)
text.config(yscrollcommand=scroll.set)

window.mainloop()




GUI版本旧版(已经不适配)

# -*- coding: utf-8 -*-
import json
import time
import random
import urllib.request
import urllib.parse
import sqlite3
import tkinter
from tkinter import END, messagebox

# python版本:3.8.12
# 打包 pyinstaller -F 1.py

# 获取抽奖类型
global draw_type
global referer
# 中奖人数
global lucky_num
global dynamic_id
global text_str
# 是否带图动态
global have_pic

have_pic = 1
draw_type = 1
dynamic_id = ""
# 打印文本框
text_str = ''

# 数据集合
id_set = set()
name_set = set()
lucky_set = set()

headers1 = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Content-Type': 'text/plain;charset=UTF-8',
    'Referer': 'https://t.bilibili.com',
    'origin': 'https://t.bilibili.com',
    # 'cookie': 'l=v',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400'
}


# 字符串是否是数字
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass

    return False


# 配置数据库
def config_db():
    global con, cur
    global text_str
    # print("开始创建数据库...")
    text_str = "开始创建数据库...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    con = sqlite3.connect("user_data.db")
    cur = con.cursor()
    # 创建表user
    sql = "CREATE TABLE IF NOT EXISTS user(mid TEXT PRIMARY KEY,uname TEXT,message TEXT)"
    cur.execute(sql)
    # 情况表数据
    sql = "delete from user"
    cur.execute(sql)


# 获取oid、转发数、评论数函数
def get_oid():
    global text_str
    global dynamic_id
    if referer[8] == 't':
        # print('解析为动态页面')
        text_str = "解析为动态页面\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
    else:
        # print('解析为视频页面')
        text_str = "解析为视频页面\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

    tab_type = "2"

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    if referer[-6:-1] == "?tab=":
        dynamic_id = referer[23:len(referer) - 6]
        tab_type = referer[-1]
    else:
        dynamic_id = referer[23:len(referer)]

    # print("dynamic_id=" + dynamic_id)
    text_str = "dynamic_id=" + dynamic_id + "\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()

    if len(dynamic_id) == 0:
        # print("dynamic_id异常,程序终止,请检查您的输入是否有误!")
        text_str = "dynamic_id异常,程序终止,请检查您的输入是否有误!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        base_info = {'ret': False}
        return base_info

    payload = {'dynamic_id': dynamic_id}
    data = urllib.parse.urlencode(payload)

    req = urllib.request.urlopen('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?%s' % data)
    ret = req.read().decode()

    # print(ret)
    json1 = json.loads(ret)
    oid = json1["data"]["card"]["desc"]["rid"]
    repost = json1["data"]["card"]["desc"]["repost"]

    comment = 0
    # 非视频动态
    if tab_type == "2":
        comment = json1["data"]["card"]["desc"]["comment"]
    else:
        comment = 0
    # 判断动态类型
    type = json1["data"]["card"]["desc"]["type"]
    global have_pic
    if int(type) == 2:
        have_pic = 1
    else:
        have_pic = 0
    # print("oid=" + str(oid))
    base_info = {'ret': True, 'oid': oid, 'repost': repost, 'comment': comment}
    return base_info


# 获取用户信息函数
def get_user_info(base_info):
    global text_str
    # print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    if int(have_pic) == 1:
        api_type = 11
    else:
        api_type = 17
        # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
        if referer[-6:-1] == "?tab=":
            base_info["oid"] = referer[23:len(referer) - 6]
        else:
            base_info["oid"] = referer[23:len(referer)]
    end = 0
    for i in range(int((base_info["comment"] - 1) / 20) + 1):
        if i == 0:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))
        else:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=" + str(i + 1) + "&type=" + str(api_type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1))

        if i == int((base_info["comment"] - 1) / 20):
            end = 1
        get_data(url, end)
        time.sleep(0.5)


# 获取数据函数
def get_data(url, end):
    global text_str
    req = urllib.request.urlopen(url)
    ret = req.read().decode()
    # print(ret)
    json1 = json.loads(ret)
    # json1["data"]["replies"]有可能为null
    if json1["data"]["replies"] is not None:
        len1 = len(json1["data"]["replies"])
        for i in range(len1):
            mid = json1["data"]["replies"][i]["member"]["mid"]
            uname = json1["data"]["replies"][i]["member"]["uname"]
            message = json1["data"]["replies"][i]["content"]["message"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(mid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (mid, uname, message))
            con.commit()

        # print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

    # print("插入一组数据组")

    if end == 1:
        # print("数据获取完毕!\n")
        text_str = "数据获取完毕!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        # print(name_set)
        # print(id_set)
        while len(lucky_set) < int(lucky_num):
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
            # print(lucky_set)
        # id_list = list(id_set)
        # name_list = list(name_set)
        # for i in range(int(lucky_num)):
        #     print("昵称:" + name_list[i] + "  id:" + id_list[i] + "\n")

        for i in range(int(lucky_num)):
            lucky_list = list(lucky_set)
            # print("lucky_num=" + str(lucky_list[i]))
            sql = "select * from user limit " + str(lucky_list[i]) + ",1"
            cur.execute(sql)
            rows = cur.fetchall()
            for row in rows:
                # print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
                text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
                text.insert(tkinter.INSERT, text_str)
                text.update()

        text_str = '\n\n'
        text.insert(tkinter.INSERT, text_str)
        text.update()


# 获取转发用户的数据
def get_repost_user_info(base_info):
    global text_str
    global dynamic_id
    print("开始获取用户信息...")
    text_str = "开始获取用户信息...\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    if referer[-6:-1] == "?tab=":
        dynamic_id = referer[23:len(referer) - 6]
    else:
        dynamic_id = referer[23:len(referer)]

    temp_num = 0
    # 根据转发数进行循环
    while temp_num < int(base_info["repost"]):
        url = "https://api.live.bilibili.com/dynamic_repost/v1/dynamic_repost/view_repost?dynamic_id=" + \
              str(dynamic_id) + "&offset=" + str(temp_num)
        req = urllib.request.urlopen(url)
        ret = req.read().decode()

        # print(url)
        # print(ret)

        json1 = json.loads(ret)
        len1 = 0
        if "comments" in ret:
            len1 = len(json1["data"]["comments"])
            # print(len1)
        else:
            print("可获取的数据结束!\n")
            text_str = "可获取的数据结束!\n"
            text.insert(tkinter.INSERT, text_str)
            text.update()
            break
        for i in range(len1):
            uid = json1["data"]["comments"][i]["uid"]
            uname = json1["data"]["comments"][i]["uname"]
            comment = json1["data"]["comments"][i]["comment"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(uid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (uid, uname, comment))
            con.commit()

        temp_num += 20
        print("已获取" + str(len(id_set)) + "个用户的数据...")
        text_str = "已获取" + str(len(id_set)) + "个用户的数据...\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        time.sleep(0.5)
    print("数据获取完毕!\n")
    text_str = "数据获取完毕!\n"
    text.insert(tkinter.INSERT, text_str)
    text.update()
    while len(lucky_set) < int(lucky_num):
        num = 0
        if len(id_set) > 1:
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
        else:
            print('用户数据不足2个,数据异常,程序结束')
            text_str = "用户数据不足2个,数据异常,程序结束\n"
            text.insert(tkinter.INSERT, text_str)
            text.update()
            return
    for i in range(int(lucky_num)):
        lucky_list = list(lucky_set)
        # print("lucky_num=" + str(lucky_list[i]))
        sql = "select * from user limit " + str(lucky_list[i]) + ",1"
        cur.execute(sql)
        rows = cur.fetchall()
        for row in rows:
            print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))
            text_str = '\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]) + '\n'
            text.insert(tkinter.INSERT, text_str)
            text.update()

    text_str = '\n\n'
    text.insert(tkinter.INSERT, text_str)
    text.update()


# 关于弹窗提示
def about():
    # 弹出对话框
    messagebox.showinfo(title='关于', message='欢迎使用 UP:Love丶伊卡洛斯 开发的b站抽奖程序 本程序开源免费\n'
                                            '请勿使用非本人仓库下载的程序,否则无法保证安全,未知程序谨慎使用\n'
                                            '本程序目前只支持动态转发、评论的抽奖,视频评论区抽奖有待开发。。。\n'
                                            '使用注意:因为涉及本地文件的操作,如果失败,则需要\"超级管理员\"权限运行\n'
                                            '温馨提示:如果以下内容输错,请重新运行程序,异常数据处理懒得做了0.0')


# 单选框点击
def radio_click():
    global draw_type
    draw_type = radio.get()
    # print("draw_type:" + str(draw_type))


# 开始抽奖按钮点击
def start_btn():
    global referer
    global lucky_num
    global text_str

    id_set.clear()
    name_set.clear()
    lucky_set.clear()

    referer = StringVar1.get()
    if len(StringVar2.get()) != 0:
        lucky_num = int(StringVar2.get())
    # print('referer:' + referer)
    # print('lucky_num:' + str(lucky_num))
    if not referer.startswith('https://t.bilibili.com'):
        # print("动态链接地址不正确,请重新输入")
        text_str = "动态链接地址不正确,请重新输入!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return
    if not is_number(lucky_num):
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return
    if int(float(lucky_num)) <= 0:
        # print("请输入正确的中奖人数")
        text_str = "请输入正确的中奖人数!!!\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()
        return

    # 配置数据库
    config_db()
    # 获取oid、转发数、评论数
    base_info = get_oid()

    if base_info["ret"]:
        # print("oid=" + str(base_info["oid"]))
        # print("转发数=" + str(base_info["repost"]))
        # print("评论数=" + str(base_info["comment"]))

        text_str = "oid=" + str(base_info["oid"]) + "\n"
        text_str = text_str + "转发数=" + str(base_info["repost"]) + "\n"
        text_str = text_str + "评论数=" + str(base_info["comment"]) + "\n"
        text.insert(tkinter.INSERT, text_str)
        text.update()

        # 根据抽奖类型进行抽奖 1评论 0转发
        if int(draw_type) == 1:
            # 获取用户信息并抽取幸运用户
            get_user_info(base_info)
        else:
            get_repost_user_info(base_info)

        # 关闭游标
        cur.close()
        # 断开数据库连接
        con.close()


# 清空输入框按钮点击
def clear_in():
    e2.delete(0, END)
    e3.delete(0, END)


# 清空输出框按钮点击
def clear_out():
    text.delete(0.0, tkinter.END)


window = tkinter.Tk()
window.title("b站动态抽奖程序")
window.geometry("1000x800+200+100")
# 菜单栏
menu = tkinter.Menu(window)
# Open放在菜单栏中,就是装入容器
menu.add_command(label='关于', command=about)
# 创建菜单栏完成后,配置让菜单栏menu显示出来
window.config(menu=menu)

# 创建一个主frame,长在主window窗口上
frame = tkinter.Frame(window)
frame.pack()

# 创建第二层框架frame,长在主框架frame上面
# 上
frame_t = tkinter.Frame(frame)
# 下
frame_b = tkinter.Frame(frame)

# frame_t.pack(side=tkinter.TOP)
# frame_b.pack(side=tkinter.BOTTOM)
frame_t.grid(row=0, column=0)
frame_b.grid(row=1, column=0)

# 创建标签
l1 = tkinter.Label(frame_t, text='抽奖类型:', width=10, font=('microsoft yahei', 16))
l2 = tkinter.Label(frame_t, text='动态链接:', width=10, font=('microsoft yahei', 16))
l3 = tkinter.Label(frame_t, text='中奖人数:', width=10, font=('microsoft yahei', 16))

radio = tkinter.IntVar()
radio1 = tkinter.Radiobutton(frame_t, text="评论", font=('microsoft yahei', 16), width=10, justify='left', value=1,
                             variable=radio, command=radio_click, padx=1)
radio1.grid(row=0, column=1)
radio2 = tkinter.Radiobutton(frame_t, text="转发", font=('microsoft yahei', 16), width=10, justify='left', value=0,
                             variable=radio, command=radio_click, padx=1)
radio2.grid(row=0, column=2)
button1 = tkinter.Button(frame_t, text="开始抽奖", command=start_btn, font=('microsoft yahei', 12), width=16, height=1)
button1.grid(row=0, column=3)

StringVar1 = tkinter.StringVar()
StringVar1.set("")
e2 = tkinter.Entry(frame_t, show=None, width=42, textvariable=StringVar1, font=('microsoft yahei', 16))
StringVar2 = tkinter.StringVar()
StringVar2.set("1")
e3 = tkinter.Entry(frame_t, show=None, width=42, textvariable=StringVar2, font=('microsoft yahei', 16))

button2 = tkinter.Button(frame_t, text="清空输入框", command=clear_in, font=('microsoft yahei', 12), width=16, height=1)
button2.grid(row=1, column=2)
button3 = tkinter.Button(frame_t, text="清空输出框", command=clear_out, font=('microsoft yahei', 12), width=16, height=1)
button3.grid(row=2, column=2)

l1.grid(row=0, column=0)
l2.grid(row=1, column=0)
e2.grid(row=1, column=1)
l3.grid(row=2, column=0)
e3.grid(row=2, column=1)

# 创建滚动条
scroll = tkinter.Scrollbar(frame_b)
text = tkinter.Text(frame_b, font=('microsoft yahei', 14), width=80, height=30)
# side放到窗体的那一侧
scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)
text.pack(side=tkinter.LEFT, fill=tkinter.Y)
# text.grid(row=3, column=0)
# scroll.grid(row=3, column=1)
# 关联
scroll.config(command=text.yview)
text.config(yscrollcommand=scroll.set)

window.mainloop()

cmd版本(已不适配)

# -*- coding: utf-8 -*-
import json
import time
import random
import urllib.request
import urllib.parse
import sqlite3

# 打包 venv\Scripts\pyinstaller.exe -F 1.py

print("*********************************************************************************")
print("***  欢迎使用 UP:Love丶伊卡洛斯 开发的b站抽奖程序 本程序开源免费          ")
print("***  请勿使用非本人仓库下载的程序,否则无法保证安全,未知程序谨慎使用        ")
print("***  本程序目前只支持动态转发、评论的抽奖,视频评论区抽奖有待开发。。。           ")
print("***  使用注意:因为涉及本地文件的操作,如果失败,则需要\"超级管理员\"权限运行   ")
print("***  温馨提示:如果以下内容输错,请重新运行程序,异常数据处理懒得做了0.0     ")
print("*********************************************************************************")


# 获取抽奖类型
global draw_type
global referer
global lucky_num
have_pic = 1


# 字符串是否是数字
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass

    return False


while True:
    draw_type = input("请输入抽奖类型(1评论 0转发):")
    if draw_type != '0' and draw_type != '1':
        print("请输入0或1")
        continue
    referer = input("请输入动态链接:")
    if not referer.startswith('https://t.bilibili.com'):
        print("动态链接地址不正确,请重新输入")
        continue
    lucky_num = input("请输入中奖人数:")
    if not is_number(lucky_num):
        print("请输入正确的中奖人数")
        continue
    if int(float(lucky_num)) > 0:
        break
    else:
        print("请输入正确的中奖人数")

id_set = set()
name_set = set()
lucky_set = set()

dynamic_id = ""

headers1 = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Connection': 'keep-alive',
    'Content-Type': 'text/plain;charset=UTF-8',
    'Referer': referer,
    'origin': 'https://t.bilibili.com',
    # 'cookie': 'l=v',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400'
}


# 配置数据库
def config_db():
    global con, cur
    con = sqlite3.connect("user_data.db")
    cur = con.cursor()
    # 创建表user
    sql = "CREATE TABLE IF NOT EXISTS user(mid TEXT PRIMARY KEY,uname TEXT,message TEXT)"
    cur.execute(sql)
    # 情况表数据
    sql = "delete from user"
    cur.execute(sql)


# 获取oid、转发数、评论数函数
def get_oid(referer):
    if (referer[8] == 't'):
        print('解析为动态页面')
    else:
        print('解析为视频页面')

    tab_type = "2"

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    if referer[-6:-1] == "?tab=":
        dynamic_id = referer[23:len(referer) - 6]
        tab_type = referer[-1]
    else:
        dynamic_id = referer[23:len(referer)]

    print("dynamic_id=" + dynamic_id)

    if len(dynamic_id) == 0:
        print("dynamic_id异常,程序终止,请检查您的输入是否有误!")
        base_info = {'ret': False}
        return base_info

    payload = {'dynamic_id': dynamic_id}
    data = urllib.parse.urlencode(payload)

    req = urllib.request.urlopen('https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?%s' % data)
    ret = req.read().decode()

    # print(ret)
    json1 = json.loads(ret)
    oid = json1["data"]["card"]["desc"]["rid"]
    repost = json1["data"]["card"]["desc"]["repost"]

    comment = 0
    # 非视频动态
    if tab_type == "2":
        comment = json1["data"]["card"]["desc"]["comment"]
    else:
        comment = 0
    # 判断动态类型
    type = json1["data"]["card"]["desc"]["type"]
    global have_pic
    if int(type) == 2:
        have_pic = 1
    else:
        have_pic = 0
    # print("oid=" + str(oid))
    base_info = {'ret': True, 'oid': oid, 'repost': repost, 'comment': comment}
    return base_info


# 获取用户信息函数
def get_user_info(referer, base_info):
    print("开始获取用户信息...")
    if int(have_pic) == 1:
        type = 11
    else:
        type = 17
        # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
        if referer[-6:-1] == "?tab=":
            base_info["oid"] = referer[23:len(referer) - 6]
        else:
            base_info["oid"] = referer[23:len(referer)]
    end = 0
    for i in range(int((base_info["comment"] - 1) / 20) + 1):
        if i == 0:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=" + str(type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1));
        else:
            url = "https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=" + str(i + 1) + "&type=" + str(type) + \
                  "&oid=" + str(base_info["oid"]) + "&mode=3&plat=1&_=" + str((int(round(time.time() * 1000)) + 1));

        if i == int((base_info["comment"] - 1) / 20):
            end = 1
        get_data(url, end)
        time.sleep(0.5)


# 获取数据函数
def get_data(url, end):
    req = urllib.request.urlopen(url)
    ret = req.read().decode()
    # print(ret)
    json1 = json.loads(ret)
    # json1["data"]["replies"]有可能为null
    if json1["data"]["replies"] is not None:
        len1 = len(json1["data"]["replies"])
        for i in range(len1):
            mid = json1["data"]["replies"][i]["member"]["mid"]
            uname = json1["data"]["replies"][i]["member"]["uname"]
            message = json1["data"]["replies"][i]["content"]["message"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(mid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (mid, uname, message))
            con.commit()

        print("已获取" + str(len(id_set)) + "个用户的数据...")

    # print("插入一组数据组")

    if end == 1:
        print("数据获取完毕!\n")
        # print(name_set)
        # print(id_set)
        while len(lucky_set) < int(lucky_num):
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
            # print(lucky_set)
        # id_list = list(id_set)
        # name_list = list(name_set)
        # for i in range(int(lucky_num)):
        #     print("昵称:" + name_list[i] + "  id:" + id_list[i] + "\n")

        for i in range(int(lucky_num)):
            lucky_list = list(lucky_set)
            # print("lucky_num=" + str(lucky_list[i]))
            sql = "select * from user limit " + str(lucky_list[i]) + ",1"
            cur.execute(sql)
            rows = cur.fetchall()
            for row in rows:
                print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))


# 获取转发用户的数据
def get_repost_user_info(referer, base_info):
    print("开始获取用户信息...")

    # 用户输入是否是完整复制动态链接,链接尾部 是否是 ?tab=2
    if referer[-6:-1] == "?tab=":
        dynamic_id = referer[23:len(referer) - 6]
    else:
        dynamic_id = referer[23:len(referer)]

    temp_num = 0
    # 根据转发数进行循环
    while temp_num < int(base_info["repost"]):
        url = "https://api.live.bilibili.com/dynamic_repost/v1/dynamic_repost/view_repost?dynamic_id=" + \
              str(dynamic_id) + "&offset=" + str(temp_num);
        req = urllib.request.urlopen(url)
        ret = req.read().decode()

        # print(url)
        # print(ret)

        json1 = json.loads(ret)
        len1 = 0
        if "comments" in ret:
            len1 = len(json1["data"]["comments"])
            # print(len1)
        else:
            print("可获取的数据结束!\n")
            break
        for i in range(len1):
            uid = json1["data"]["comments"][i]["uid"]
            uname = json1["data"]["comments"][i]["uname"]
            comment = json1["data"]["comments"][i]["comment"]

            # 数据插入集合
            # name_set.add(uname)
            id_set.add(uid)
            # 数据插入数据库
            sql = "replace into user(mid, uname, message) values (?, ?, ?)"
            cur.execute(sql, (uid, uname, comment))
            con.commit()

        temp_num += 20
        print("已获取" + str(len(id_set)) + "个用户的数据...")
        time.sleep(0.5)
    print("数据获取完毕!\n")
    while len(lucky_set) < int(lucky_num):
        num = 0
        if len(id_set) > 1:
            num = random.randint(0, (len(id_set) - 1))
            lucky_set.add(num)
        else:
            print('用户数据不足2个,数据异常,程序结束')
            return
    for i in range(int(lucky_num)):
        lucky_list = list(lucky_set)
        # print("lucky_num=" + str(lucky_list[i]))
        sql = "select * from user limit " + str(lucky_list[i]) + ",1"
        cur.execute(sql)
        rows = cur.fetchall()
        for row in rows:
            print('\nid:%s  昵称:%s  评论:%s' % (row[0], row[1], row[2]))


# 配置数据库
config_db()
# 获取oid、转发数、评论数
base_info = get_oid(referer)

if base_info["ret"]:
    print("oid=" + str(base_info["oid"]))
    print("转发数=" + str(base_info["repost"]))
    print("评论数=" + str(base_info["comment"]))

    # 根据抽奖类型进行抽奖 1评论 0转发
    if (int(draw_type) == 1):
        # 获取用户信息并抽取幸运用户
        get_user_info(referer, base_info)
    else:
        get_repost_user_info(referer, base_info)

    # 关闭游标
    cur.close()
    # 断开数据库连接
    con.close()

    print("\n程序运行完毕!")
    quit = 0
    while quit != "1":
        quit = input("是否关闭程序(是1,否0):")


  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 32
    评论
你可以使用 Python 的 requests 库和 BeautifulSoup 库来实现这个爬虫。首先,你需要使用 requests 库向哔哩哔哩动态页面发送 GET 请求,获取动态页面的 HTML 代码。然后,你可以使用 BeautifulSoup 库解析 HTML 代码,找到抽奖相关的信息,比如抽奖的标题、抽奖的链接等等。最后,你可以使用 requests 库向抽奖链接发送 POST 请求,完自动转发抽奖的操作。 具体的代码实现可以参考以下的示例: ```python import requests from bs4 import BeautifulSoup # 设置请求头,模拟浏览器访问 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} # 发送 GET 请求,获取动态页面的 HTML 代码 url = 'https://t.bilibili.com/' response = requests.get(url, headers=headers) html = response.text # 使用 BeautifulSoup 解析 HTML 代码,找到抽奖相关的信息 soup = BeautifulSoup(html, 'html.parser') lottery_title = soup.find('div', class_='card-title').text lottery_link = soup.find('a', class_='card-image')['href'] # 发送 POST 请求,完自动转发抽奖的操作 data = { 'title': lottery_title, 'link': lottery_link, 'action': 'enter', 'csrf': 'xxxxxxxxxxxxxxxxxxxxx' # 这里需要填写你的 CSRF token } response = requests.post('https://t.bilibili.com/lottery/handler/Join', headers=headers, data=data) ``` 需要注意的是,这个示例中的 CSRF token 需要你自己从哔哩哔哩动态页面中获取。你可以使用浏览器的开发者工具,在 Network 标签页中找到抽奖链接对应的请求,然后在 Headers 标签页中找到 CSRF token。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Love丶伊卡洛斯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值