This commit is contained in:
27942
2025-11-12 16:10:43 +08:00
parent 5bd2d0dbac
commit 03c7b31146
10 changed files with 871 additions and 223 deletions

Binary file not shown.

233
telegram/bot-n2.0.py Normal file
View File

@@ -0,0 +1,233 @@
from telethon import TelegramClient, events
import sqlite3
from datetime import date
import os
import asyncio
# ========== 配置区 ==========
API_ID = 2040
API_HASH = "b18441a1ff607e10a989891a5462e627"
BOT_TOKEN = "8451724418:AAGTGqCmc1JiUr88IABhMiQTHeVLcAcnT5Y"
DB_PATH = "sign.db"
SIGN_POINTS = 10
ALLOWED_GROUPS = [-1003238845008] # 只允许的群聊
PROXY = {
'proxy_type': "socks5",
'addr': "202.155.144.102",
'port': 31102,
'username': "SyNuejCtrQ",
'password': "MH8ioL7EXf"
}
# ============================
# ---------- 数据库操作 ----------
def init_db():
"""初始化数据库,创建缺失表"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# 用户积分与签到
cursor.execute('''
CREATE TABLE IF NOT EXISTS users
(
user_id
INTEGER
PRIMARY
KEY,
username
TEXT,
points
INTEGER
DEFAULT
0,
last_sign_date
TEXT
)
''')
# 发言统计
cursor.execute('''
CREATE TABLE IF NOT EXISTS daily_messages
(
user_id
INTEGER,
date
TEXT,
count
INTEGER
DEFAULT
0,
PRIMARY
KEY
(
user_id,
date
)
)
''')
# 邀请统计
cursor.execute('''
CREATE TABLE IF NOT EXISTS invites
(
inviter_id
INTEGER,
invitee_id
INTEGER
PRIMARY
KEY
)
''')
conn.commit()
conn.close()
def add_or_update_user(user_id, username):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO users (user_id, username) VALUES (?, ?)", (user_id, username))
cursor.execute("UPDATE users SET username=? WHERE user_id=?", (username, user_id))
conn.commit()
conn.close()
def can_sign(user_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT last_sign_date FROM users WHERE user_id=?", (user_id,))
row = cursor.fetchone()
today = date.today().isoformat()
conn.close()
return False if row and row[0] == today else True
def add_points(user_id, points):
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
UPDATE users
SET points = points + ?,
last_sign_date = ?
WHERE user_id = ?
""", (points, today, user_id))
conn.commit()
conn.close()
def get_points(user_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT points FROM users WHERE user_id=?", (user_id,))
points = cursor.fetchone()
conn.close()
return points[0] if points else 0
# ---------- 发言统计 ----------
def add_message(user_id):
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
INSERT INTO daily_messages (user_id, date, count)
VALUES (?, ?, 1) ON CONFLICT(user_id, date)
DO
UPDATE SET count = count + 1
""", (user_id, today))
conn.commit()
conn.close()
def get_daily_message_ranking():
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
SELECT u.username, d.count
FROM daily_messages d
JOIN users u ON d.user_id = u.user_id
WHERE d.date = ?
ORDER BY d.count DESC
""", (today,))
results = cursor.fetchall()
conn.close()
return results
# ---------- 邀请统计 ----------
def add_invite(inviter_id, invitee_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO invites (inviter_id, invitee_id) VALUES (?, ?)", (inviter_id, invitee_id))
conn.commit()
conn.close()
def get_invite_count(inviter_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM invites WHERE inviter_id=?", (inviter_id,))
count = cursor.fetchone()[0]
conn.close()
return count
# ---------- Bot 主逻辑 ----------
async def main():
# 初始化数据库,保证缺失表也会创建
init_db()
bot = TelegramClient('bot_session', API_ID, API_HASH, proxy=PROXY)
await bot.start(bot_token=BOT_TOKEN)
@bot.on(events.NewMessage)
async def message_handler(event):
# 限制群聊
if event.chat_id not in ALLOWED_GROUPS:
return
user = await event.get_sender()
user_id = user.id
username = user.username or user.first_name or "未知用户"
add_or_update_user(user_id, username)
# 只统计普通消息,不统计命令
if not event.raw_text.startswith('/'):
add_message(user_id)
# 处理签到命令
if event.raw_text in ['签到', '/sign']:
if not can_sign(user_id):
await event.reply(f"🌞 @{username},你今天已经签到过啦!")
return
add_points(user_id, SIGN_POINTS)
total = get_points(user_id)
await event.reply(f"✅ @{username} 签到成功!你获得 {SIGN_POINTS} 积分。\n当前总积分:{total}")
# 查询每日发言排行
elif event.raw_text == '/daily_rank':
ranking = get_daily_message_ranking()
if not ranking:
await event.reply("📊 今日还没有人发言哦~")
return
msg = "📊 今日发言排行:\n"
for i, (uname, count) in enumerate(ranking, 1):
msg += f"{i}. {uname}: {count}\n"
await event.reply(msg)
# 查询自己邀请人数
elif event.raw_text == '/my_invites':
count = get_invite_count(user_id)
await event.reply(f"👥 @{username},你邀请了 {count} 人。")
print("🤖 签到机器人已启动,等待群聊消息...")
await bot.run_until_disconnected()
if __name__ == "__main__":
asyncio.run(main())

299
telegram/bot-v3.0.py Normal file
View File

@@ -0,0 +1,299 @@
from nbformat.v4 import new_raw_cell
from telethon import TelegramClient, events, Button
import sqlite3
from datetime import date
import os
import asyncio
# ========== 配置区 ==========
API_ID = 2040
API_HASH = "b18441a1ff607e10a989891a5462e627"
BOT_TOKEN = "8451724418:AAGTGqCmc1JiUr88IABhMiQTHeVLcAcnT5Y"
DB_PATH = "sign.db"
SIGN_POINTS = 10
ALLOWED_GROUPS = [-1003238845008] # 只允许的群聊
PROXY = {
'proxy_type': "socks5",
'addr': "202.155.144.102",
'port': 31102,
'username': "SyNuejCtrQ",
'password': "MH8ioL7EXf"
}
# ============================
# ---------- 命令字典 ----------
COMMANDS = {
'/sign': '签到,每天签到一次,获取积分',
'签到': '签到,每天签到一次,获取积分',
'/daily_rank': '查看今日发言排行',
'/my_invites': '查看你邀请的人数',
'/help': '显示所有可用命令及说明'
}
def get_command_list_text():
msg = "🤖 机器人命令列表:\n"
for cmd, desc in COMMANDS.items():
msg += f"{cmd}{desc}\n"
return msg
# ---------- 数据库操作 ----------
def init_db():
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users
(
user_id
INTEGER
PRIMARY
KEY,
username
TEXT,
points
INTEGER
DEFAULT
0,
last_sign_date
TEXT
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS daily_messages
(
user_id
INTEGER,
date
TEXT,
count
INTEGER
DEFAULT
0,
PRIMARY
KEY
(
user_id,
date
)
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS invites
(
inviter_id
INTEGER,
invitee_id
INTEGER
PRIMARY
KEY
)
''')
conn.commit()
conn.close()
def add_or_update_user(user_id, username):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO users (user_id, username) VALUES (?, ?)", (user_id, username))
cursor.execute("UPDATE users SET username=? WHERE user_id=?", (username, user_id))
conn.commit()
conn.close()
def can_sign(user_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT last_sign_date FROM users WHERE user_id=?", (user_id,))
row = cursor.fetchone()
today = date.today().isoformat()
conn.close()
return False if row and row[0] == today else True
def add_points(user_id, points):
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
UPDATE users
SET points = points + ?,
last_sign_date = ?
WHERE user_id = ?
""", (points, today, user_id))
conn.commit()
conn.close()
def get_points(user_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT points FROM users WHERE user_id=?", (user_id,))
points = cursor.fetchone()
conn.close()
return points[0] if points else 0
# ---------- 发言统计 ----------
def add_message(user_id):
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
INSERT INTO daily_messages (user_id, date, count)
VALUES (?, ?, 1) ON CONFLICT(user_id, date)
DO
UPDATE SET count = count + 1
""", (user_id, today))
conn.commit()
conn.close()
def get_daily_message_ranking():
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
SELECT u.username, d.count
FROM daily_messages d
JOIN users u ON d.user_id = u.user_id
WHERE d.date = ?
ORDER BY d.count DESC
""", (today,))
results = cursor.fetchall()
conn.close()
return results
# ---------- 邀请统计 ----------
def add_invite(inviter_id, invitee_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO invites (inviter_id, invitee_id) VALUES (?, ?)", (inviter_id, invitee_id))
conn.commit()
conn.close()
def get_invite_count(inviter_id):
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM invites WHERE inviter_id=?", (inviter_id,))
count = cursor.fetchone()[0]
conn.close()
return count
# ---------- 统一命令处理 ----------
async def handle_command(event, cmd):
user = await event.get_sender()
user_id = user.id
username = user.username or user.first_name or "未知用户"
add_or_update_user(user_id, username)
reply_text = ""
if cmd in data["签到"]:
if not can_sign(user_id):
reply_text = f"🌞 @{username},你今天已经签到过啦!"
else:
add_points(user_id, SIGN_POINTS)
total = get_points(user_id)
reply_text = f"✅ @{username} 签到成功!你获得 {SIGN_POINTS} 积分。\n当前总积分:{total}"
elif cmd in data["发言"]:
ranking = get_daily_message_ranking()
if not ranking:
reply_text = "📊 今日还没有人发言哦~"
else:
reply_text = "📊 今日发言排行:\n"
for i, (uname, count) in enumerate(ranking, 1):
reply_text += f"{i}. {uname}: {count}\n"
elif cmd in data["邀请"]:
count = get_invite_count(user_id)
reply_text = f"👥 @{username},你邀请了 {count} 人。"
elif cmd == '/help':
reply_text = get_command_list_text()
else:
reply_text = f"⚠️ 未知命令:{cmd}"
# 每次命令回复附带命令列表
reply_text += "\n\n" + get_command_list_text()
await event.reply(reply_text)
data = {
"签到": ['/sign', '签到', "haha"],
"发言": ["/daily_rank"],
"邀请": ['/my_invites'],
}
# ---------- Bot 主逻辑 ----------
async def main():
init_db()
bot = TelegramClient('bot_session', API_ID, API_HASH, proxy=PROXY)
await bot.start(bot_token=BOT_TOKEN)
# 新用户加入欢迎
@bot.on(events.ChatAction)
async def welcome_new_user(event):
if event.user_added or event.user_joined:
for user in event.users:
username = user.username or user.first_name or "新成员"
await event.reply(f"欢迎 @{username} 加入群聊!\n{get_command_list_text()}")
# 普通消息处理
@bot.on(events.NewMessage)
async def message_handler(event):
if event.chat_id not in ALLOWED_GROUPS:
return
text = event.raw_text.strip()
user = await event.get_sender()
user_id = user.id
# 普通消息计入发言
for i in data:
if text in data[i]:
# 去掉 @botusername 后缀
cmd = text.split('@')[0]
await handle_command(event, cmd)
break
else:
add_message(user_id)
# if not text.startswith('/'):
# add_message(user_id)
# else:
# # 去掉 @botusername 后缀
# cmd = text.split('@')[0]
# await handle_command(event, cmd)
# 按钮命令发送
@bot.on(events.NewMessage(pattern='/commands'))
async def send_buttons(event):
buttons = [
[Button.inline("签到", b"/sign"), Button.inline("今日发言排行", b"/daily_rank")],
[Button.inline("我的邀请", b"/my_invites"), Button.inline("帮助", b"/help")]
]
await event.reply("请选择命令:", buttons=buttons)
# 按钮点击处理
@bot.on(events.CallbackQuery)
async def callback_handler(event):
cmd = event.data.decode() # 获取按钮绑定的命令
print(cmd)
await handle_command(event, cmd)
await event.answer() # 防止按钮 loading 一直转
print("🤖 机器人已启动,等待群聊消息...")
await bot.run_until_disconnected()
if __name__ == "__main__":
asyncio.run(main())

Binary file not shown.

135
telegram/bot_test.py Normal file
View File

@@ -0,0 +1,135 @@
from telethon import TelegramClient, events
import sqlite3
from datetime import date
import os
# ========== 配置区 ==========
API_ID = 2040 # ← 替换为你的 Telegram API ID
API_HASH = "b18441a1ff607e10a989891a5462e627" # ← 替换为你的 API HASH
BOT_TOKEN = "8451724418:AAGTGqCmc1JiUr88IABhMiQTHeVLcAcnT5Y" # ← 替换为你的 Bot Token
DB_PATH = "sign.db" # 数据库文件
SIGN_POINTS = 10 # 每次签到获得的积分
# ============================
# ---------- 数据库操作 ----------
def init_db():
"""初始化数据库"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT,
points INTEGER DEFAULT 0,
last_sign_date TEXT
)
''')
conn.commit()
conn.close()
def get_user(user_id):
"""获取用户信息"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
user = cursor.fetchone()
conn.close()
return user
def add_or_update_user(user_id, username):
"""如果用户不存在则新增"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO users (user_id, username) VALUES (?, ?)", (user_id, username))
conn.commit()
conn.close()
def can_sign(user_id):
"""判断今天是否可以签到"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT last_sign_date FROM users WHERE user_id=?", (user_id,))
row = cursor.fetchone()
today = date.today().isoformat()
conn.close()
if row and row[0] == today:
return False
return True
def add_points(user_id, points):
"""给用户加积分并更新签到日期"""
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
UPDATE users
SET points = points + ?, last_sign_date = ?
WHERE user_id = ?
""", (points, today, user_id))
conn.commit()
conn.close()
def get_points(user_id):
"""获取用户当前积分"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT points FROM users WHERE user_id=?", (user_id,))
points = cursor.fetchone()
conn.close()
return points[0] if points else 0
# ---------- 机器人主逻辑 ----------
def main():
# 初始化数据库
if not os.path.exists(DB_PATH):
init_db()
proxy = {
'proxy_type': "socks5", # 或 'socks4',具体看你的代理类型
'addr': "202.155.144.102", # 代理服务器地址
'port': 31102, # 代理服务器端口
'username': "SyNuejCtrQ", # 如果有用户名,填写
'password': "MH8ioL7EXf" # 如果有密码,填写
}
# proxy = ("socks5", "202.155.144.102", 31102, True, "SyNuejCtrQ", "MH8ioL7EXf")
bot = TelegramClient(
'haha',
api_id=API_ID,
api_hash=API_HASH,
proxy=proxy
).start(bot_token=BOT_TOKEN)
@bot.on(events.NewMessage(pattern='^(签到|/sign)$'))
async def sign_handler(event):
user = await event.get_sender()
user_id = user.id
username = user.username or user.first_name or "未知用户"
# 注册用户
add_or_update_user(user_id, username)
# 检查是否已签到
if not can_sign(user_id):
await event.reply(f"🌞 {username},你今天已经签到过啦!")
return
# 签到成功,加积分
add_points(user_id, SIGN_POINTS)
total = get_points(user_id)
await event.reply(f"✅ 签到成功!你获得 {SIGN_POINTS} 积分。\n当前总积分:{total}")
print("🤖 签到机器人已启动,等待消息中...")
bot.run_until_disconnected()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,161 @@
from telethon import TelegramClient, events
from telethon.tl.functions.messages import ImportChatInviteRequest
import sqlite3
from datetime import date
import os
import asyncio
# ========== 配置区 ==========
API_ID = 2040
API_HASH = "b18441a1ff607e10a989891a5462e627"
BOT_TOKEN = "8451724418:AAGTGqCmc1JiUr88IABhMiQTHeVLcAcnT5Y"
DB_PATH = "sign.db"
SIGN_POINTS = 10
INVITE_LINK = "ergggreef" # t.me/后面的群链接部分
# 代理配置,如果需要
PROXY = {
'proxy_type': "socks5",
'addr': "202.155.144.102",
'port': 31102,
'username': "SyNuejCtrQ",
'password': "MH8ioL7EXf"
}
# ============================
# ---------- 数据库操作 ----------
def init_db():
"""初始化数据库"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
username TEXT,
points INTEGER DEFAULT 0,
last_sign_date TEXT
)
''')
conn.commit()
conn.close()
def get_user(user_id):
"""获取用户信息"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
user = cursor.fetchone()
conn.close()
return user
def add_or_update_user(user_id, username):
"""如果用户不存在则新增"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT OR IGNORE INTO users (user_id, username) VALUES (?, ?)", (user_id, username))
conn.commit()
conn.close()
def can_sign(user_id):
"""判断今天是否可以签到"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT last_sign_date FROM users WHERE user_id=?", (user_id,))
row = cursor.fetchone()
today = date.today().isoformat()
conn.close()
if row and row[0] == today:
return False
return True
def add_points(user_id, points):
"""给用户加积分并更新签到日期"""
today = date.today().isoformat()
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("""
UPDATE users
SET points = points + ?, last_sign_date = ?
WHERE user_id = ?
""", (points, today, user_id))
conn.commit()
conn.close()
def get_points(user_id):
"""获取用户当前积分"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT points FROM users WHERE user_id=?", (user_id,))
points = cursor.fetchone()
conn.close()
return points[0] if points else 0
# ---------- 机器人主逻辑 ----------
async def main():
# 初始化数据库
if not os.path.exists(DB_PATH):
init_db()
bot = TelegramClient(
'bot_session',
api_id=API_ID,
api_hash=API_HASH,
proxy=PROXY
)
await bot.start(bot_token=BOT_TOKEN) # 注意这里是 await
# # 尝试加入群聊并获取 chat_id
# try:
# result = await bot(ImportChatInviteRequest(INVITE_LINK))
# chat_id = result.chats[0].id
# print(f"✅ 已加入群聊: {result.chats[0].title}, chat_id={chat_id}")
# except Exception as e:
# # 如果已经加入,遍历对话获取 chat_id
# async for dialog in bot.iter_dialogs():
# if dialog.name and INVITE_LINK in dialog.name: # 简单匹配群名
# chat_id = dialog.id
# print(f"✅ 已存在群聊: {dialog.name}, chat_id={chat_id}")
# break
# else:
# print("❌ 无法加入或找到群聊,请检查邀请链接")
# return
ALLOWED_GROUPS = [-1003238845008]
@bot.on(events.NewMessage(pattern='^(签到|/sign)$'))
async def sign_handler(event):
# 检查是否在允许的群聊中
if event.chat_id not in ALLOWED_GROUPS:
return # 非指定群聊,忽略
user = await event.get_sender()
user_id = user.id
username = user.username or user.first_name or "未知用户"
# 注册用户
add_or_update_user(user_id, username)
# 检查是否已签到
if not can_sign(user_id):
await event.reply(f"🌞 @{username},你今天已经签到过啦!")
return
# 签到成功,加积分
add_points(user_id, SIGN_POINTS)
total = get_points(user_id)
await event.reply(f"✅ @{username} 签到成功!你获得 {SIGN_POINTS} 积分。\n当前总积分:{total}")
print("🤖 签到机器人已启动,等待群聊消息...")
await bot.run_until_disconnected()
if __name__ == "__main__":
asyncio.run(main())

BIN
telegram/haha.session Normal file

Binary file not shown.

BIN
telegram/sign.db Normal file

Binary file not shown.

32
telegram/test.py Normal file
View File

@@ -0,0 +1,32 @@
from telethon import TelegramClient, sync
from telethon.sessions import StringSession
# ========== 配置区 ==========
API_ID = 2040 # 替换成你的 API ID
API_HASH = "b18441a1ff607e10a989891a5462e627" # 替换成你的 API HASH
SESSION_FILE = "2349073562091" # 登录会话保存文件
# ============================
PROXY = {
'proxy_type': "socks5",
'addr': "202.155.144.102",
'port': 31102,
'username': "SyNuejCtrQ",
'password': "MH8ioL7EXf"
}
client = TelegramClient(SESSION_FILE, API_ID, API_HASH,proxy=PROXY)
async def main():
await client.start() # 登录,如果第一次会要求输入手机号和验证码
print("✅ 登录成功!正在获取群聊列表...\n")
async for dialog in client.iter_dialogs():
if dialog.is_group or dialog.is_channel:
print(f"群聊名称: {dialog.name}, chat_id: {dialog.id}")
print("\n✅ 完成!请复制你想要的群聊 chat_id 到 Bot 的 ALLOWED_GROUPS")
if __name__ == "__main__":
import asyncio
asyncio.run(main())

View File

@@ -1,227 +1,15 @@
import datetime
import time
import hmac
import hashlib
import base64
import json
import re
import requests
from bs4 import BeautifulSoup
from loguru import logger
from tqdm import tqdm
from DrissionPage import ChromiumPage, ChromiumOptions
url = "http://8.137.99.82:9005/api/send_click?token=fegergauiernguie&phone=8613661496481"
# ==============================================================
# ✅ 通用工具函数
# ==============================================================
res = requests.post(
url=url,
json={
"phone": "8613661496481",
"bot_name": "ergggreef",
"datas": [
{"send_message": ["grgegg"], "click_button": [""], },
]
def is_bullish(candle):
return float(candle['close']) > float(candle['open'])
def is_bearish(candle):
return float(candle['close']) < float(candle['open'])
def current_time():
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# ==============================================================
# ✅ 钉钉通知模块
# ==============================================================
class DingTalkNotifier:
def __init__(self, webhook_url: str, secret: str):
self.webhook_url = webhook_url
self.secret = secret
def _get_signature(self, timestamp):
string_to_sign = f'{timestamp}\n{self.secret}'
hmac_code = hmac.new(self.secret.encode('utf-8'), string_to_sign.encode('utf-8'),
digestmod=hashlib.sha256).digest()
return base64.b64encode(hmac_code).decode('utf-8')
def send(self, content: str):
timestamp = str(round(time.time() * 1000))
sign = self._get_signature(timestamp)
url = f"{self.webhook_url}&timestamp={timestamp}&sign={sign}"
msg = {"msgtype": "text", "text": {"content": content}}
try:
res = requests.post(url, json=msg, timeout=10)
res.raise_for_status()
logger.success(f"[钉钉通知成功] {content}")
except Exception as e:
logger.error(f"[钉钉通知失败] {e}")
# ==============================================================
# ✅ 浏览器与页面交互模块
# ==============================================================
class WeexBrowser:
def __init__(self, tge_id: int, api_key: str, base_url="http://127.0.0.1:50326"):
self.tge_id = tge_id
self.api_key = api_key
self.base_url = base_url
self.page = None
self.port = None
def start_browser(self):
try:
res = requests.post(
f"{self.base_url}/api/browser/start",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"envId": self.tge_id}
).json()
self.port = res["data"]["port"]
logger.info(f"浏览器已启动,端口:{self.port}")
return True
except Exception as e:
logger.error(f"启动浏览器失败: {e}")
return False
def connect(self, url):
try:
opts = ChromiumOptions()
opts.set_local_port(self.port)
self.page = ChromiumPage(addr_or_opts=opts)
self.page.set.window.max()
self.page.get(url=url)
logger.success("浏览器接管成功!")
return True
except Exception as e:
logger.error(f"浏览器接管失败: {e}")
return False
def click(self, xpath):
try:
ele = self.page.ele(f'x://{xpath}')
if ele:
ele.scroll.to_see(center=True)
ele.click()
return True
except Exception as e:
logger.error(f"点击元素失败:{xpath},原因:{e}")
return False
def contains_text(self, text):
soup = BeautifulSoup(self.page.html, "html.parser")
cleaned_target = re.sub(r'\s', '', text)
for tag in soup.find_all():
if cleaned_target in re.sub(r'\s', '', tag.get_text()):
return True
return False
# ==============================================================
# ✅ K线策略模块
# ==============================================================
class KlineStrategy:
@staticmethod
def engulf_signal(prev, curr):
"""包住形态信号"""
p_open, p_close = float(prev['open']), float(prev['close'])
c_open, c_close = float(curr['open']), float(curr['close'])
if is_bullish(curr) and is_bearish(prev) and c_open <= p_close and c_close >= p_open:
return "long"
if is_bearish(curr) and is_bullish(prev) and c_open >= p_close and c_close <= p_open:
return "short"
return None
# ==============================================================
# ✅ 主交易逻辑模块
# ==============================================================
class WeexTrader:
def __init__(self, tge_id):
self.browser = WeexBrowser(tge_id=tge_id, api_key="asp_174003986c9b0799677c5b2c1adb76e402735d753bc91a91")
self.notifier = DingTalkNotifier(
webhook_url="https://oapi.dingtalk.com/robot/send?access_token=e2fafb3f46866d50fe52cbb29650ba9ef1cbc97915dde238192f04c906fe4125",
secret="SEC5f320e72d7a4eaca540c66c3d09edff2f74936517390dee99ece6dd1b3611998"
)
self.direction = 0 # -1:空 0:无 1:多
self.page = None
def run(self):
if not self.browser.start_browser() or not self.browser.connect(
"https://www.weeaxs.site/zh-CN/futures/demo-trading/ETH-SUSDT"):
return
page = self.browser.page
page.listen.start("public/quote/v1/getKlineV2")
pbar = tqdm(total=30, desc="监控中", ncols=80)
while True:
try:
tm = time.localtime().tm_min
pbar.n = tm % 30
pbar.refresh()
# 每30分钟判断信号
if tm in [0, 1, 2, 30, 31, 32]:
self._check_position(page)
klines = self._get_kline_data(page)
if not klines:
continue
prev, curr = klines[-2:]
signal = KlineStrategy.engulf_signal(prev, curr)
if signal:
self._handle_signal(signal)
else:
logger.info("无信号触发")
time.sleep(10)
except Exception as e:
logger.exception(f"主循环异常: {e}")
time.sleep(15)
def _check_position(self, page):
if self.browser.contains_text("ETH/SUSDT多"):
self.direction = 1
elif self.browser.contains_text("ETH/SUSDT空"):
self.direction = -1
else:
self.direction = 0
def _get_kline_data(self, page):
try:
page.refresh()
res = page.listen.wait(timeout=10)
if not res: return None
return sorted([
{'id': int(d[4]), 'open': d[3], 'high': d[1], 'low': d[2], 'close': d[0]}
for d in res.response.body['data']["dataList"]
], key=lambda x: x['id'])
except Exception as e:
logger.error(f"获取K线失败{e}")
return None
def _handle_signal(self, signal):
if signal == "long" and self.direction <= 0:
self._trade("买入开多", 1)
elif signal == "short" and self.direction >= 0:
self._trade("卖出开空", -1)
def _trade(self, action_text, new_dir):
logger.success(f"{current_time()}:执行 {action_text}")
self.notifier.send(f"{current_time()} 执行 {action_text}")
self.browser.click(f'*[contains(text(), "闪电平仓")]')
time.sleep(2)
self.browser.click(f'*[contains(text(), "{action_text}")]')
self.direction = new_dir
# ==============================================================
# ✅ 启动程序
# ==============================================================
if __name__ == '__main__':
trader = WeexTrader(tge_id=146473)
trader.run()
}
)