矿机租赁系统矿池网站获取矿工算力代码
This commit is contained in:
92
v1/2miners_collector.py
Normal file
92
v1/2miners_collector.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import redis
|
||||||
|
import requests
|
||||||
|
import pymysql
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# ---------------- Redis 配置 ----------------
|
||||||
|
r = redis.Redis(host='127.0.0.1', port=6379, db=7, decode_responses=True)
|
||||||
|
|
||||||
|
# ---------------- MySQL 配置 ----------------
|
||||||
|
conn = pymysql.connect(
|
||||||
|
host='127.0.0.1',
|
||||||
|
user='root',
|
||||||
|
password='123456',
|
||||||
|
database='pool',
|
||||||
|
port=25600,
|
||||||
|
charset='utf8mb4'
|
||||||
|
)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# ---------------- API 配置 ----------------
|
||||||
|
API_URLS = {
|
||||||
|
"NEXA": "https://nexa.2miners.com/api/accounts/{wallet}",
|
||||||
|
"XNA": "https://xna.2miners.com/api/accounts/{wallet}",
|
||||||
|
"CLORE": "https://clore.2miners.com/api/accounts/{wallet}",
|
||||||
|
"RVN": "https://rvn.2miners.com/api/accounts/{wallet}",
|
||||||
|
"ERG": "https://erg.2miners.com/api/accounts/{wallet}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------- 工具函数 ----------------
|
||||||
|
def to_mhs(value):
|
||||||
|
"""算力转换为 MH/s"""
|
||||||
|
return float(value) / 1_000_000 if value else 0.0
|
||||||
|
|
||||||
|
def get_half_hour_time(now):
|
||||||
|
"""取最近半点整时间"""
|
||||||
|
minute = 0 if now.minute < 30 else 30
|
||||||
|
return now.replace(minute=minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
# ---------------- 主逻辑(单次执行) ----------------
|
||||||
|
def run_once():
|
||||||
|
keys = r.keys("*")
|
||||||
|
half_time = get_half_hour_time(datetime.now())
|
||||||
|
|
||||||
|
for key in keys:
|
||||||
|
try:
|
||||||
|
parts = key.split(":")
|
||||||
|
if len(parts) != 4:
|
||||||
|
continue
|
||||||
|
|
||||||
|
pool_name, wallet, coin, algo = parts
|
||||||
|
if pool_name.lower() != "2miners":
|
||||||
|
continue # 只处理2miners
|
||||||
|
|
||||||
|
coin_upper = coin.upper()
|
||||||
|
if coin_upper not in API_URLS:
|
||||||
|
print(f"[跳过] 不支持币种 {coin_upper}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# NEXA 需要补全前缀
|
||||||
|
wallet_api = f"nexa:{wallet}" if coin_upper=="NEXA" and not wallet.startswith("nexa:") else wallet
|
||||||
|
|
||||||
|
url = API_URLS[coin_upper].format(wallet=wallet_api)
|
||||||
|
resp = requests.get(url, timeout=10)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
workers = data.get("workers", {})
|
||||||
|
if not workers:
|
||||||
|
print(f"[无矿机] {coin_upper} {wallet}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for miner, info in workers.items():
|
||||||
|
hashrate = to_mhs(info.get("hr"))
|
||||||
|
print(f"写入 → {coin_upper} | {miner} | {hashrate:.2f} MH/s")
|
||||||
|
|
||||||
|
sql = """
|
||||||
|
INSERT INTO `2miners`
|
||||||
|
(datetime,pool_name,wallet,miner,hashrate,coin,algorithm)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
"""
|
||||||
|
cursor.execute(sql,(half_time,pool_name,wallet,miner,hashrate,coin_upper,algo))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[错误] {key} ->", e)
|
||||||
|
|
||||||
|
# ---------------- 执行一次后退出 ----------------
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_once()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print("✔ 本次采集结束")
|
||||||
103
v1/herominers_collector.py
Normal file
103
v1/herominers_collector.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import redis
|
||||||
|
import requests
|
||||||
|
import pymysql
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# ---------------- Redis 配置 ----------------
|
||||||
|
REDIS_HOST = "127.0.0.1"
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
REDIS_DB = 7
|
||||||
|
|
||||||
|
# ---------------- MySQL 配置 ----------------
|
||||||
|
MYSQL_HOST = "127.0.0.1"
|
||||||
|
MYSQL_PORT = 25600
|
||||||
|
MYSQL_USER = "root"
|
||||||
|
MYSQL_PASS = "123456"
|
||||||
|
MYSQL_DB = "pool"
|
||||||
|
TABLE_NAME = "`herominers`"
|
||||||
|
|
||||||
|
# ---------------- 连接 Redis ----------------
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, decode_responses=True)
|
||||||
|
|
||||||
|
# ---------------- 连接 MySQL ----------------
|
||||||
|
conn = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER,
|
||||||
|
password=MYSQL_PASS, database=MYSQL_DB, charset='utf8mb4')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# ---------------- 币种 -> 域名映射 ----------------
|
||||||
|
domain_map = {
|
||||||
|
"CFX": "conflux.herominers.com",
|
||||||
|
"IRON": "ironfish.herominers.com",
|
||||||
|
"KLS": "karlsen.herominers.com",
|
||||||
|
"RVN": "ravencoin.herominers.com",
|
||||||
|
"ERG": "ergo.herominers.com",
|
||||||
|
"XEL": "xelis.herominers.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------- 从 Redis 获取矿池配置 ----------------
|
||||||
|
# 格式: herominers:wallet:COIN:ALGORITHM
|
||||||
|
keys = r.keys("herominers:*")
|
||||||
|
|
||||||
|
def round_half_hour(dt=None):
|
||||||
|
"""返回最近的半点时间"""
|
||||||
|
dt = dt or datetime.now()
|
||||||
|
minute = 30 if dt.minute >= 30 else 0
|
||||||
|
return dt.replace(minute=minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
def get_api_url(coin, wallet):
|
||||||
|
domain = domain_map.get(coin)
|
||||||
|
if coin == "CFX" and not wallet.startswith("cfx:"):
|
||||||
|
wallet = f"cfx:{wallet}"
|
||||||
|
return f"https://{domain}/api/stats_address?address={wallet}&recentBlocksAmount=20&longpoll=false"
|
||||||
|
|
||||||
|
def fetch_herominers_data(pool_name, coin, wallet, algorithm):
|
||||||
|
url = get_api_url(coin, wallet)
|
||||||
|
try:
|
||||||
|
resp = requests.get(url, timeout=10)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
workers = data.get("workers", [])
|
||||||
|
if not workers:
|
||||||
|
print(f"{coin} | {wallet} | {pool_name} ⚠ 当前没有任何在线矿机")
|
||||||
|
return
|
||||||
|
|
||||||
|
for worker in workers:
|
||||||
|
name = worker.get("name", "unknown")
|
||||||
|
hashrate = worker.get("hashrate", 0) / 1_000_000 # 转 MH/s
|
||||||
|
|
||||||
|
# 写入 MySQL
|
||||||
|
sql = f"""INSERT INTO {TABLE_NAME}
|
||||||
|
(datetime, pool_name, wallet, miner, hashrate, coin, algorithm)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s)"""
|
||||||
|
cursor.execute(sql, (
|
||||||
|
round_half_hour(),
|
||||||
|
pool_name,
|
||||||
|
wallet,
|
||||||
|
name,
|
||||||
|
hashrate,
|
||||||
|
coin,
|
||||||
|
algorithm
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
print(f"{coin} | {pool_name} | {name}: {hashrate:.2f} MH/s 写入成功")
|
||||||
|
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
print(f"{coin} | {wallet} | {pool_name} 请求失败 HTTP 错误:", e)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{coin} | {wallet} | {pool_name} 请求失败:", e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
for key in keys:
|
||||||
|
parts = key.split(":")
|
||||||
|
if len(parts) != 4:
|
||||||
|
continue
|
||||||
|
_, wallet, coin, algorithm = parts
|
||||||
|
pool_name = parts[0] # Redis key第一部分作为矿池名
|
||||||
|
|
||||||
|
fetch_herominers_data(pool_name, coin, wallet, algorithm)
|
||||||
|
|
||||||
|
# 关闭连接
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
96
v1/kryptex_collector.py
Normal file
96
v1/kryptex_collector.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import redis
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import pymysql
|
||||||
|
from datetime import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Redis 配置
|
||||||
|
r = redis.Redis(host='127.0.0.1', port=6379, db=7, decode_responses=True)
|
||||||
|
|
||||||
|
# MySQL 配置
|
||||||
|
conn = pymysql.connect(
|
||||||
|
host='127.0.0.1',
|
||||||
|
user='root',
|
||||||
|
password='123456',
|
||||||
|
database='pool',
|
||||||
|
port=25600,
|
||||||
|
charset='utf8mb4'
|
||||||
|
)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# URL 模板
|
||||||
|
BASE_URL = "https://pool.kryptex.com/zh-cn/{coin}/miner/stats/{wallet}"
|
||||||
|
HEADERS = {"User-Agent": "Mozilla/5.0"}
|
||||||
|
|
||||||
|
|
||||||
|
def to_mhs(value: str):
|
||||||
|
"""自动将各种单位算力字符串转换成 MH/s 纯数字值"""
|
||||||
|
value = value.strip().lower()
|
||||||
|
if "gh/s" in value: return float(value.replace("gh/s", "")) * 1000
|
||||||
|
if "mh/s" in value: return float(value.replace("mh/s", ""))
|
||||||
|
if "kh/s" in value: return float(value.replace("kh/s", "")) / 1000
|
||||||
|
if "h/s" in value: return float(value.replace("h/s", "")) / 1_000_000
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def get_half_hour_time(now):
|
||||||
|
"""取最近半点整时间 如 10:08→10:00,10:40→10:30"""
|
||||||
|
minute = 0 if now.minute < 30 else 30
|
||||||
|
return now.replace(minute=minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
|
||||||
|
def query_and_insert():
|
||||||
|
keys = r.keys("*")
|
||||||
|
half_hour_time = get_half_hour_time(datetime.now())
|
||||||
|
|
||||||
|
for key in keys:
|
||||||
|
try:
|
||||||
|
parts = key.split(":")
|
||||||
|
if len(parts) != 4:
|
||||||
|
continue
|
||||||
|
|
||||||
|
pool_name, wallet, coin, algo = parts
|
||||||
|
if pool_name != "pool.kryptex":
|
||||||
|
continue
|
||||||
|
|
||||||
|
coin_lower = coin.lower()
|
||||||
|
coin_for_url = "xtm-c29" if coin_lower == "xtm" else coin_lower
|
||||||
|
url = BASE_URL.format(coin=coin_for_url, wallet=wallet.lower())
|
||||||
|
|
||||||
|
resp = requests.get(url, headers=HEADERS, timeout=10)
|
||||||
|
resp.raise_for_status()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(resp.text, "html.parser")
|
||||||
|
tbody = soup.find("tbody")
|
||||||
|
if not tbody:
|
||||||
|
print(f"❗无矿工数据 {wallet} {coin}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for row in tbody.find_all("tr"):
|
||||||
|
try:
|
||||||
|
worker = row.find("th").find("a").text.strip()
|
||||||
|
mhs = to_mhs(row.find_all("td")[5].text.strip())
|
||||||
|
|
||||||
|
print(f"[OK] {coin}:{wallet} {worker} -> {mhs:.2f} MH/s")
|
||||||
|
|
||||||
|
sql = """
|
||||||
|
INSERT INTO `pool.kryptex`
|
||||||
|
(datetime, pool_name, wallet, miner, hashrate, coin, algorithm)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
"""
|
||||||
|
cursor.execute(sql, (half_hour_time, pool_name, wallet, worker, mhs, coin.upper(), algo))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("解析矿工失败 =>", e)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("请求失败 =>", e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
query_and_insert()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print("✔ 采集完成,程序已退出")
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import redis
|
|
||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import pymysql
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import time
|
|
||||||
|
|
||||||
# Redis 配置
|
|
||||||
r = redis.Redis(host='127.0.0.1', port=6379, db=7, decode_responses=True)
|
|
||||||
|
|
||||||
# MySQL 配置
|
|
||||||
conn = pymysql.connect(
|
|
||||||
host='127.0.0.1',
|
|
||||||
user='root',
|
|
||||||
password='123456',
|
|
||||||
database='pool',
|
|
||||||
port=25600,
|
|
||||||
charset='utf8mb4'
|
|
||||||
)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# URL 模板
|
|
||||||
BASE_URL = "https://pool.kryptex.com/zh-cn/{coin}/miner/stats/{wallet}"
|
|
||||||
HEADERS = {"User-Agent": "Mozilla/5.0"}
|
|
||||||
|
|
||||||
|
|
||||||
def to_mhs(value: str):
|
|
||||||
"""自动把算力字符串转换成 MH/s 纯数字"""
|
|
||||||
value = value.strip().lower()
|
|
||||||
if "gh/s" in value:
|
|
||||||
return float(value.replace("gh/s", "").strip()) * 1000
|
|
||||||
if "mh/s" in value:
|
|
||||||
return float(value.replace("mh/s", "").strip())
|
|
||||||
if "kh/s" in value:
|
|
||||||
return float(value.replace("kh/s", "").strip()) / 1000
|
|
||||||
if "h/s" in value:
|
|
||||||
return float(value.replace("h/s", "").strip()) / 1_000_000
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
|
|
||||||
def get_half_hour_time(now):
|
|
||||||
"""取最近半点时间"""
|
|
||||||
minute = 0 if now.minute < 30 else 30
|
|
||||||
return now.replace(minute=minute, second=0, microsecond=0)
|
|
||||||
|
|
||||||
|
|
||||||
def query_and_insert():
|
|
||||||
keys = r.keys("*") # 遍历所有 key
|
|
||||||
half_hour_time = get_half_hour_time(datetime.now())
|
|
||||||
|
|
||||||
for key in keys:
|
|
||||||
try:
|
|
||||||
parts = key.split(":")
|
|
||||||
if len(parts) != 4:
|
|
||||||
continue
|
|
||||||
pool_name, wallet, coin, algo = parts
|
|
||||||
coin_lower = coin.lower()
|
|
||||||
# xtm 特殊处理
|
|
||||||
coin_for_url = "xtm-c29" if coin_lower == "xtm" else coin_lower
|
|
||||||
url = BASE_URL.format(coin=coin_for_url, wallet=wallet.lower())
|
|
||||||
|
|
||||||
resp = requests.get(url, headers=HEADERS, timeout=10)
|
|
||||||
resp.raise_for_status()
|
|
||||||
soup = BeautifulSoup(resp.text, "html.parser")
|
|
||||||
tbody = soup.find("tbody")
|
|
||||||
if not tbody:
|
|
||||||
print(f"池:{pool_name} 币种:{coin} 钱包:{wallet} 没有矿工数据")
|
|
||||||
continue
|
|
||||||
rows = tbody.find_all("tr")
|
|
||||||
if not rows:
|
|
||||||
print(f"池:{pool_name} 币种:{coin} 钱包:{wallet} 没有矿工数据")
|
|
||||||
continue
|
|
||||||
|
|
||||||
for row in rows:
|
|
||||||
try:
|
|
||||||
worker = row.find("th").find("a").text.strip()
|
|
||||||
tds = row.find_all("td")
|
|
||||||
# 10 分钟算力列
|
|
||||||
hashrate_raw = tds[5].text.strip()
|
|
||||||
mhs = to_mhs(hashrate_raw)
|
|
||||||
|
|
||||||
# 输出日志
|
|
||||||
print(f"池:{pool_name} 币种:{coin} 钱包:{wallet} 矿工:{worker} -> {mhs:.2f} MH/s")
|
|
||||||
|
|
||||||
# 写入数据库
|
|
||||||
sql = """
|
|
||||||
INSERT INTO `pool.kryptex`
|
|
||||||
(datetime, pool_name, wallet, miner, hashrate, coin, algorithm)
|
|
||||||
VALUES (%s,%s,%s,%s,%s,%s,%s)
|
|
||||||
"""
|
|
||||||
cursor.execute(sql, (half_hour_time, pool_name, wallet, worker, mhs, coin.upper(), algo))
|
|
||||||
conn.commit()
|
|
||||||
except Exception as e:
|
|
||||||
print("解析矿工数据失败:", e)
|
|
||||||
except Exception as e:
|
|
||||||
print("请求或解析失败:", e)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
now = datetime.now()
|
|
||||||
next_minute = 30 if now.minute < 30 else 60
|
|
||||||
wait_seconds = (next_minute - now.minute) * 60 - now.second
|
|
||||||
if wait_seconds > 0:
|
|
||||||
print(f"等待 {wait_seconds} 秒到下一个半点...")
|
|
||||||
time.sleep(wait_seconds)
|
|
||||||
query_and_insert()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("程序结束")
|
|
||||||
finally:
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
import redis
|
|
||||||
import requests
|
|
||||||
import pymysql
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import time
|
|
||||||
|
|
||||||
# ---------------- Redis 配置 ----------------
|
|
||||||
r = redis.Redis(host='127.0.0.1', port=6379, db=7, decode_responses=True)
|
|
||||||
|
|
||||||
# ---------------- MySQL 配置 ----------------
|
|
||||||
conn = pymysql.connect(
|
|
||||||
host='127.0.0.1',
|
|
||||||
user='root',
|
|
||||||
password='123456',
|
|
||||||
database='pool',
|
|
||||||
port=25600,
|
|
||||||
charset='utf8mb4'
|
|
||||||
)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# ---------------- API 配置 ----------------
|
|
||||||
API_URLS = {
|
|
||||||
"NEXA": "https://nexa.2miners.com/api/accounts/{wallet}",
|
|
||||||
"XNA": "https://xna.2miners.com/api/accounts/{wallet}",
|
|
||||||
"CLORE": "https://clore.2miners.com/api/accounts/{wallet}",
|
|
||||||
"RVN": "https://rvn.2miners.com/api/accounts/{wallet}",
|
|
||||||
"ERG": "https://erg.2miners.com/api/accounts/{wallet}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------- 工具函数 ----------------
|
|
||||||
def to_mhs(value):
|
|
||||||
"""算力转换为 MH/s"""
|
|
||||||
return float(value) / 1_000_000 if value else 0.0
|
|
||||||
|
|
||||||
def get_half_hour_time(now):
|
|
||||||
"""取最近半点时间"""
|
|
||||||
minute = 0 if now.minute < 30 else 30
|
|
||||||
return now.replace(minute=minute, second=0, microsecond=0)
|
|
||||||
|
|
||||||
# ---------------- 主逻辑 ----------------
|
|
||||||
def query_and_insert():
|
|
||||||
keys = r.keys("*") # 遍历所有 key
|
|
||||||
half_hour_time = get_half_hour_time(datetime.now())
|
|
||||||
|
|
||||||
for key in keys:
|
|
||||||
try:
|
|
||||||
# key 格式: pool_name:wallet:coin:algo
|
|
||||||
parts = key.split(":")
|
|
||||||
if len(parts) != 4:
|
|
||||||
continue
|
|
||||||
pool_name, wallet, coin, algo = parts
|
|
||||||
if pool_name.lower() != "2miners":
|
|
||||||
continue # 不是 2Miners 的数据就跳过
|
|
||||||
coin_upper = coin.upper()
|
|
||||||
|
|
||||||
if coin_upper not in API_URLS:
|
|
||||||
print(f"币种 {coin_upper} 不在支持列表中,跳过")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# NEXA 特殊处理,其他币种直接用 wallet
|
|
||||||
if coin_upper == "NEXA" and not wallet.lower().startswith("nexa:"):
|
|
||||||
wallet_for_api = f"nexa:{wallet}"
|
|
||||||
else:
|
|
||||||
wallet_for_api = wallet
|
|
||||||
|
|
||||||
url = API_URLS[coin_upper].format(wallet=wallet_for_api)
|
|
||||||
resp = requests.get(url, timeout=10)
|
|
||||||
resp.raise_for_status()
|
|
||||||
data = resp.json()
|
|
||||||
|
|
||||||
# 遍历矿机
|
|
||||||
workers = data.get("workers", {})
|
|
||||||
if not workers:
|
|
||||||
print(f"{coin_upper} 钱包 {wallet} 没有矿机数据")
|
|
||||||
continue
|
|
||||||
|
|
||||||
for miner_name, miner_data in workers.items():
|
|
||||||
hashrate = to_mhs(miner_data.get("hr"))
|
|
||||||
print(f"池:{pool_name} 币种:{coin_upper} 钱包:{wallet} 矿机:{miner_name} -> {hashrate:.2f} MH/s")
|
|
||||||
|
|
||||||
# 写入数据库
|
|
||||||
sql = """
|
|
||||||
INSERT INTO `2miners`
|
|
||||||
(datetime, pool_name, wallet, miner, hashrate, coin, algorithm)
|
|
||||||
VALUES (%s,%s,%s,%s,%s,%s,%s)
|
|
||||||
"""
|
|
||||||
cursor.execute(sql, (half_hour_time, pool_name, wallet, miner_name, hashrate, coin_upper, algo))
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print("请求或解析失败:", e)
|
|
||||||
|
|
||||||
# ---------------- 定时执行 ----------------
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
now = datetime.now()
|
|
||||||
next_minute = 30 if now.minute < 30 else 60
|
|
||||||
wait_seconds = (next_minute - now.minute) * 60 - now.second
|
|
||||||
if wait_seconds > 0:
|
|
||||||
print(f"等待 {wait_seconds} 秒到下一个半点...")
|
|
||||||
time.sleep(wait_seconds)
|
|
||||||
query_and_insert()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("程序结束")
|
|
||||||
finally:
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
45
v1/run_collectors.py
Normal file
45
v1/run_collectors.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 你的 Python 路径(如无需特定可直接 python3)
|
||||||
|
PYTHON = "/usr/bin/python3"
|
||||||
|
|
||||||
|
# 要执行的脚本
|
||||||
|
SCRIPTS = [
|
||||||
|
"2miners_collector.py",
|
||||||
|
"kryptex_collector.py",
|
||||||
|
"herominers_collector.py",
|
||||||
|
"vipor_collector.py"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_half_round_sleep():
|
||||||
|
now = datetime.now()
|
||||||
|
minute = now.minute
|
||||||
|
|
||||||
|
# 计算距离下个半点的秒数
|
||||||
|
if minute < 30:
|
||||||
|
target = now.replace(minute=30, second=0, microsecond=0)
|
||||||
|
else:
|
||||||
|
target = now.replace(hour=now.hour + 1, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
|
return int((target - now).total_seconds())
|
||||||
|
|
||||||
|
|
||||||
|
def run_scripts():
|
||||||
|
print("\n================= 开始执行采集任务 =================")
|
||||||
|
for script in SCRIPTS:
|
||||||
|
print(f"▶ 正在执行 {script} ...")
|
||||||
|
os.system(f"{PYTHON} {script}") # 如果脚本不在同目录请加绝对路径
|
||||||
|
print(f"✔ 执行完成 {script}\n")
|
||||||
|
|
||||||
|
print("================= 当前轮次已完成 =================\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
while True:
|
||||||
|
run_scripts()
|
||||||
|
sleep_time = get_half_round_sleep()
|
||||||
|
print(f"⏳ 等待 {sleep_time} 秒进入下个半点执行...\n")
|
||||||
|
time.sleep(sleep_time)
|
||||||
105
v1/vipor_collector.py
Normal file
105
v1/vipor_collector.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import redis
|
||||||
|
import requests
|
||||||
|
import pymysql
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# ---------------- Redis 配置 ----------------
|
||||||
|
REDIS_HOST = "127.0.0.1"
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
REDIS_DB = 7
|
||||||
|
|
||||||
|
# ---------------- MySQL 配置 ----------------
|
||||||
|
MYSQL_HOST = "127.0.0.1"
|
||||||
|
MYSQL_PORT = 25600
|
||||||
|
MYSQL_USER = "root"
|
||||||
|
MYSQL_PASS = "123456"
|
||||||
|
MYSQL_DB = "pool"
|
||||||
|
TABLE_NAME = "`vipor.net`"
|
||||||
|
|
||||||
|
# ---------------- 连接 Redis ----------------
|
||||||
|
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, decode_responses=True)
|
||||||
|
|
||||||
|
# ---------------- 连接 MySQL ----------------
|
||||||
|
conn = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER,
|
||||||
|
password=MYSQL_PASS, database=MYSQL_DB, charset='utf8mb4')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# ---------------- 从 Redis 获取矿池配置 ----------------
|
||||||
|
# 格式: pool_name:wallet:COIN:ALGORITHM
|
||||||
|
keys = r.keys("vipor.net:*")
|
||||||
|
|
||||||
|
def get_half_hour_time():
|
||||||
|
"""返回最近半点时间"""
|
||||||
|
now = datetime.now()
|
||||||
|
minute = 30 if now.minute >= 30 else 0
|
||||||
|
return now.replace(minute=minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
def fetch_vipor_data(pool_name, coin, wallet, algorithm, api_pool):
|
||||||
|
url = f"https://restapi.vipor.net/api/pools/{api_pool}/miners/{wallet}"
|
||||||
|
try:
|
||||||
|
resp = requests.get(url, timeout=10)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
# 优先 performance.workers
|
||||||
|
workers = data.get("performance", {}).get("workers")
|
||||||
|
if not workers:
|
||||||
|
workers = data.get("workers") or data.get("miners") or {}
|
||||||
|
|
||||||
|
if not workers:
|
||||||
|
print(f"{coin} | {api_pool} | {wallet} ⚠ 当前没有任何在线矿机")
|
||||||
|
return
|
||||||
|
|
||||||
|
for miner, info in workers.items():
|
||||||
|
hashrate = info.get("hashrate", 0) or 0
|
||||||
|
hashrate_mhs = hashrate / 1_000_000 # 转为 MH/s
|
||||||
|
|
||||||
|
# 插入 MySQL
|
||||||
|
sql = f"""INSERT INTO {TABLE_NAME}
|
||||||
|
(datetime, pool_name, wallet, miner, hashrate, coin, algorithm)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s)"""
|
||||||
|
cursor.execute(sql, (
|
||||||
|
get_half_hour_time(),
|
||||||
|
pool_name, # 这里使用 Redis key 的第一部分
|
||||||
|
wallet,
|
||||||
|
miner,
|
||||||
|
hashrate_mhs,
|
||||||
|
coin,
|
||||||
|
algorithm
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
print(f"{coin} | {api_pool} | {miner}: {hashrate_mhs:.2f} MH/s 写入成功")
|
||||||
|
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
print(f"{coin} | {api_pool} | {wallet} 请求失败 HTTP 错误:", e)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{coin} | {api_pool} | {wallet} 请求失败:", e)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
for key in keys:
|
||||||
|
parts = key.split(":")
|
||||||
|
if len(parts) != 4:
|
||||||
|
continue
|
||||||
|
pool_name, wallet, coin, algorithm = parts
|
||||||
|
|
||||||
|
# 构造普通和 solo pool 名(用于请求 API,不影响存入数据库的 pool_name)
|
||||||
|
api_pools = []
|
||||||
|
if coin == "NEXA":
|
||||||
|
api_pools = ["nexa", "nexa_solo"]
|
||||||
|
elif coin == "XEL":
|
||||||
|
api_pools = ["xelis", "xelis_solo"]
|
||||||
|
elif coin == "XNA":
|
||||||
|
api_pools = ["neurai", "neurai_solo"]
|
||||||
|
elif coin == "CLORE":
|
||||||
|
api_pools = ["clore", "clore_solo"]
|
||||||
|
else:
|
||||||
|
api_pools = ["default", "default_solo"]
|
||||||
|
|
||||||
|
for api_pool in api_pools:
|
||||||
|
fetch_vipor_data(pool_name, coin, wallet, algorithm, api_pool)
|
||||||
|
|
||||||
|
# 关闭连接
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
Reference in New Issue
Block a user