├── log └── daily.log ├── common ├── __init__.py ├── get_secrets.py ├── __pycache__ │ ├── config.cpython-36.pyc │ ├── dirs.cpython-36.pyc │ ├── logger.cpython-36.pyc │ ├── __init__.cpython-36.pyc │ ├── dy_badge.cpython-36.pyc │ ├── dy_glows.cpython-36.pyc │ ├── get_secrets.cpython-36.pyc │ ├── login_check.cpython-36.pyc │ ├── douyu_request.cpython-36.pyc │ └── send_message.cpython-36.pyc ├── dirs.py ├── logger.py ├── login_check.py ├── config.py ├── send_message.py ├── douyu_request.py ├── dy_badge.py └── dy_glows.py ├── .gitignore ├── docs └── img │ ├── Config.png │ ├── Linux1.png │ ├── Linux2.png │ ├── Path1.png │ ├── Path2.png │ ├── Path3.jpg │ ├── Secrets.png │ ├── cookie.png │ ├── Workfelow.png │ ├── WatchAction.png │ ├── WatchAction2.png │ └── WatchAction3.png ├── requirements.txt ├── config └── config.ini ├── .github └── workflows │ └── auto_donate_douyu.yml ├── main.py └── README.md /log/daily.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | venv/ 3 | log/ 4 | 5 | # Generated by MacOS 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /docs/img/Config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Config.png -------------------------------------------------------------------------------- /docs/img/Linux1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Linux1.png -------------------------------------------------------------------------------- /docs/img/Linux2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Linux2.png -------------------------------------------------------------------------------- /docs/img/Path1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Path1.png -------------------------------------------------------------------------------- /docs/img/Path2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Path2.png -------------------------------------------------------------------------------- /docs/img/Path3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Path3.jpg -------------------------------------------------------------------------------- /docs/img/Secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Secrets.png -------------------------------------------------------------------------------- /docs/img/cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/cookie.png -------------------------------------------------------------------------------- /common/get_secrets.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def get_secrets(item): 5 | return os.environ[item] 6 | -------------------------------------------------------------------------------- /docs/img/Workfelow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/Workfelow.png -------------------------------------------------------------------------------- /docs/img/WatchAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/WatchAction.png -------------------------------------------------------------------------------- /docs/img/WatchAction2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/WatchAction2.png -------------------------------------------------------------------------------- /docs/img/WatchAction3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/docs/img/WatchAction3.png -------------------------------------------------------------------------------- /common/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/dirs.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/dirs.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/logger.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/logger.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/dy_badge.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/dy_badge.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/dy_glows.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/dy_glows.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/get_secrets.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/get_secrets.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/login_check.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/login_check.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/douyu_request.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/douyu_request.cpython-36.pyc -------------------------------------------------------------------------------- /common/__pycache__/send_message.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSlientnight/douyu_helper/HEAD/common/__pycache__/send_message.cpython-36.pyc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | packaging 2 | requests>=2.28.1 3 | lxml>=4.9.1 4 | selenium>=4.3.0 5 | jsonpath>=0.82 6 | loguru>=0.6.0 7 | webdriver-manager>=3.8.0 8 | 9 | -------------------------------------------------------------------------------- /config/config.ini: -------------------------------------------------------------------------------- 1 | [Modechoose] 2 | # givemode为赠送模式,1为自定义模式,0为平均分配模式 3 | giveMode = 0 4 | 5 | [selfMode] 6 | # 房间号和荧光棒分配数量用逗号做分隔符,上下对应 7 | roomId = 93589 8 | giftCount = 50 9 | 10 | [log] 11 | logger_level = INFO 12 | stream_level = INFO 13 | file_level = INFO 14 | file_level_rf = INFO 15 | -------------------------------------------------------------------------------- /common/dirs.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | import os 3 | import time 4 | 5 | # 根目录 6 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 7 | # 设置地址 8 | CONFIG_DIR = os.path.join(BASE_DIR, "config") 9 | # 日志目录 10 | LOGS_DIR = os.path.join(BASE_DIR, "log") 11 | # 日志地址 12 | LOG_FILE = os.path.join(LOGS_DIR, "daily.log") 13 | 14 | 15 | def file_log(filepath): 16 | dir = LOGS_DIR 17 | if not os.path.exists(dir): 18 | os.makedirs(dir) 19 | return os.path.join(dir, "daily.log") 20 | 21 | 22 | if __name__ == '__main__': 23 | print(LOGS_DIR) 24 | -------------------------------------------------------------------------------- /common/logger.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from loguru import logger 4 | 5 | 6 | class Logger: 7 | __instance = None 8 | 9 | def __new__(cls, *args, **kwargs): 10 | if not cls.__instance: 11 | cls.__instance = super(Logger, cls).__new__(cls, *args, **kwargs) 12 | 13 | return cls.__instance 14 | 15 | def __init__(self): 16 | self.log = logger 17 | 18 | def info(self, msg): 19 | return self.log.info(msg) 20 | 21 | def debug(self, msg): 22 | return self.log.debug(msg) 23 | 24 | def warning(self, msg): 25 | return self.log.warning(msg) 26 | 27 | def error(self, msg): 28 | return self.log.error(msg) 29 | 30 | 31 | loggers = Logger() 32 | -------------------------------------------------------------------------------- /.github/workflows/auto_donate_douyu.yml: -------------------------------------------------------------------------------- 1 | name: Daily donate in 12306 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | schedule: 9 | - cron: '02 16 * * *' 10 | - cron: '02 19 * * *' 11 | 12 | jobs: 13 | dy_auto_donate_helper: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: 'Checkout' 17 | uses: actions/checkout@v2 18 | - name: 'Set up Python' 19 | uses: actions/setup-python@v1 20 | with: 21 | python-version: 3.7 22 | - name: 'Install requirements' 23 | run: pip install -r requirements.txt 24 | - name: 'Working' 25 | env: 26 | SERVERPUSHKEY: ${{ secrets.SERVERPUSHKEY }} 27 | COOKIES: ${{ secrets.COOKIES }} 28 | BARKURL: ${{ secrets.BARKURL }} 29 | run: | 30 | python main.py 31 | -------------------------------------------------------------------------------- /common/login_check.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | from common.douyu_request import dyreq 3 | from common.logger import logger 4 | import requests 5 | from common.get_secrets import get_secrets 6 | 7 | 8 | Is_login = 0 9 | login_url = "/wgapi/livenc/liveweb/follow/list" 10 | 11 | 12 | def is_login(): 13 | """ 14 | :return:返回登陆结果,用于主程序判断 15 | """ 16 | global Is_login 17 | login = dyreq.request("get", login_url).json() 18 | if login['error'] == 0: 19 | Is_login = 1 20 | logger.info("Cookie有效,登陆成功") 21 | else: 22 | logger.warning("登陆失败,请检查Cookie有效性") 23 | # check if get_secrets('BARKURL') starts with http 24 | barkurl = get_secrets('BARKURL') 25 | if barkurl.startswith('http'): 26 | requests.get(barkurl + "/斗鱼+Cookie+失效/登陆失败,请检查Cookie有效性") 27 | logger.warning("Notification Sent") 28 | 29 | return Is_login 30 | 31 | 32 | if __name__ == '__main__': 33 | is_login() 34 | -------------------------------------------------------------------------------- /common/config.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | import configparser 3 | from common.dirs import * 4 | import os 5 | 6 | conf_path = os.path.join(CONFIG_DIR, "config.ini") 7 | 8 | 9 | class Config(configparser.ConfigParser): 10 | 11 | def __init__(self): 12 | super().__init__() 13 | self.file = conf_path 14 | self.read(self.file, encoding="utf8") 15 | 16 | def get_conf(self, section, *options) -> dict: 17 | op_list = [] 18 | if options: 19 | for option in options: 20 | res = self.get(section, option) 21 | op_list.append(res) 22 | options_list = dict(zip(options, op_list)) 23 | else: 24 | options_list = dict(self.items(section)) 25 | return options_list 26 | 27 | def get_conf_list(self, section, option): 28 | return Config.get_conf(self, section, option)[option].split(",") 29 | 30 | 31 | conf = Config() 32 | 33 | if __name__ == '__main__': 34 | a = Config() 35 | b = a.get_conf("Modechoose")['givemode'] 36 | print(b) 37 | -------------------------------------------------------------------------------- /common/send_message.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | import requests 3 | from common.dirs import LOGS_DIR, LOG_FILE 4 | from common.logger import logger 5 | import re 6 | 7 | 8 | def log_reader(): 9 | with open(LOG_FILE, 'r', encoding="UTF-8") as lg: 10 | logs = lg.readlines() 11 | logs_str = ''.join(logs).replace("\n","\n\n") 12 | return logs_str 13 | 14 | 15 | def send_message(send_key): 16 | url = "https://sctapi.ftqq.com/{}.send".format(send_key) 17 | data = { 18 | "title": u"DouYu-Helper执行结果", 19 | "desp": log_reader() 20 | } 21 | if data['desp']: 22 | try: 23 | logger.info("------执行server酱推送------") 24 | requests.post(url, data=data) 25 | logger.info("------推送成功------") 26 | except Exception as e: 27 | logger.error(e) 28 | else: 29 | data = { 30 | "title": u"DouYu-Helper执行结果", 31 | "desp": "执行出现问题,日志为空" 32 | } 33 | requests.post(url, data=data) 34 | 35 | 36 | if __name__ == '__main__': 37 | send_message() -------------------------------------------------------------------------------- /common/douyu_request.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | from requests.sessions import session 3 | from common.get_secrets import get_secrets 4 | 5 | 6 | # 重写请求方法,便于直接获取结果 7 | class DYHTTPRequests: 8 | 9 | def __init__(self): 10 | self.cookie = get_secrets('COOKIES') 11 | self.session = session() 12 | self.header = { 13 | "Content-Type": "application/x-www-form-urlencoded", 14 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " 15 | "Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.81", 16 | "referer": "https://www.douyu.com", 17 | "Cookie": self.cookie 18 | } 19 | 20 | def request(self, method, path, **kwargs): 21 | url = "https://www.douyu.com" + path 22 | method.upper() 23 | return self.session.request(method, url=url, headers=self.header, **kwargs) 24 | 25 | def __del__(self): 26 | self.session.close() 27 | 28 | 29 | dyreq = DYHTTPRequests() 30 | if __name__ == '__main__': 31 | print(dyreq.request("get", "/lapi/member/api/getInfo").json()) 32 | glow_url = "/japi/prop/backpack/web/v1?rid=12306" 33 | print(dyreq.request("get", glow_url).json()) 34 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | from common.dy_glows import * 3 | from common.login_check import * 4 | from common.config import conf 5 | from common.dy_badge import * 6 | from common.logger import logger 7 | import math 8 | from common.get_secrets import get_secrets 9 | from common.send_message import send_message 10 | 11 | 12 | def run(): 13 | logger.info("------登录检查开始------") 14 | login_res = is_login() 15 | logger.info("------登录检查结束------") 16 | mode = int(conf.get_conf("Modechoose")['givemode']) 17 | if login_res: 18 | get_glow() 19 | try: 20 | glow_nums = get_own() 21 | assert glow_nums != 0 22 | if mode == 1: 23 | logger.info("当前选择模式为:自选模式") 24 | nums = conf.get_conf_list('selfMode', 'giftCount') 25 | room_list = conf.get_conf_list('selfMode', 'roomId') 26 | logger.info("------开始捐赠荧光棒------") 27 | for i in range(len(nums)): 28 | glow_donate(nums[i], room_list[i]) 29 | logger.info("------荧光棒捐赠结束------") 30 | get_need_exp() 31 | elif mode == 0: 32 | logger.info("当前选择模式为:平均分配模式") 33 | room_list = get_room_list() 34 | every_give = math.ceil(glow_nums / len(room_list)) 35 | left = int(glow_nums) - int(every_give) * (len(room_list) - 1) 36 | logger.info("------开始捐赠荧光棒------") 37 | for room in room_list: 38 | if room == room_list[-1]: 39 | glow_donate(left, room) 40 | else: 41 | glow_donate(every_give, room) 42 | logger.info("------荧光棒捐赠结束------") 43 | get_need_exp() 44 | else: 45 | logger.warning("配置错误,没有这种选项,请修改配置并重新执行") 46 | except Exception as e: 47 | logger.warning("背包中没有荧光棒,无法执行赠送,任务即将结束") 48 | logger.debug(e) 49 | else: 50 | logger.warning("未登录状态无法进行后续操作,任务已结束") 51 | try: 52 | server_key = get_secrets("SERVERPUSHKEY") 53 | send_message(server_key) 54 | except Exception as e: 55 | logger.info("当前未配置Server酱推送,任务结束") 56 | logger.debug(e) 57 | 58 | 59 | if __name__ == '__main__': 60 | run() 61 | -------------------------------------------------------------------------------- /common/dy_badge.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | from common.douyu_request import dyreq 3 | from common.logger import logger 4 | from common.config import conf 5 | from common.get_secrets import get_secrets 6 | from lxml import etree 7 | import re 8 | import math 9 | import requests 10 | 11 | 12 | def get_badge(): 13 | """ 14 | :return: 获取具有粉丝牌的房间号、当前经验、升级所需经验、升级还需要的经验 15 | """ 16 | badges_url = "/member/cp/getFansBadgeList" 17 | badges = dyreq.request("get", badges_url) 18 | html = etree.HTML(badges.text, etree.HTMLParser()) 19 | num = len(html.xpath('//*[@id="wrap"]/div/div[2]/div[2]/div[3]/table/tbody/tr')) 20 | re_now = r'(?<= )\d.*\d(?=\/\d)' 21 | re_up = r'(?<=\/)\d.*\d' 22 | badge_dict = {} 23 | exp_list = [] 24 | for path in range(num): 25 | path += 1 26 | room_id = html.xpath('//*[@id="wrap"]/div/div[2]/div[2]/div[3]/table/tbody/tr[%s]/@data-fans-room' % path)[ 27 | 0] 28 | anchor = html.xpath('//*[@id="wrap"]/div/div[2]/div[2]/div[3]/table/tbody/tr[%s]/td[2]/a/text()' % path)[0] 29 | exp = html.xpath('//*[@id="wrap"]/div/div[2]/div[2]/div[3]/table/tbody/tr[%s]/td[3]/text()' % path)[0] 30 | exp_now = float(re.findall(re_now, exp)[0]) 31 | up_grade = float(re.findall(re_up, exp)[0]) 32 | exp_need = round((up_grade - exp_now), 1) 33 | exp_list.append(exp_need) 34 | badge_dict[room_id] = anchor 35 | return badge_dict, exp_list 36 | 37 | 38 | def get_room_list(): 39 | """ 40 | :return:通过数组方式返回房间号 41 | """ 42 | room_list = [] 43 | for room in get_badge()[0]: 44 | room_list.append(room) 45 | return room_list 46 | 47 | 48 | def get_need_exp(): 49 | """ 50 | :return:通过数组方式返回升级所需经验 51 | """ 52 | nums = conf.get_conf_list('selfMode', 'giftCount') 53 | for i in range(len(get_badge()[1])): 54 | days_require = int(math.ceil(int(math.ceil(get_badge()[1][i])) / int(nums[i]))) 55 | logger.info("房间号%s升级还需%s点经验,还需%s天" % (get_room_list()[i], get_badge()[1][i], days_require)) 56 | barkurl = get_secrets('BARKURL') 57 | if barkurl.startswith('http'): 58 | requests.get(barkurl + "/房间号%s/升级还需%s点经验,+%s天" % (get_room_list()[i], get_badge()[1][i], days_require)) 59 | 60 | 61 | if __name__ == '__main__': 62 | a = get_room_list() 63 | get_need_exp() 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | DouYu-Helper 4 |

