# Source: https://github.com/lksky8/sign-ql/blob/main/3dmgame.py # Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/3dmgame.py # Repo: lksky8/sign-ql # Path: 3dmgame.py # UploadedAt: 2026-03-27T20:17:30Z # SHA256: 2262c9f7c2d40c8ef9822325fadd2e8ed3c43ba0f609c072a27c49b02edc2eaa # Category: web版/账密 # Evidence: web/H5关键词 + username/password/login """ 作者:https://github.com/lksky8/sign-ql/ 日期:2026-3-28 网站:3dmgame论坛签到 功能:签到、抽奖,金币可换现金买游戏 食用方法:登录论坛后,浏览器F12打开抓包,https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1抓这个url请求头的cookie包 变量:bbs3dmck='cookie' 多个账号用换行分割 定时一天三次 青龙需要安装lxml模块 cron: 0 9 */8 * * * """ import time import requests from lxml import etree import re import random import os send_msg = '' one_msg = '' def Log(cont=''): global send_msg, one_msg if cont: one_msg += f'{cont}\n' send_msg += f'{cont}\n' # 发送通知消息 def send_notification_message(title): try: from notify import send print("加载通知服务成功!") send(title, send_msg) except Exception as e: print('发送通知消息失败!' + str(e)) class ThreeDMGame: def __init__(self, cookies): headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': 'https://bbs.3dmgame.com', 'Pragma': 'no-cache', 'Sec-Fetch-Dest': 'iframe', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-User': '?1', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36', 'sec-ch-ua': '"Chromium";v="146", "Not-A.Brand";v="24", "Google Chrome";v="146"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'Cookie': cookies, } self.session = requests.Session() self.session.headers.update(headers) def user_info(self): try: response = self.session.get('https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1') html = etree.HTML(response.text) user_id = html.xpath('//*[@id="hd"]/div/div[1]/p/strong/a/text()')[0] points = html.xpath('//*[@id="extcreditmenu"]/text()')[0] gold = html.xpath('//*[@id="ct"]/div[1]/div/ul[2]/li[1]/text()')[0] print(f'用户ID:[{user_id}] {points} 金元:{gold}') Log(f'\n用户ID:[{user_id}] {points} 金元:{gold}') except Exception as e: print('3dmgame论坛用户信息获取失败:', e) Log(f'\n3dmgame论坛用户信息获取失败') def task_view(self, t_id): try: response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={t_id}') html = etree.HTML(response.text) task_name = html.xpath('//h1[contains(@class, "xs2") and contains(@class, "ptm") and contains(@class, "pbm")]/text()')[0].strip() if 'do=apply' in response.text: print(f'任务:《{task_name}》 可申请') elif '后可以再次申请' in response.text: print(f'任务:《{task_name}》 未到申请时间') elif '您所在的用户组无法申请此任务' in response.text: print(f'任务:《{task_name}》 您所在的用户组无法申请此任务') elif 'static/image/task/reward.gif' in response.text: print(f'任务:《{task_name}》 任务已完成,待领取奖励') else: print(f'任务:《{task_name}》 未知状态') except Exception as e: print(f'查看任务信息失败:{t_id} {e}') def check_task(self): try: response = self.session.get('https://bbs.3dmgame.com/home.php?mod=task') # print(response.text) html = etree.HTML(response.text) task_rows = html.xpath('//div[@class="ptm"]//table//tr') # for row in task_rows: # # 提取任务名称 # task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else "" # # # 提取任务描述 # description = row.xpath('.//td[2]/p/text()')[0] if row.xpath('.//td[2]/p/text()') else "" # # # 提取任务奖励 # reward = row.xpath('.//td[3]/text()')[0].strip() if row.xpath('.//td[3]/text()') else "" # # # 提取任务状态(可申请/不可申请) # is_available = len(row.xpath('.//td[4]//img[@alt="apply"]')) > 0 # # apply_link = row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href')[0] if row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href') else "无可用申请链接" # # print(f"任务名称: {task_name}") # print(f"申请链接: {apply_link}") # print(f"描述: {description}") # print(f"奖励: {reward}") # print(f"是否可申请: {'是' if is_available else '否'}") # print("---") task_list = {} for row in task_rows: task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else "" description = row.xpath('.//td[2]/p/text()')[0] if row.xpath('.//td[2]/p/text()') else "" reward = row.xpath('.//td[3]/text()')[0].strip() if row.xpath('.//td[3]/text()') else "" apply_links = row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href') # 只处理有可用申请链接的任务 if apply_links: apply_link = apply_links[0] print(f"任务名称: {task_name}") print(f"描述: {description}") print(f"奖励: {reward}") # print(f"任务id: {apply_link.split('id=')[-1]}") print("-" * 50) task_list.update({task_name: apply_link.split('id=')[-1]}) if len(task_list) > 0: print(f'获取到{len(task_list)}个可接任务') for name, link_id in task_list.items(): print('*' * 30) print(f'尝试领取任务:{name}') response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=apply&id={link_id}') if 'do=draw' in response.text: response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={link_id}') if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text: print(f'任务:{name} 直接完成') else: print(f'任务:{name} 失败' + response.text) elif '申请此任务需要先完成另一个任务' in response.text: html_message = etree.HTML(response.text) qianzhi_task = html_message.xpath('//div[@id="messagetext"]//p[@class="alert_btnleft"]/a/@href')[0].split("id=")[-1] print(f'任务:{name} 领取失败 | 原因是:前置任务未完成,跳转前置任务id:{qianzhi_task}') self.task_view(qianzhi_task) elif '任务申请成功' in response.text: print(f'任务:{name} 领取成功') elif '不是进行中的任务' in response.text: print(f'任务:{name} 无法直接完成') else: print(f'任务:{name} 领取失败') print(response.text) time.sleep(1) print('-' * 50) else: print('没有可接任务') # Log(f'\n没有可接任务') print('-' * 50) except Exception as e: print(f'检查任务信息失败:{e}') def check_task_doing(self): try: response = self.session.get('https://bbs.3dmgame.com/home.php?mod=task&item=doing') # print(response.text) html = etree.HTML(response.text) task_rows = html.xpath('//div[@class="ptm"]//table//tr') task_list = [] for row in task_rows: # 提取任务名称 task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else "" # 提取任务ID task_id = row.xpath('.//td[2]//h3/a/@href')[0].split('id=')[-1] if row.xpath('.//td[2]//h3/a/@href') else "" # 提取do=view链接(任务详情链接) # view_link = row.xpath('.//td[2]//h3/a[contains(@href, "do=view")]/@href')[0] if row.xpath('.//td[2]//h3/a[contains(@href, "do=view")]/@href') else "" # 提取领取链接(do=draw类型) # draw_links = row.xpath('.//td[4]/p/a[contains(@href, "do=draw")]/@href')[0] if row.xpath('.//td[4]/p/a/@href') else "" print(f"进行中的任务: 《{task_name}》") task_list.append({task_name: task_id}) print('-' * 30) if len(task_list) > 0: return task_list else: print('没有进行中的任务') # Log(f'\n没有进行中的任务') return [] except Exception as e: print(f'检查任务进行中失败:{e}') def do_task(self, tk_list): print(f'获取到{len(tk_list)}个待完成任务') for task_name, task_id in tk_list.items(): print(f'尝试完成任务:《{task_name}》') response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={task_id}') if 'static/image/task/reward.gif' in response.text: response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}') if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text: print(f'任务:《{task_name}》 完成') else: print(f'任务:《{task_name}》 失败') print(response.text) elif '完成此任务所需条件' in response.text: print(f'任务:《{task_name}》 无完成条件') response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}') if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text: print(f'任务:《{task_name}》 完成') else: print(f'任务:《{task_name}》 失败') print(response.text) else: print(f'任务:《{task_name}》 有完成条件') tree = etree.HTML(response.text) tables = tree.xpath("//table[@class='tfm']//td[@class='bbda']/a/@href")[0] # print(tables) reply_td = tree.xpath("//table[@class='tfm']//td[@class='bbda'][contains(., '次')]/text()[normalize-space()]")[1] reply_td = reply_td.replace(' ', '') # print(reply_td) reply_count = re.search(r'(\d+)次', reply_td).group(1) if re.search(r'(\d+)次', reply_td) else "未知" if 'thread' in tables: response = self.session.get(f'https://bbs.3dmgame.com/{tables}') formhash = re.search(r'name="formhash" value="(\w+)"', response.text).group(1) fid_match = re.search(r"fid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1) tid_match = re.search(r"tid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1) print('回复次数:' + reply_count) if int(reply_count) > 5: print('回复次数大于5次,任务跳过') else: for _ in range(int(reply_count)): for i in range(3): result = self.reply(tid_match, fid_match, formhash) if result: break time.sleep(10) time.sleep(35) print(f'已完成任务 《{task_name}》 回复指定文章要求') else: response = self.session.get(f'https://bbs.3dmgame.com/{tables}') result = re.findall(r'mod=redirect&tid=(\d+)&goto', response.text) if len(result) > 0: response = self.session.get(f'https://bbs.3dmgame.com/thread-{random.choice(result)}-1-1.html') formhash = re.search(r'name="formhash" value="(\w+)"', response.text).group(1) fid_match = re.search(r"fid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1) tid_match = re.search(r"tid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1) for _ in range(int(reply_count)): for i in range(3): result = self.reply(tid_match, fid_match, formhash) if result: break time.sleep(10) time.sleep(35) print(f'已完成任务 《{task_name}》 回复指定主题要求') response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}') if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text: print(f'任务:《{task_name}》 完成') elif '您已完成该任务的' in response.text: html = etree.HTML(response.text) b = html.xpath('//div[@id="messagetext"]/p/text()')[0] print(f'任务:《{task_name}》 失败:' + b.strip()) elif '您还没有开始执行任务,赶快哦' in response.text: print(f'任务:《{task_name}》 失败:因任务特殊跳过该任务') elif '您还没有开始执行任务' in response.text: print(f'任务:《{task_name}》 失败:因任务特殊跳过该任务') else: print(f'任务:《{task_name}》 失败') print(response.text) time.sleep(3) def reply(self, tid, fid, formhash): response = requests.get("https://www.mxnzp.com/api/jokes/list?page=1&app_id=vqohyieoq7qklmgp&app_secret=FCc9Uf0h1c0LNkqeLRolebStTGfds3Fx") response_json = response.json() if response_json['code'] == 1 : message = response_json['data']['list'][0]['content'] else: message = '我是新玩家,搞不懂' + random.choice(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']) data = { 'file': '', 'message': message, 'posttime': str(int(time.time())), 'formhash': formhash, 'usesig': '1', 'subject': ' ', } response = self.session.post(f'https://bbs.3dmgame.com/forum.php?mod=post&action=reply&fid={fid}&tid={tid}&extra=page%3D1&replysubmit=yes&infloat=yes&handlekey=fastpost&inajax=1', data=data) if '回复发布成功' in response.text: print('回帖成功,等待35秒后回复下个帖子') return True else: print('回复失败,未知原因') return False def main(self): self.user_info() print('-' * 50) print('开始做论坛任务-->>>>>>>>') self.check_task() task_list = self.check_task_doing() if task_list: for task in task_list: self.do_task(task) print('等待30秒进行下一个账号') self.session.close() print('*' * 50) time.sleep(30) Log('-' * 30) if __name__ == '__main__': try: if 'bbs3dmck' in os.environ: bbs3dmck = re.split("@|&", os.environ.get("bbs3dmck")) print(f'查找到{len(bbs3dmck)}个账号\n') else: bbs3dmck = None print('无bbs3dmck变量') Log(f'\n未填入bbs3dmck变量') if bbs3dmck: z = 1 for ck in bbs3dmck: print(f'登录第{z}个账号') threeDM = ThreeDMGame(ck) threeDM.main() z+= 1 except Exception as e: print(e) try: send_notification_message(title='3dmgame论坛签到') # 发送通知 except Exception as e: print(e)