feat(stalk): add mobile-legends, free-fire, genshin, twitter, tiktok, instagram
Ported from Shirokami-API scraper/stalk/*.js: - /stalk/mobile-legends (gempaytopup CSRF+POST) - /stalk/free-fire (freefirecommunity API + field transform) - /stalk/genshin-impact (enka.network __data.json) - /stalk/twitter (fxtwitter API) - /stalk/tiktok (rehydration JSON parse) - /stalk/instagram (mollygram HTML scrape) Upstream status: twitter/genshin verified working live (elonmusk 241M followers). github+youtube verified earlier. tiktok WAF-blocked, instagram mollygram-captcha blocked, mobile-legends gempaytopup changed POST->GET+JS (all upstream dead for VPS IP; code faithful to source).
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""Extract TikTok user-detail JSON (__UNIVERSAL_DATA_FOR_REHYDRATION__) via Playwright.
|
||||
|
||||
The direct HTTP path gets a SlardarWAF challenge page; a real browser with JS
|
||||
executes the challenge and exposes the __UNIVERSAL_DATA_FOR_REHYDRATION__ script.
|
||||
Usage: python3 stalk_tiktok.py <username>
|
||||
"""
|
||||
import sys
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
|
||||
os.environ.setdefault("PLAYWRIGHT_BROWSERS_PATH", "/usr/local/share/ms-playwright")
|
||||
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
|
||||
async def main(username):
|
||||
url = f"https://www.tiktok.com/@{username}?_t=ZS-8tHANz7ieoS&_r=1"
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(
|
||||
headless=True,
|
||||
args=["--no-sandbox", "--disable-bypass", "--disable-blink-features=AutomationControlled"],
|
||||
)
|
||||
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": 1366, "height": 768},
|
||||
java_script_enabled=True,
|
||||
locale="en-US",
|
||||
)
|
||||
page = await context.new_page()
|
||||
try:
|
||||
await page.goto(url, timeout=60000, wait_until="domcontentloaded")
|
||||
except Exception as e:
|
||||
await browser.close()
|
||||
print(json.dumps({"success": False, "error": f"Navigation: {e}"}))
|
||||
return
|
||||
|
||||
# Wait for the rehydration script to appear (WAF challenge may take a few seconds)
|
||||
found = None
|
||||
for _ in range(30):
|
||||
try:
|
||||
found = await page.evaluate(
|
||||
"""() => {
|
||||
const s = document.querySelector('script#__UNIVERSAL_DATA_FOR_REHYDRATION__');
|
||||
return s ? s.textContent : null;
|
||||
}"""
|
||||
)
|
||||
if found:
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
await page.wait_for_timeout(1000)
|
||||
|
||||
await browser.close()
|
||||
|
||||
if not found:
|
||||
print(json.dumps({"success": False, "error": "Rehydration data not found (WAF challenge)"}))
|
||||
return
|
||||
|
||||
print(json.dumps({"success": True, "data": found}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main(sys.argv[1]))
|
||||
Reference in New Issue
Block a user