君临天下v 发表于 2020-7-21 18:58

B站自动操作脚本(投币点赞分享视频,直播签到,获取银瓜子,自动转发抽奖,漫画APP签到)

本帖最后由 君临天下v 于 2020-8-22 23:06 编辑

#2020/08/22更新
##更新内容
###1.增加参与B站官方活动抽奖的功能
####活动列表在config/activity.json文件中,对应B站 https://www.bilibili.com/blackboard/x/act_list/ ,我抽中了一个抱枕,奖品一般是几个硬币或者月度会员之类的。(所有活动都有过期时间,如果出新活动需要手动更新config/activity.json文件)。
###2.增加动态清理的功能,每半个月清理一次转发的抽奖动态和被原up主删除的失效动态
###3.去除客户端access_key参数
####模拟客户端签到的功能不再需要手机抓包得到access_key,账户配置文件移到config/config.json
###4.添加aliyun-serverless-template.yml文件,借助阿里云的funcraft工具可实现一键部署到阿里云
####阿里云funcraft工具windows版下载地址https://gosspublic.alicdn.com/fun/fun-v3.6.14-win.exe.zip, 解压进入cmd,cd到解压目录,执行fun-v3.6.14-win config,输入阿里云的AccountID,AccessKeyID,AccessKeySecret和服务器地区四个参数,再cd到我的脚本目录,执行fun-v3.6.14-win deploy -t aliyun-serverless-template.yml即可直接部署到阿里云函数。
</br>
最新代码已经上传到附件和github(https://github.com/happy888888/BiliExp) ,支持使用github actions将代码自动部署到阿里云函数(需要将阿里云的AccessKey等参数和B站cookie等参数填入github中的Secret中),其他云函数目前并不支持一键部署,请自行探索手动部署</br>



#2020/07/31更新
##更新内容
###1.添加server酱的微信推送接口用来推送脚本执行情况
###2.去除自动抽奖脚本的数据库文件,自动抽奖脚本支持云函数运行
###3.添加B站直播领取时间宝箱获取银瓜子的功能
###4.添加将银瓜子兑换为硬币的功能
###5.添加检查用户登录状态的有效性,登录失效时推送微信消息的功能

##使用方法(以阿里云函数为例)
#####1.准备工作
* 1.1 解压附件,在userData/userData.py文件中填写账户cookie,B站app的access_key(仅领取时间宝箱获取银瓜子的功能需要),B站漫画app的access_key(仅漫画app签到需要),server酱的SCKEY(仅微信推送需要,详情见sc.ftqq.com)。
* 1.2 返回上级目录,将所有.py文件和文件夹全选中右键压缩为.zip文件(并非把所有文件放在一个文件夹下压缩)。

#####2.部署投币、点赞、分享视频,直播签到脚本
* 2.1 进入阿里云函数https://fc.console.aliyun.com/fc/overview/cn-shanghai </br>
!(https://wx1.sbimg.cn/2020/07/31/Pahl8.jpg)
* 2.2 点击"服务/函数"--》"新建函数"</br>
!(https://wx1.sbimg.cn/2020/07/31/Pagw2.jpg)
* 2.3 点击"下一步"</br>
!(https://wx1.sbimg.cn/2020/07/31/Pad91.jpg)
* 2.4 函数名称随意填写,运行环境选择"python3",函数入口填写"BiliExp.main",点击"完成"</br>
!(https://wx1.sbimg.cn/2020/07/31/PaRVl.jpg)
* 2.5 在"代码执行"页面中选择"代码包上传",点击"选择文件",上传1.1中的压缩包,点击"保存"</br>
!(https://wx1.sbimg.cn/2020/07/31/PaBYo.jpg)
* 2.6 点击"触发器"--》"创建触发器",服务类型选择"定时触发器",触发器名称随意填写,时间配置选择"Cron表达式",内容填写"0 30 0 \* \* \*"(不要引号,意思是每天凌晨0:30执行一次),点击"确定"
!(https://wx2.sbimg.cn/2020/07/31/PaJCJ.jpg)

#####3.部署自动抽奖脚本
* 3.1 重复步骤2.1 - 2.6,仅把步骤2.4中函数入口填写改为"BiliLottery.main",把步骤2.6中"cron表达式"改为"0 \*/10 0 \* \* \*"(意思是每10分钟执行一次)

#####4.部署直播领取时间宝箱获取银瓜子脚本
* 4.1 重复步骤2.1 - 2.6,仅把步骤2.4中函数入口填写改为"SilverAward.main",把步骤2.6中"cron表达式"改为"0 \*/10 1,2 \* \* \*"(意思是在每天1点和2点,每10分钟执行一次)

#####5.部署银瓜子兑换硬币脚本
* 5.1 重复步骤2.1 - 2.6,仅把步骤2.4中函数入口填写改为"silver2coin.main",把步骤2.6中"cron表达式"改为"0 0 4 \* \* \*"(意思是在每天4点执行一次)

#####6.部署漫画签到脚本
* 6.1 重复步骤2.1 - 2.6,仅把步骤2.4中函数入口填写改为"mangaClockIn.main",把步骤2.6中"cron表达式"改为"0 0 1 \* \* \*"(意思是在每天1点执行一次)

#####7.部署账户登录状态检测脚本(账户失效后会微信推送)
* 7.1 重复步骤2.1 - 2.6,仅把步骤2.4中函数入口填写改为"userData/check.main",把步骤2.6中"cron表达式"改为"0 0 0 \* \* \*"(意思是在每天0点执行一次)

</br>关于自动抽奖脚本带来的动态臃肿问题,建议定期删除已经过期的抽奖动态。</br>
打开 B站主页--》右上角"动态"--》左边头像下方"动态"(此时浏览器链接应该为https://space.bilibili.com/xxxxxx/dynamic)</br>
按F12打开开发者工具--》console--》粘贴以下脚本,回车,然后等待无效动态删除完就行</br>
`(function(){if(!window.location.href.match(/https:\/\/space.bilibili.com\/*\/dynamic.*/g)){console.log("本脚本只能在B站个人动态页面执行!");return}var i=0;function dellott(){var a=$("span.dynamic-link-hover-bg").eq(i);if(a.length==0){$(document).scrollTop($(document).height()-$(window).height());setTimeout(function(){dellott()},1500);return}var ids=a.attr("click-href").match(/.*business_id=(*)&.*/);if(ids){var bid=ids}else{setTimeout(function(){i++;dellott()},500);return}$.get("https://api.vc.bilibili.com/lottery_svr/v1/lottery_svr/lottery_notice",{"dynamic_id":bid},function(data){if("lottery_result" in data["data"]){a.parents("div.card").find(".child-button").click();setTimeout(function(){$(".bp-popup-ctnr").find(".bl-button--size").click();dellott()},1000)}else{i++;dellott()}})}dellott()})();`



今天开放注册,新人报道,分享自己写的B站自动操作脚本,功能简介如下:
1.投币、点赞、分享视频(每项操作都有经验值,如果今天已投币大于5,则不投币,否则投x个币,x为现有币的数量)
2.直播签到(连续签到可以获得银瓜子,大老爷权限和月老称号)
3.自动转发抽奖(计划任务每隔10分钟启动一次抽奖脚本)
4.漫画APP签到(连续签到7天可以获得漫读券一张)

Biliapi.py,B站操作类,后续脚本依赖这个类

# -*- coding: utf-8 -*-
import requests
import json
import re
class Biliapi(object):
    "B站API操作"
    __headers = {
            "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36",
            "Referer": "https://www.bilibili.com/",
            }
    def __init__(self, cookieData):
      #创建session
      self.__session = requests.session()
      #添加cookie
      requests.utils.add_dict_to_cookiejar(self.__session.cookies, cookieData)
      #设置header
      self.__session.headers.update(Biliapi.__headers)

      self.__bili_jct = cookieData["bili_jct"]
      self.__uid = cookieData["DedeUserID"]

      content = self.__session.get("https://account.bilibili.com/home/reward")
      if json.loads(content.text)["code"] != 0:
            raise Exception("参数验证失败")


    def getReward(self):
      "取B站经验信息"
      url = "https://account.bilibili.com/home/reward"
      content = self.__session.get(url)
      return json.loads(content.text)["data"]

    @staticmethod
    def getId(url):
      "取B站指定视频链接的aid和cid号"
      content = requests.get(url, headers=Biliapi.__headers)
      match = re.search( 'https:\/\/www.bilibili.com\/video\/av(.*?)\/\">', content.text, 0)
      aid = match.group(1)
      match = re.search( '\"cid\":(.*?),', content.text, 0)
      cid = match.group(1)
      return {"aid": aid, "cid": cid}

    def getCoin(self):
      "获取剩余硬币数"
      url = "https://api.bilibili.com/x/web-interface/nav?build=0&mobi_app=web"
      content = self.__session.get(url)
      return int(json.loads(content.text)["data"]["money"])

    def coin(self, aid, num, select_like):
      "给指定av号视频投币"
      url = "https://api.bilibili.com/x/web-interface/coin/add"
      post_data = {
            "aid": aid,
            "multiply": num,
            "select_like": select_like,
            "cross_domain": "true",
            "csrf": self.__bili_jct
            }
      content = self.__session.post(url, post_data)
      return json.loads(content.text)

    def share(self, aid):
      "分享指定av号视频"
      url = "https://api.bilibili.com/x/web-interface/share/add"
      post_data = {
            "aid": aid,
            "csrf": self.__bili_jct
            }
      content = self.__session.post(url, post_data)
      return json.loads(content.text)

    def report(self, aid, cid, progres):
      "B站上报观看进度"
      url = "http://api.bilibili.com/x/v2/history/report"
      post_data = {
            "aid": aid,
            "cid": cid,
            "progres": progres,
            "csrf": self.__bili_jct
            }
      content = self.__session.post(url, post_data)
      return json.loads(content.text)

    def getHomePageUrls(self):
      "取B站首页推荐视频地址列表"
      url = "https://www.bilibili.com"
      content = self.__session.get(url)
      match = re.findall( '<div class=\"info-box\"><a href=\"(.*?)\" target=\"_blank\">', content.text, 0)
      match = ["https:" + x for x in match]
      return match

    @staticmethod
    def getRegions(rid=1, num=6):
      "获取B站分区视频信息"
      url = "https://api.bilibili.com/x/web-interface/dynamic/region?ps=" + str(num) + "&rid=" + str(rid)
      content = requests.get(url, headers=Biliapi.__headers)
      datas = json.loads(content.text)["data"]["archives"]
      ids = []
      for x in datas:
            ids.append({"title": x["title"], "aid": x["aid"], "bvid": x["bvid"], "cid": x["cid"]})
      return ids

    @staticmethod
    def getRankings(rid=1, day=3):
      "获取B站分区排行榜视频信息"
      url = "https://api.bilibili.com/x/web-interface/ranking?rid=" + str(rid) + "&day=" + str(day)
      content = requests.get(url, headers=Biliapi.__headers)
      datas = json.loads(content.text)["data"]["list"]
      ids = []
      for x in datas:
            ids.append({"title": x["title"], "aid": x["aid"], "bvid": x["bvid"], "cid": x["cid"], "coins": x["coins"], "play": x["play"]})
      return ids

    def repost(self, dynamic_id, content="", extension='{"emoji_type":1}'):
      "转发B站动态"
      url = "https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/repost"
      post_data = {
            "uid": self.__uid,
            "dynamic_id": dynamic_id,
            "content": content,
            "extension": extension,
            #"at_uids": "",
            #"ctrl": "[]",
            "csrf_token": self.__bili_jct
            }
      content = self.__session.post(url, post_data)
      return json.loads(content.text)

    def getDynamicNew(self, type_list='268435455'):
      "取B站用户动态数据"
      url = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=" + self.__uid + "&type_list=" + type_list
      content = self.__session.get(url)
      return json.loads(content.text)

    @staticmethod
    def mangaClockIn(access_key, platform="android"):
      "模拟B站漫画客户端签到"
      url = "https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn"
      headers = {
            "User-Agent": "Mozilla/5.0 BiliComic/3.0.0",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            }
      post_data = {
            "access_key": access_key,
            "platform": platform
            }
      content = requests.post(url, data=post_data, headers=headers)
      return json.loads(content.text)

    def xliveSign(self):
      "B站直播签到"
      url = "https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/DoSign"
      content = self.__session.get(url)
      return json.loads(content.text)


BiliExp.py,负责直播签到,投币分享获取经验,模拟观看视频用来模拟用户登陆操作

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Biliapi import Biliapi
import logging

cookieDatas = [{
    "SESSDATA": "填写账户1 SESSDATA",
    "bili_jct": "填写账户1 bili_jct",
    "DedeUserID": "填写账户1 UserID",
    },
    {
    "SESSDATA": "填写账户2 SESSDATA",
    "bili_jct": "填写账户2 bili_jct",
    "DedeUserID": "填写账户2 UserID",
    }]

def bili_exp(cookieData):
   "B站直播签到,投币分享获取经验,模拟观看一个视频"
   logging.info(f': B站经验脚本开始为id为{cookieData["DedeUserID"]}的用户进行直播签到,投币点赞分享并观看一个首页视频')
   try:
       biliapi = Biliapi(cookieData)
   except Exception as e:
       logging.error(f'登录验证id为{cookieData["DedeUserID"]}的账户失败,原因为{str(e)},跳过此账户后续所有操作')
       return

   try:
       xliveInfo = biliapi.xliveSign()
       logging.info(f'bilibili直播签到信息:{str(xliveInfo)}')
   except Exception as e:
       logging.warning(f'直播签到异常,原因为{str(e)}')

   try:
       reward = biliapi.getReward()
       logging.info(f'经验脚本开始前经验信息 :{str(reward)}')
   except Exception as e:
       logging.warning(f'获取账户经验信息异常,原因为{str(e)},跳过此账户后续所有操作')
       return

   try:
       coin_num = biliapi.getCoin()
   except Exception as e:
       logging.warning(f'获取账户剩余硬币数异常,原因为{str(e)}')
       coin_num = 0

   coin_exp_num = (50 - reward["coins_av"]) // 10
   toubi_num = coin_exp_num if coin_num > coin_exp_num else coin_num

   try:
       datas = biliapi.getRegions()
   except Exception as e:
       logging.warning(f'获取B站分区视频信息异常,原因为{str(e)},跳过此账户后续所有操作')
       return

   if(toubi_num > 0):
       for i in range(toubi_num):
         try:
               info = biliapi.coin(datas["aid"], 1, 1)
               logging.info(f'投币信息 :{str(info)}')
         except Exception as e:
               logging.warning(f'投币异常,原因为{str(e)}')

   try:
       info = biliapi.report(datas["aid"], datas["cid"], 300)
       logging.info(f'模拟视频观看进度上报:{str(info)}')
   except Exception as e:
       logging.warning(f'模拟视频观看异常,原因为{str(e)}')

   try:
       info = biliapi.share(datas["aid"])
       logging.info(f'分享视频结果:{str(info)}')
   except Exception as e:
       logging.warning(f'分享视频异常,原因为{str(e)}')

   logging.info(f'id为{cookieData["DedeUserID"]}的账户操作全部完成')

def main(*args):
    try:
      logging.basicConfig(filename="exp.log", filemode='a', level=logging.INFO, format="%(asctime)s: %(levelname)s, %(message)s", datefmt="%Y/%d/%m %H:%M:%S")
    except:
      pass
    for x in cookieDatas:
      bili_exp(x)

main()

需要填写SESSDATA,bili_jct,DedeUserID三个参数,支持多用户,参数获取方法为:
浏览器打开B站主页--》按F12打开开发者工具--》application--》cookies

BiliLottery.py,负责转发抽奖信息,需要定时启动

from Biliapi import Biliapi
import sqlite3

cookieData = {
    "SESSDATA": "0ad8e6d8%2C1608434698%2C1eba3*61",
    "bili_jct": "e85bbbe9712cf8b9160aa5921a269a97",
    "DedeUserID": "8466742",
}

def update(dynamic_id):
    conn = sqlite3.connect('lottery.db')
    cursor = conn.cursor()
    cursor.execute("SELECT id FROM lottery WHERE dynamic_id=?", (dynamic_id,))
    result = True if cursor.fetchone() else False
    if not result:
      cursor.execute("SELECT id FROM lottery ORDER BY date ASC LIMIT 0,1")
      id = cursor.fetchone()
      cursor.execute("UPDATE lottery SET dynamic_id=? WHERE id=?", (dynamic_id, id))
    cursor.close()
    conn.commit()
    conn.close()
    return result

def bili_lottery(data):

    try:
      biliapi = Biliapi(data)
    except Exception as e:
      logging.error(f'登录验证id为{data["DedeUserID"]}的账户失败,原因为{str(e)},跳过后续所有操作')
      return

    try:
      datas = biliapi.getDynamicNew()["data"]["cards"]
    except Exception as e:
      logging.warning(f'获取动态列表异常,原因为{str(e)},跳过后续所有操作')
      return

    for x in datas:
      if x.__contains__("extension") and x["extension"].__contains__("lott"):
            uname = x["desc"]["user_profile"]["info"]["uname"]
            dynamic_id = x["desc"]["dynamic_id"]
            if not update(dynamic_id):
                try:
                  biliapi.repost(dynamic_id)
                  logging.info(f'转发抽奖(用户名:{uname},dynamic_id:{str(dynamic_id)})成功')
                except Exception as e:
                  logging.warning(f'此次转发抽奖失败,原因为{str(e)}')

def main(*args):
    try:
      logging.basicConfig(filename="lottery.log", filemode='a', level=logging.INFO, format="%(asctime)s: %(levelname)s, %(message)s", datefmt="%Y/%d/%m %H:%M:%S")
    except:
      pass
    bili_lottery(cookieData)

main()


mangaClockIn.py,负责B站漫画APP签到,需要access_key参数来保持登录状态,需要会手机抓包的才能拿到这个参数,我这里就不细讲了

from Biliapi import Biliapi
import logging

access_keys = ["这里填写access_key,可以多个,用逗号分开"]

def mangaClockIn(access_key):
    logging.info(f'B站漫画签到脚本开始为access_key({access_key}的账户签到')
    try:
      result = Biliapi.mangaClockIn(access_key)
      logging.info(f'签到信息为:{str(result)}')
    except Exception as e:
      logging.warning(f'签到异常,原因为{str(e)}')

def main(*args):
    try:
      logging.basicConfig(filename="manga.log", filemode='a', level=logging.INFO, format="%(asctime)s: %(levelname)s, %(message)s", datefmt="%Y/%d/%m %H:%M:%S")
    except:
      pass
    for x in access_keys:
      mangaClockIn(x)

main()



所有脚本放在附件里,除了抽奖的脚本都可以在腾讯云函数里面运行,腾讯云函数怎么用论坛里已经有教程了,这里不细讲了。

ly765893958 发表于 2020-9-19 15:20

本帖最后由 ly765893958 于 2020-9-19 15:30 编辑

https://1www.lanzouj.com/i1UWvgrczmh每次都抓包取Cookie比较麻烦,有些人可能还不会,我自己写了一个小工具,只需要手动登陆一次,就可以自动取出Cookie并且生成填写好信息的BiliExp.py文件,只用拿到目录里去用就行了,比较方便一点!!!为了方便自己写的东西,顺带也分享出来,希望可以帮到大家!
https://s1.ax1x.com/2020/09/19/w5x6vF.jpghttps://s1.ax1x.com/2020/09/19/w5vmoq.jpg

https://www.lanzouj.com/i3IIAgrd8ti附带一个完整的打包,在装有python环境的电脑上直接用本工具登陆一次,然后点启动.bat就行了,如果自己有服务器想挂的话,也可以自己写个定时的小脚本来挂!

君临天下v 发表于 2020-7-23 08:52

十叶 发表于 2020-7-22 23:12
这咋用,纯小白,求教

保存第一个代码,命名为Biliapi.py
如果只需要直播签到,投币分享获取经验和模拟观看视频,只需要保存第二个代码,命名为BiliExp.py,将两个文件放在一起
填写BiliExp.py文件中SESSDATA,bili_jct,DedeUserID三个参数,参数获取方法看一楼

如果要本地执行,按win+r,输入cmd回车,在弹出的窗口中输入python c:\BiliExp.py并回车就行(这里假定Biliapi.py和BiliExp.py都放在c盘根目录)。如果要每天执行,按win+r,输入taskschd.msc回车,右键任务计划程序库,创建基本任务,输入任务名一直下一步,直到让你输入程序或脚本时,输入python c:\BiliExp.py再一直下一步直到完成。
注意本地执行需要先安装python3.6,安装requests库

如果要使用腾讯云函数,可以参考本站内其它人的帖子(我也是在本站内找到使用方法的),不同点在于创建好函数后,默认只有一个index.py,需要清空后把第二个代码复制进去,还需要新建一个Biliapi.py文件,把第一个代码复制进去,并把上面"执行方法"改为index.main,保存就行。如果要每天执行,需要在左边触发管理里新建一个触发器,触发周期选择每天一次,保存就行。

win计划任务和腾讯云函数的使用方法本站里已经有人发详细的图文教程了,这里不再赘述。
我也是论坛新人而已,希望共同进步。

君临天下v 发表于 2020-8-10 20:31

121W 发表于 2020-8-5 08:40
再问下楼主可以设置每天投币数量吗?

可以的,把BiliExp.py里面toubi_num = coin_exp_num if coin_num > coin_exp_num else coin_num那一行改为toubi_num = 3就可以每天只投3个币,access_key需要手机抓包,我用的Fiddler,Android7.0以后的系统需要root后才能安装证书,然后才能抓包https

az12az 发表于 2020-7-21 19:52

不错的东西。

18364166263 发表于 2020-7-21 20:00

不错,以后不用人肉投币了

南岸 发表于 2020-7-21 20:37


不错的东西。

quanxiaodai 发表于 2020-7-21 20:44

这个可以,不错

Painting 发表于 2020-7-21 20:51

阔以,感谢分享

isnoya 发表于 2020-7-21 23:35

同新人,但你是大佬{:1_921:}

桀兄3712 发表于 2020-7-22 07:33

新人表示,这个是可以学习的技术,谢谢你的分享。

NiniStark 发表于 2020-7-22 07:49

新人之间的差距也太大了

wynnshn 发表于 2020-7-22 07:55

拜读大佬作品,学习中
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: B站自动操作脚本(投币点赞分享视频,直播签到,获取银瓜子,自动转发抽奖,漫画APP签到)