1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/DT4XYh若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/DT4XYh
若失效,可用地址
https://www.aliyun.com/activity/wuying/dj?source=5176.29345612&userCode=49hts92d
腾讯云:
https://curl.qcloud.com/wJpWmSfU
若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console
华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=201905
2.部署教程
3.代码如下
"""
网站:3dmgame论坛签到
cron: 0 9 */3 * * *
"""
import time
import requests
from lxml import etree
import re
import random
import os
if 'bbs3dmck' in os.environ:
bbs3dmck = re.split("@|&",os.environ.get("bbs3dmck"))
print(f'查找到{len(bbs3dmck)}个账号\n')
else:
bbs3dmck =[]
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:
if e:
print('发送通知消息失败!')
api_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': 'en',
'cache-control': 'no-cache',
'pragma': 'no-cache',
'priority': 'u=0, i',
'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'document',
'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/133.0.0.0 Safari/537.36'
}
def user_info(ck):
headers = api_headers.copy()
headers['cookie'] = ck
try:
response = requests.get('https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1', headers=headers)
if 'window.location.href' in response.text:
response = requests.get('https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1', headers=headers)
# print(response.text)
html = etree.HTML(response.text)
user_id = html.xpath('//*[@id="hd"]/div/div[1]/p/strong/a/text()')[0]
jifen = 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}] {jifen} 金元:{gold}')
Log(f'\n用户ID:[{user_id}] {jifen} 金元:{gold}')
except Exception as e:
print(e)
Log(f'\n3dmgmae论坛用户信息获取失败')
def task_view(t_id,ck):
headers = api_headers.copy()
headers['cookie'] = ck
try:
response = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={t_id}', headers=headers)
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(e)
def check_task(ck):
headers = api_headers.copy()
headers['cookie'] = ck
try:
response = requests.get('https://bbs.3dmgame.com/home.php?mod=task', headers=headers)
# 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 = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=apply&id={link_id}', headers=headers)
if 'do=draw' in response.text:
response = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={link_id}', headers=headers)
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}')
task_view(qianzhi_task,ck)
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(e)
def check_task_doing(ck):
headers = api_headers.copy()
headers['cookie'] = ck
try:
response = requests.get('https://bbs.3dmgame.com/home.php?mod=task&item=doing', headers=headers)
# 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(e)
def do_task(tk_list,ck):
headers = api_headers.copy()
headers['cookie'] = ck
print(f'获取到{len(tk_list)}个待完成任务')
for task_name,task_id in tk_list.items():
print(f'尝试完成任务:《{task_name}》')
response = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={task_id}',headers=headers)
if 'static/image/task/reward.gif' in response.text:
response = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}',headers=headers)
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 = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}', headers=headers)
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 = requests.get(f'https://bbs.3dmgame.com/{tables}', headers=headers)
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)):
reply(tid_match, fid_match, formhash, ck)
time.sleep(35)
print(f'已完成任务 《{task_name}》 回复指定文章要求')
else:
response = requests.get(f'https://bbs.3dmgame.com/{tables}', headers=headers)
result = re.findall(r'mod=redirect&tid=(\d+)&goto', response.text)
if len(result) > 0:
tiezi_id = random.choice(result)
response = requests.get(f'https://bbs.3dmgame.com/thread-{tiezi_id}-1-1.html', headers=headers)
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)):
reply(tid_match, fid_match, formhash, ck)
time.sleep(35)
print(f'已完成任务 《{task_name}》 回复指定主题要求')
response = requests.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}', headers=headers)
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(tid,fid,formhash,ck):
headers = api_headers.copy()
headers['cookie'] = ck
data = {
'file': '',
'message': '我是新玩家,搞不懂'+ random.choice(['1','2','3','4','5','6','7','8','9','0']),
'posttime': str(int(time.time())),
'formhash': formhash,
'usesig': '',
'subject': ' ',
}
response = requests.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', headers=headers, data=data)
if '回复发布成功' in response.text:
print('回帖成功,等待35秒后回复下个帖子')
else:
print('回复失败,未知原因')
print(response.text)
def main():
z = 1
if bbs3dmck:
for ck in bbs3dmck:
print(f'登录第{z}个账号')
user_info(ck)
print('-' * 50)
print('开始做论坛任务-->>>>>>>>')
check_task(ck)
task_list = check_task_doing(ck)
if task_list:
for task in task_list:
do_task(task, ck)
print('等待1分钟进行下一个账号')
time.sleep(60)
Log('-' * 30)
z = z + 1
else:
print('无bbs3dmck变量')
Log(f'\n未填入3dmgame_cookies变量')
if __name__ == '__main__':
try:
main()
except Exception as e:
print(e)
try:
send_notification_message(title='3dmgame论坛签到') # 发送通知
except Exception as e:
print(e)
解析
该脚本是3DMGame 论坛自动化脚本,核心是:用环境变量里的 Cookie 登录多个账号,自动签到 / 领取并完成任务 / 抽奖(若任务触发)/ 通知结果。它还会在需要时自动回帖以满足任务要求。
主要作用包括:
读取环境变量
bbs3dmck
(多账号用换行、@
或&
分割),逐个账号执行:查询账户积分/金元;
扫描任务大厅可接任务并尝试申请与领取奖励;
查询"进行中的任务",按页面提示自动完成(含自动回帖);
通过青龙的
notify.py
发送汇总通知。依赖:
requests
、lxml
(脚本内用from lxml import etree
),运行环境推荐青龙面板。
主要方法的作用
user_info(ck)
携带 Cookie 访问积分页面,解析并打印:用户ID、积分、金元。用于登录有效性与账户概览。task_view(t_id, ck)
查看某个任务详情页,输出该任务当前可申请/未到时间/不可申请/已完成待领取等状态。check_task(ck)
访问任务大厅,解析所有可申请的任务(提取任务名、奖励、申请链接中的任务ID),逐一尝试:直接
apply
;如果返回可draw
就立即领取奖励;若提示有前置任务,打印前置任务并调用
task_view()
做辅助判定;其他情况打印原因。
(完成后为后续"进行中任务"做铺垫)check_task_doing(ck)
打开"进行中的任务",收集任务名与任务ID列表,返回给do_task()
继续处理。do_task(tk_list, ck)
对"进行中"的每个任务执行完成逻辑:如果页面出现
reward.gif
,说明可直接领取奖励;如果出现"完成此任务所需条件"但无具体条件,直接尝试领取;
否则解析表格里的目标帖子或版块链接与需要回帖次数,进入帖子页,提取
formhash/fid/tid
,循环调用reply()
进行自动回帖(每次间隔 35 秒、最多 5 次的保护逻辑);回帖完成后再尝试领取奖励,并根据返回提示输出成功/失败原因。reply(tid, fid, formhash, ck)
向指定主题快速回帖。内容是简单模板(带随机数字避免完全重复)。成功回帖会提示并等待 35 秒再继续下一个,减小触发风控概率。send_notification_message(title)
&Log(cont)
简单的日志累积与青龙notify.py
推送封装;收尾时统一发送 "3dmgame论坛签到" 的结果通知。main()
读取多账号 Cookie,逐个账号依次:user_info → check_task → check_task_doing → do_task
;两个账号之间等待 60 秒;脚本末尾调用send_notification_message()
推送结果。
使用与提示
环境变量:
bbs3dmck='cookie1\ncookie2'
(或用@
/&
分隔)。需要模块:
pip install requests lxml
。定时(示例注释):
cron: 0 9 */3 * * *
站点可能有限流/风控:已加入延时回帖与有限次数控制,但仍建议合理频率运行,避免异常封号或禁言。
若页面结构改版(XPath 失效)或 Cookie 过期,会导致解析/访问失败;请更新 XPath 或重新抓取 Cookie。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论