import asyncio
import json
import re
import time
import ctypes
from pathlib import Path
from playwright.async_api import async_playwright
# --- Ẩn cửa sổ CMD ---
def hide_console():
try:
hwnd = ctypes.windll.kernel32.GetConsoleWindow()
if hwnd:
ctypes.windll.user32.ShowWindow(hwnd, 0)
except Exception:
pass
hide_console()
# ================== CẤU HÌNH ==================
ACCOUNTS_FILE = "accounts.txt"
LOGIN_URL = "https://1900.fun/login.php"
DAO_MO_URL = "https://1900.fun/city/daomo/"
HEADLESS = True
MAX_CONCURRENT = 2 # Máy yếu → chạy tối đa 2 tài khoản
DELAY_BETWEEN_START = 3
INTERVAL_SECONDS = 10 * 60 # 10 phút
WAIT_BEFORE_MINE = 2 * 60 # 2 phút chờ ban đầu
MINING_DURATION = 10 * 60 # 10 phút đào
HARVEST_EARLY = 25 # Thu hoạch sớm 25 giây
CLAIM_INTERVAL = 28 # Claim mỗi ~28 giây
# ==============================================
def load_accounts(file_path: str) -> list[tuple[str, str]]:
accounts = []
path = Path(file_path)
if not path.exists():
print(f"[!] Không tìm thấy file {file_path}")
return accounts
for line in path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
if "|" in line:
user, pwd = line.split("|", 1)
accounts.append((user.strip(), pwd.strip()))
return accounts
def clean_and_parse_json(raw_text: str) -> dict:
try:
match = re.search(r"\{.*\}", raw_text, re.DOTALL)
if match:
return json.loads(match.group(0))
return {"success": False, "error": f"Không tìm thấy JSON: {raw_text[:120]}"}
except Exception as e:
return {"success": False, "error": f"Lỗi parse: {e}"}
async def fetch_ajax(page, body: str) -> dict:
raw = await page.evaluate(
f"""async () => {{
try {{
const res = await fetch('ajax_mine.php', {{
method: 'POST',
headers: {{ 'Content-Type': 'application/x-www-form-urlencoded' }},
body: '{body}'
}});
return await res.text();
}} catch (e) {{
return e.toString();
}}
}}"""
)
return clean_and_parse_json(raw)
async def login(page, username: str, password: str) -> bool:
try:
print(f" [{username}] Truy cập trang login...")
await page.goto(LOGIN_URL, wait_until="domcontentloaded", timeout=30000)
await page.wait_for_timeout(1500)
user_selectors = [
"input[name='username']",
"input[name='user']",
"input[name='login']",
"input[type='text']",
"#username",
"input[placeholder*='Tên']",
"input[placeholder*='tài khoản']",
]
pass_selectors = [
"input[name='password']",
"input[name='pass']",
"input[type='password']",
"#password",
]
btn_selectors = [
"button[type='submit']",
"input[type='submit']",
"button:has-text('Đăng nhập')",
"button:has-text('Login')",
".btn-login",
"form button",
]
filled_user = False
for sel in user_selectors:
try:
el = page.locator(sel).first
if await el.count() > 0 and await el.is_visible():
await el.fill(username)
filled_user = True
print(f" [{username}] Điền username bằng selector: {sel}")
break
except:
continue
if not filled_user:
print(f" [{username}] Không tìm thấy ô username!")
return False
filled_pass = False
for sel in pass_selectors:
try:
el = page.locator(sel).first
if await el.count() > 0 and await el.is_visible():
await el.fill(password)
filled_pass = True
print(f" [{username}] Điền password bằng selector: {sel}")
break
except:
continue
if not filled_pass:
print(f" [{username}] Không tìm thấy ô password!")
return False
clicked = False
for sel in btn_selectors:
try:
el = page.locator(sel).first
if await el.count() > 0 and await el.is_visible():
async with page.expect_navigation(wait_until="domcontentloaded", timeout=15000):
await el.click()
clicked = True
print(f" [{username}] Click nút bằng selector: {sel}")
break
except:
continue
if not clicked:
await page.keyboard.press("Enter")
await page.wait_for_timeout(2000)
await page.wait_for_timeout(2000)
current_url = page.url.lower()
content = (await page.content()).lower()
success_signs = [
"logout" in content,
"đăng xuất" in content,
"thoát" in content,
username.lower() in content,
"city" in current_url,
"index.php" in current_url and "login" not in current_url,
"house.php" in current_url,
"daomo" in current_url,
]
if any(success_signs) and "login" not in current_url:
print(f" [{username}] Đăng nhập THÀNH CÔNG (URL: {page.url})")
return True
print(f" [{username}] Đăng nhập THẤT BẠI")
print(f" [{username}] URL hiện tại: {page.url}")
body_text = await page.inner_text("body")
print(f" [{username}] Nội dung trang (300 ký tự): {body_text[:300].replace(chr(10), ' ')}")
return False
except Exception as e:
print(f" [{username}] Lỗi exception khi login: {e}")
return False
async def process_account(username: str, password: str, browser, semaphore: asyncio.Semaphore):
async with semaphore:
print(f"\n{'='*55}")
print(f" Bắt đầu: {username}")
print(f"{'='*55}")
context = await browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
viewport={"width": 1280, "height": 720},
)
page = await context.new_page()
try:
ok = await login(page, username, password)
if not ok:
print(f"[{username}] Đăng nhập thất bại → bỏ qua")
return
print(f"[{username}] Vào trang Đào Mỏ...")
await page.goto(DAO_MO_URL, wait_until="domcontentloaded", timeout=30000)
await page.wait_for_timeout(1500)
info = await fetch_ajax(page, "action=get_mine_info")
if not info.get("success"):
print(f"[{username}] Không lấy được thông tin mỏ: {info.get('error')}")
return
is_mining = info.get("is_mining", False)
print(f"[{username}] Trạng thái: {'Đang đào' if is_mining else 'Đang rảnh'}")
print(f"[{username}] Hiện có: 💎{info.get('collected_stone', 0)} | "
f"💰{info.get('collected_xu', 0)} | ✨{info.get('collected_exp', 0)}")
if not is_mining:
print(f"[{username}] Bắt đầu đào mỏ...")
start_res = await fetch_ajax(page, "action=start_mining")
if start_res.get("success"):
print(f"[{username}] → {start_res.get('message', 'Bắt đầu thành công')}")
is_mining = True
else:
print(f"[{username}] Không thể bắt đầu: {start_res.get('error')}")
return
if not is_mining:
return
total_wait = WAIT_BEFORE_MINE + MINING_DURATION - HARVEST_EARLY
print(f"[{username}] Đang đào... sẽ thu hoạch sau khoảng {total_wait // 60} phút {total_wait % 60} giây")
start_time = time.time()
last_claim = 0
while True:
elapsed = time.time() - start_time
if elapsed - last_claim >= CLAIM_INTERVAL:
claim = await fetch_ajax(page, "action=claim_reward")
if claim.get("success"):
print(f"[{username}] Claim → 💎{claim.get('collected_stone', 0)} | "
f"💰{claim.get('collected_xu', 0)} | ✨{claim.get('collected_exp', 0)}")
last_claim = elapsed
if elapsed >= total_wait:
print(f"[{username}] Đến giờ thu hoạch...")
harvest = await fetch_ajax(page, "action=harvest")
if harvest.get("success"):
print(f"[{username}] → {harvest.get('message', 'Thu hoạch thành công')}")
if harvest.get("new_xu"):
print(f"[{username}] Xu hiện tại: {harvest['new_xu']:,}")
else:
print(f"[{username}] Lỗi thu hoạch: {harvest.get('error')}")
break
await asyncio.sleep(5)
print(f"[{username}] ✓ Hoàn thành")
except Exception as e:
print(f"[{username}] Lỗi: {e}")
finally:
await context.close()
async def run_one_cycle(accounts, browser, semaphore):
tasks = []
for idx, (user, pwd) in enumerate(accounts):
async def delayed_start(u=user, pw=pwd, delay=idx * DELAY_BETWEEN_START):
if delay > 0:
await asyncio.sleep(delay)
await process_account(u, pw, browser, semaphore)
tasks.append(asyncio.create_task(delayed_start()))
await asyncio.gather(*tasks)
async def main():
accounts = load_accounts(ACCOUNTS_FILE)
if not accounts:
print("[!] Không có tài khoản nào để chạy.")
return
print(f"[*] Tìm thấy {len(accounts)} tài khoản")
print(f"[*] Chạy song song tối đa: {MAX_CONCURRENT} tài khoản")
print(f"[*] Headless = {HEADLESS}")
print(f"[*] Chế độ: CHẠY LẶP mỗi {INTERVAL_SECONDS // 60} phút")
semaphore = asyncio.Semaphore(MAX_CONCURRENT)
cycle = 1
async with async_playwright() as p:
browser = await p.chromium.launch(headless=HEADLESS)
while True:
print(f"\n{'#'*60}")
print(f" BẮT ĐẦU VÒNG LẶP THỨ {cycle}")
print(f"{'#'*60}")
await run_one_cycle(accounts, browser, semaphore)
print(f"\n[✓] Hoàn thành vòng {cycle}")
print(f"[*] Nghỉ {INTERVAL_SECONDS // 60} phút rồi chạy lại...")
await asyncio.sleep(INTERVAL_SECONDS)
cycle += 1
if __name__ == "__main__":
asyncio.run(main())