2025年10月11日星期六

同程旅行任务脚本

1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/Bg6shY若失效,可用地址

1.购买服务器

阿里云:

服务器购买地址

https://t.aliyun.com/U/Bg6shY

若失效,可用地址

https://www.aliyun.com/daily-act/ecs/activity_selection?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.部署教程

2024年最新青龙面板跑脚本教程(一)持续更新中

3.代码如下

import asyncioimport timefrom datetime import datetimeimport osimport refrom typing import *
import httpx
# ==================== Bark 推送配置 ====================# Bark 推送地址(环境变量读取,不变)BARK_PUSH = os.getenv("BARK_PUSH")
# 你可以在这里写死参数,也可以留空CUSTOM_BARK_ICON = "Travel.png"   # 自定义图标CUSTOM_BARK_GROUP = "同程旅行"              # 自定义分组PUSH_SWITCH = "0"    #推送开关,1开启,0关闭
# 定义全局变量,保证不会报未定义错误BARK_ICON = CUSTOM_BARK_ICON or os.getenv("BARK_ICON""")BARK_GROUP = CUSTOM_BARK_GROUP or os.getenv("BARK_GROUP""")
# 覆盖环境变量,让 notify.py 能读到os.environ["BARK_ICON"] = BARK_ICONos.environ["BARK_GROUP"] = BARK_GROUPos.environ["PUSH_SWITCH"] = PUSH_SWITCH
# =====================================================
all_print_list = []push_summary_list = []  # 存储精简的推送内容
def fn_print(*args, sep=' ', end='\n', **kwargs):    global all_print_list    output = ""    # 构建输出字符串    for index, arg in enumerate(args):        if index == len(args) - 1:            output += str(arg)            continue        output += str(arg) + sep    output = output + end    all_print_list.append(output)    # 调用内置的 print 函数打印字符串    print(*args, sep=sep, end=end, **kwargs)

def get_env(env_var, separator):    if env_var in os.environ:        return re.split(separator, os.environ.get(env_var))    else:        try:            from dotenv import load_dotenv, find_dotenv            load_dotenv(find_dotenv())            if env_var in os.environ:                return re.split(separator, os.environ.get(env_var))            else:                fn_print(f"未找到{env_var}变量.")                return []        except ImportError:            fn_print(f"未找到{env_var}变量且无法加载dotenv.")            return []

try:    from notify import send as notify_sendexcept ImportError:    fn_print("无法导入青龙面板的notify模块,将使用简单的打印通知")    def notify_send(title, content):        fn_print(f"【{title}】\n{content}")

tc_cookies = get_env("tc_cookie""@")push_switch = os.environ.get('PUSH_SWITCH''1')bark_key = os.environ.get('BARK_KEY''')bark_icon = os.environ.get('BARK_ICON''')bark_group = os.environ.get('BARK_GROUP''')