5 | 6 | [![GitHub stars](https://img.shields.io/github/stars/TheSlientnight/douyu_helper?style=flat-square)](https://github.com/TheSlientnight/douyu_helper/stargazers) 7 | [![GitHub forks](https://img.shields.io/github/forks/TheSlientnight/douyu_helper?style=flat-square)](https://github.com/TheSlientnight/douyu_helper/network) 8 | [![GitHub issues](https://img.shields.io/github/issues/TheSlientnight/douyu_helper?style=flat-square)](https://github.com/TheSlientnight/douyu_helper/issues) 9 | [![GitHub All Releases](https://img.shields.io/github/downloads/TheSlientnight/douyu_helper/total?style=flat-square)](https://github.com/TheSlientnight/douyu_helper/releases) 10 | [![GitHub contributors](https://img.shields.io/github/contributors/TheSlientnight/douyu_helper?style=flat-square)](https://github.com/TheSlientnight/douyu_helper/graphs/contributors) 11 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/TheSlientnight/douyu_helper?style=flat-square) 12 |
13 | 14 | ## 工具简介 15 | 利用Github Action的方式实现斗鱼TV自动获取粉丝荧光棒,并完成赠送工具,简单配置即可实现赠送每日赠送荧光棒 16 | 17 | **如果认为工具还算好用,请顺手点一个Star吧~** 18 | 19 | ## 功能列表 20 | * [x] 每天上午9点启动 21 | * [x] 自动获取荧光棒 22 | * [x] 自定义赠送的房间 23 | * [x] 平均分配荧光棒至拥有粉丝牌的房间 24 | * [x] 推送日志 25 | 26 | # 目录 27 | - [目录](#目录) 28 | - [使用说明](#使用说明) 29 | - [一、Actions方式](#一、Actions方式(推荐)) 30 | - [二、本地执行](#二、本地执行(不推荐)) 31 | 32 | ## 使用说明 33 | 34 | ### 一、Actions方式(推荐) 35 | 1. **Fork本项目** 36 | 2. 修改config.ini配置文件 37 | ![修改配置文件](docs/img/Config.png) 38 | 3. **获取自己斗鱼账号的COOKIE**(请注意:斗鱼的Token大概一周会失效,因此需要每周更新一次) 39 | 4. 使用浏览器登录[斗鱼](https://www.douyu.com) 40 | 5. 按下F12打开[开发者工具],在[网络/network]中打开筛选,选择XHR 41 | 6. 随意点击一个请求,将请求头中的cookie复制出来 42 | ![获取cookie](docs/img/cookie.png) 43 | 44 | 45 | 7. 在项目内点击Setting -> Secrets -> Actions -> New repository secret,并添加获取到的COOKIES 46 | 47 | | Name | Value | 48 | |-------------|--------------------------| 49 | |COOKIES |按步骤5获取 | 50 | |SERVERPUSHKEY|server酱(Turbo版)的推送sckey(可选配置)| 51 | |BARKURL|[Bark](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) 的推送链接(可选配置)| 52 | ![添加Secrets](docs/img/Secrets.png) 53 | 8. **开启Actions 并触发每日自动执行** 54 | **Fork仓库之后,GitHub默认不自动执行Actions任务,请手动执行一次以检查工作流** 55 | ![运行任务](docs/img/Workfelow.png) 56 | 57 | 9. 如果需要修改每日执行任务的时间,请修改`.github/workflows/auto_donate_douyu.yml`下的`schedule` 58 | ```yml 59 | schedule: 60 | - cron: '00 1 * * *' 61 | # cron表达式,Actions时区是国际时间,国际时间1点的时候,国内时间是早上9点。 62 | # 示例: 每天晚上22点30执行 '30 14 * * *' 63 | # 部分直播间会在周末开启双倍亲密度,可以修改时间表,实现每周末赠送 64 | # 示例: 每周天凌晨12点30分执行 '0 30 16 ? * 7 ' 65 | ``` 66 | 如果收到了 GitHub Action 的错误邮件,请检查 Cookies 是不是失效了,用户修改密码、踢除设备下线,会导致 COOKIES 失效 67 | 68 | 请各位使用 Actions 时务必遵守Github条款。不要滥用Actions服务。 69 | 70 | Please be sure to abide by the Github terms when using Actions. Do not abuse the Actions service. 71 | 72 | **查看Actions运行日志** 73 | 1. 进入Actions执行结果 74 | ![](docs/img/WatchAction.png) 75 | 2. 查看执行详情 76 | ![](docs/img/WatchAction2.png) 77 | 3. 查看执行日志 78 | ![](docs/img/WatchAction3.png) 79 | 80 | [日志示例](https://github.com/TheSlientnight/douyu_helper/runs/2078519193?check_suite_focus=true) 81 | 82 | ### 二、本地执行(不推荐) 83 | 84 | #### Windows命令行内执行 85 | 执行步骤类似于GitHub执行,但是需要将你的COOKIE放入到系统的环境变量中 86 | 1. 将代码clone到本地或直接下载压缩包 87 | 2. 添加环境变量 88 | 89 | ![](docs/img/Path1.png) 90 | ![](docs/img/Path2.png) 91 | ![](docs/img/Path3.jpg) 92 | 93 | 3. 修改config.ini,详细做法可见[修改config配置](#一、Actions方式(推荐)) 94 | 4. 进入项目根目录,使用指令 95 | ```shell 96 | python main.py 97 | ``` 98 | 99 | #### Linux命令行执行 100 | 执行步骤同Windows执行,但是环境变量需要配置到/etc/Profile中 101 | ![](docs/img/Linux1.png) 102 | ![](docs/img/Linux2.png) 103 | 添加完成后需要重新读取,使用指令 104 | ```shell 105 | source /etc/profile 106 | ``` 107 | ### 三、Docker镜像 108 | * [ ] 待更新 109 | 110 | ### 四、版本记录 111 | V1.0 工具开源 112 | 113 | V1.1 修复平均分配问题 -------------------------------------------------------------------------------- /common/dy_glows.py: -------------------------------------------------------------------------------- 1 | # encoding:utf-8 2 | import sys 3 | from jsonpath import jsonpath 4 | from time import sleep 5 | 6 | from selenium import webdriver 7 | from selenium.webdriver.chrome.options import Options 8 | from selenium.webdriver.support.wait import WebDriverWait 9 | from webdriver_manager.chrome import ChromeDriverManager 10 | 11 | from common.douyu_request import dyreq 12 | from common.logger import logger 13 | 14 | Bags = 0 15 | Own = 0 16 | 17 | cookies = {} 18 | 19 | 20 | def get_glow(): 21 | """ 22 | :return: 领取结果的基本格式 23 | """ 24 | # 需要先访问一次直播间才会获得道具 25 | logger.info("------正在获取荧光棒------") 26 | go_room() 27 | glow_url = "/japi/prop/backpack/web/v1?rid=12306" 28 | glow_res = dyreq.request("get", glow_url) 29 | global Bags 30 | logger.info("------背包检查开始------") 31 | try: 32 | # 查询获取到的荧光棒 33 | assert glow_res.status_code == 200 34 | assert glow_res.json()['msg'] == "success" 35 | # 防止没有道具导致程序报错 36 | if glow_res.json()['data']['list']: 37 | global Own 38 | try: 39 | Own = jsonpath(glow_res.json(), '$..list[?(@.id == 268)].count')[0] 40 | logger.info("当前拥有荧光棒%s个,给你喜欢的主播进行赠送吧" % Own) 41 | except TypeError as e: 42 | logger.error("背包当中没有荧光棒,但拥有其他礼物:%s" % e) 43 | Bags = 1 44 | logger.info("------背包检查结束------") 45 | else: 46 | logger.warning("当前背包中没有任何道具") 47 | logger.info("------背包检查结束------") 48 | except AssertionError: 49 | if glow_res.json()['msg'] == '请登录': 50 | logger.error("请更新COOKIE") 51 | else: 52 | logger.error("领取荧光棒时发生错误") 53 | logger.info("------背包检查结束------") 54 | return glow_res 55 | 56 | 57 | def get_own(): 58 | """ 59 | :return:返回全局变量,用于主程序内判断 60 | """ 61 | return Own 62 | 63 | 64 | def glow_donate(num=1, room_id=12306): 65 | """ 66 | :param num: 向该房间赠送荧光棒的数量 67 | :param room_id: 房间号 68 | """ 69 | donate_url = "/japi/prop/donate/mainsite/v1" 70 | DATA = "propId=268&propCount=%s&roomId=%s&bizExt={\"yzxq\":{}}" % (num, room_id) 71 | # 背包中含有道具才会进行赠送,否则会报错 72 | if Bags: 73 | donate_res = dyreq.request(method="post", path=donate_url, data=DATA) 74 | global Own 75 | try: 76 | assert donate_res.status_code == 200 77 | assert donate_res.json()['msg'] == "success" 78 | # 计算剩余荧光棒 79 | now_left = int(Own) - int(num) 80 | Own = now_left 81 | logger.info("向房间号%s赠送荧光棒%s个成功,当前剩余%s个" % (room_id, num, now_left)) 82 | except AssertionError: 83 | if donate_res.json()['msg'] == "用户没有足够的道具": 84 | logger.warning("向房间号%s赠送荧光棒失败,当前背包中荧光棒数量为:%s,而设定捐赠数量为%s" % (room_id, Own, num)) 85 | else: 86 | logger.warning(donate_res.json()['msg']) 87 | 88 | 89 | def go_room(): 90 | driver_path = ChromeDriverManager().install() # 使用webdriver manager自动安装新版本 91 | chrome_options = Options() 92 | chrome_options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在报错问题 93 | chrome_options.add_argument('--disable-gpu') # 禁用GPU硬件加速,如果软件渲染器没有就位,则GPU进程将不会启动 94 | chrome_options.add_argument('--disable-dev-shm-usage') 95 | chrome_options.add_argument('--headless') # 无界面 96 | driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options) 97 | logger.info("打开直播间") 98 | driver.get('https://www.douyu.com/8291425') 99 | dy_cookie = set_cookie(dyreq.cookie) 100 | for i in dy_cookie.keys(): 101 | mycookie = { 102 | 'domain': '.douyu.com', 103 | 'name': i, 104 | 'value': dy_cookie[i], 105 | 'expires': '', 106 | 'path': '/', 107 | 'httpOnly': False, 108 | 'HostOnly': False, 109 | 'Secure': False, 110 | } 111 | driver.add_cookie(mycookie) 112 | logger.info("刷新页面以完成登录") 113 | driver.refresh() 114 | WebDriverWait(driver, 30, 0.5).until(lambda drivers: drivers.find_element("xpath", "/html/body/section/header/div" 115 | "/div/div[3]/div[7]/div")) 116 | a = driver.find_element("xpath", "/html/body/section/header/div/div/div[3]/div[7]/div") 117 | if "UserInfo" in a.get_attribute("class"): 118 | logger.info("成功以登陆状态进入页面") 119 | logger.info("如提示背包没有荧光棒请延长等待时间") 120 | else: 121 | logger.info("没有携带cookie进入页面,请重新检查cookie") 122 | logger.info("再次刷新页面") 123 | driver.refresh() 124 | sleep(10) 125 | driver.quit() 126 | logger.info("关闭直播间") 127 | 128 | 129 | def set_cookie(cookie): 130 | for line in cookie.split(';'): 131 | # 其设置为1就会把字符串拆分成2份 132 | name, value = line.strip().split('=', 1) 133 | cookies[name] = value 134 | return cookies 135 | 136 | 137 | if __name__ == '__main__': 138 | get_glow() 139 | --------------------------------------------------------------------------------