class Tclx:    def __init__(self, cookie):        self.client = httpx.AsyncClient(base_url="https://app.17u.cn/welfarecenter",                                        verify=False,                                        timeout=60)        self.phone = cookie.split("#")[0]        self.apptoken = cookie.split("#")[1]        self.device = cookie.split("#")[2]        self.headers = {            'accept''application/json, text/plain, */*',            'phone': self.phone,            'channel''1',            'apptoken': self.apptoken,            'sec-fetch-site''same-site',            'accept-language''zh-CN,zh-Hans;q=0.9',            'accept-encoding''gzip, deflate, br',            'sec-fetch-mode''cors',            'origin''https://m.17u.cn',            'user-agent''Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 TcTravel/11.0.0 tctype/wk',            'referer''https://m.17u.cn/',            # 'content-length': str(len(payload_str.encode('utf-8'))),            'device': self.device,            'sec-fetch-dest''empty'        }        self.summary_info = {}  # 存储精简的推送信息
    @staticmethod    async def get_today_date():        return datetime.now().strftime('%Y-%m-%d')
    async def sign_in(self):        try:            response = await self.client.post(                url="/index/signIndex",                headers=self.headers,                json={}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - token失效了,请更新")                self.summary_info['status'] = "token失效"                return None            else:                today_sign = data['data']['todaySign']                mileage = data['data']['mileageBalance']['mileage']                fn_print(f"用户【{self.phone}】 - 今日{'已' if today_sign else '未'}签到,当前剩余里程{mileage}!")                return today_sign        except Exception as e:            fn_print(f"用户【{self.phone}】 - 签到请求异常!{e}")            fn_print(response.text)            self.summary_info['status'] = "签到异常"            return None
    async def do_sign_in(self):        today_date = await self.get_today_date()        try:            response = await self.client.post(                url="/index/sign",                headers=self.headers,                json={"type"1"day": today_date}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - 签到失败了,尝试获取任务列表")                self.summary_info['status'] = "签到失败"                return False            else:                fn_print(f"用户【{self.phone}】 - 签到成功!开始获取任务列表")                self.summary_info['status'] = "签到成功"                return True        except Exception as e:            fn_print(f"用户【{self.phone}】 - 执行签到请求异常!{e}")            fn_print(response.text)            self.summary_info['status'] = "签到异常"            return False
    async def get_task_list(self):        try:            response = await self.client.post(                url="/task/taskList?version=11.0.7",                headers=self.headers,                json={}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - 获取任务列表失败了")                return None            else:                tasks = []                for task in data['data']:                    if task['state'] == 1 and task['browserTime'] != 0:                        tasks.append(                            {                                'taskCode': task['taskCode'],                                'title': task['title'],                                'browserTime': task['browserTime']                            }                        )                return tasks        except Exception as e:            fn_print(f"用户【{self.phone}】 - 获取任务列表请求异常!{e}")            fn_print(response.text)            return None
    async def perform_tasks(self, task_code):        try:            response = await self.client.post(                url="/task/start",                headers=self.headers,                json={"taskCode": task_code}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - 执行任务【{task_code}】失败了,跳过当前任务")                return None            else:                task_id = data['data']                return task_id        except Exception as e:            fn_print(f"用户【{self.phone}】 - 执行任务【{task_code}】请求异常!{e}")            fn_print(response.text)            return None
    async def finsh_task(self, task_id):        max_retry = 3  # 最大重试次数        retry_delay = 2  # 重试间隔时间(秒)        for attempt in range(max_retry):            try:                response = await self.client.post(                    url="/task/finish",                    headers=self.headers,                    json={"id": task_id}                )                data = response.json()                if data['code'] == 2200:                    fn_print(f"用户【{self.phone}】 - 完成任务【{task_id}】成功!开始领取奖励")                    return True                if attempt < max_retry - 1:                    fn_print(f"用户【{self.phone}】 - 完成任务【{task_id}】失败了,尝试重新提交(第{attempt + 1}次重试。。)")                    await asyncio.sleep(retry_delay * (attempt + 1))                    continue                fn_print(f"用户【{self.phone}】 - 完成任务【{task_id}】最终失败,跳过当前任务")                return False            except Exception as e:                error_msg = f"用户【{self.phone}】 - 完成任务【{task_id}】请求异常!{e}"                if 'response' in locals():                    error_msg += f"\n{response.text}"                fn_print(error_msg)                if attempt == max_retry - 1:                    return False                await asyncio.sleep(retry_delay * (attempt + 1))
    async def receive_reward(self, task_id):        try:            response = await self.client.post(                url="/task/receive",                headers=self.headers,                json={"id": task_id}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - 领取签到奖励失败了, 请尝试手动领取")            else:                fn_print(f"用户【{self.phone}】 - 领取签到奖励成功!开始下一个任务")        except Exception as e:            fn_print(f"用户【{self.phone}】 - 领取签到奖励请求异常!{e}")            fn_print(response.text)
    async def get_mileage_info(self):        try:            response = await self.client.post(                url="/index/signIndex",                headers=self.headers,                json={}            )            data = response.json()            if data['code'] != 2200:                fn_print(f"用户【{self.phone}】 - 获取积分信息失败了")                return None            else:                cycle_sign_num = data['data']['cycleSighNum']                continuous_history = data['data']['continuousHistory']                mileage = data['data']['mileageBalance']['mileage']                today_mileage = data['data']['mileageBalance']['todayMileage']
                # 存储精简信息                self.summary_info['cycle_sign_num'] = cycle_sign_num                self.summary_info['continuous_history'] = continuous_history                self.summary_info['mileage'] = mileage                self.summary_info['today_mileage'] = today_mileage
                fn_print(                    f"用户【{self.phone}】 - 本月签到{cycle_sign_num}天,连续签到{continuous_history}天,今日共获取{today_mileage}里程,当前剩余里程{mileage}")                return True        except Exception as e:            fn_print(f"用户【{self.phone}】 - 获取积分信息请求异常!{e}")            fn_print(response.text)            return None
    async def run(self):        # 初始化摘要信息        self.summary_info = {            'phone': self.phone,            'status''未签到',            'cycle_sign_num'0,            'continuous_history'0,            'mileage'0,            'today_mileage'0        }
        today_sign = await self.sign_in()        if today_sign is None:            return self.summary_info        if today_sign:            fn_print(f"用户【{self.phone}】 - 今日已签到,开始获取任务列表")            self.summary_info['status'] = "签到成功"        else:            if await self.do_sign_in():                fn_print(f"用户【{self.phone}】 - 签到成功,开始获取任务列表")        tasks = await self.get_task_list()        if tasks:            for task in tasks:                task_code = task['taskCode']                title = task['title']                browser_time = task['browserTime']                fn_print(f"用户【{self.phone}】 - 开始做任务【{title}】,需要浏览{browser_time}秒")                task_id = await self.perform_tasks(task_code)                if task_id:                    await asyncio.sleep(browser_time)                    if await self.finsh_task(task_id):                        await self.receive_reward(task_id)        await self.get_mileage_info()
        # 添加到推送摘要列表        summary = f" {self.phone}\n • {self.summary_info['status']}本月签到{self.summary_info['cycle_sign_num']}天\n • 当前里程: {self.summary_info['mileage']}(+{self.summary_info['today_mileage']})"        push_summary_list.append(summary)
        return self.summary_info

async def main():    tasks = []    for cookie in tc_cookies:        tclx = Tclx(cookie)        tasks.append(tclx.run())    results = await asyncio.gather(*tasks)    return results

if __name__ == '__main__':    results = asyncio.run(main())
    # 构建精简推送内容    title = f"同程旅行签到 - {datetime.now().strftime('%m/%d')}"    push_content = ""
    for summary in push_summary_list:        push_content += f"\n\n{summary}"
    # 添加统计信息    success_count = sum(1 for r in results if r and r.get('status'in ['签到成功''今日已签到'])    push_content += f""
    push_content = push_content.strip()
    # 根据推送开关决定是否推送    if push_switch == '1':        if bark_key:            bark_send(title, push_content, bark_key, bark_icon, bark_group)        else:            notify_send(title, push_content)    else:        fn_print("推送开关已关闭,不发送推送通知")
    # 输出详细日志    fn_print("\n" + "="*50)    fn_print("详细执行日志:")    fn_print(''.join(all_print_list))

解析

该脚本为面向同程旅行领福利自动签到与做任务脚本,支持多账号并发。它会:

  1. 读取环境变量 tc_cookie(格式:phone#apptoken#device,多账号用 @ 分隔);

  2. 调用同程旅行福利中心接口判断今天是否已签到,必要时执行签到;

  3. 拉取任务列表,逐个开始任务→等待浏览时长→提交完成→领取奖励

  4. 查询当日/当月积分(里程)等信息;

  5. 汇总为简短推送(Bark 或青龙 notify),并打印详细日志。

主要方法

  • get_env(env_var, separator)
    从环境变量(或 .env)中取配置,按分隔符拆分。用于拿 tc_cookie 多账号串。

  • fn_print(*args, ...)
    对 print 的包装:既打印到控制台,也把文本追加到全局 all_print_list,用于最后"详细日志"输出。

  • Bark/通知设置(顶端常量 & notify_send

    • 读取 BARK_*PUSH_SWITCH 等,覆写到 os.environ 以兼容青龙的 notify.py

    • 尝试 from notify import send,失败则降级为简单打印。

    • ( 警示)主流程结尾调用了 bark_send(...),但脚本里没有定义该函数——要么实现它,要么统一用 notify_send

  • 类 Tclx(一个账号一实例)

    • code==2200 认为 token 有效;解析 todaySign(今日是否已签)和剩余里程;

    • 其他 code 视为 token 失效

    • 构造:创建 

    • httpx.AsyncClientbase_url=https://app.17u.cn/welfarecenter),拼请求头,把 phone/apptoken/device 注入到 header;并准备 summary_info(用于推送摘要)。

    • sign_in()
      调 /index/signIndex

    • do_sign_in()
      调 /index/sign 提交签到(type:1, day:YYYY-MM-DD),成功则标记"签到成功"。

    • get_task_list()
      调 /task/taskList?version=11.0.7,筛出需浏览的进行中任务(state==1 且 browserTime>0),返回 [{taskCode,title,browserTime}, ...]

    • perform_tasks(task_code)
      调 /task/start 启动任务,返回 task_id(后续提交/领奖用)。

    • finsh_task(task_id)(原文拼写如此)
      调 /task/finish 提交完成,内置最大 3 次重试(指数型延时 2s、4s …),成功返回 True。

    • receive_reward(task_id)
      调 /task/receive 领取任务奖励。

    • get_mileage_info()
      再调一次 /index/signIndex,拿本月签到天数连续签到今日里程当前里程,写入 summary_info

    • run()(单账号完整流程)

    1. sign_in() 判断今日是否已签;未签则 do_sign_in()

    2. 拉任务 → start → await browserTime → finish → receive

    3. 查询里程信息;

    4. 生成一条精简摘要,附加到全局 push_summary_list 供统一推送。

  • main()

    • 为每个 tc_cookie 账号 new 一个 Tclx,异步并发 run()asyncio.gather),最终返回各账号结果。

  • __main__ 区

    • 执行 asyncio.run(main())

    • 拼接推送标题与摘要内容;

    • 若 PUSH_SWITCH=='1' 则推送( 目前引用了未定义的 bark_send);

    • 打印累积的"详细执行日志"。

接口一览(相对路径)

  • POST /index/signIndex:查询签到与里程信息(用两次:前置判断 & 结尾汇总)

  • POST /index/sign:执行签到

  • POST /task/taskList?version=11.0.7:取任务列表

  • POST /task/start:开始任务(返回 id

  • POST /task/finish:完成任务(带重试)

  • POST /task/receive:领取奖励


注意

本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。


历史脚本txt文件获取>>
服务器搭建,人工服务咨询>>


没有评论:

发表评论

同程旅行任务脚本

1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/Bg6shY若失效,可用地址 1.购买服务器 阿里云: 服务器购买地址 https : //t.aliyun.com/U/Bg6shY 若失效,可用地址 https ://www.aliyun....