URnetwork free-tier farm: API-only accounts, keys, hosted residential proxies + measured limits
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""URnetwork farm — instant networks, API keys, hosted proxies. No browser.
|
||||
|
||||
POST /auth/network-create {"terms": true} -> by_jwt (an account with no email)
|
||||
then: seedphrase, urn_ key, N hosted HTTPS proxies by country.
|
||||
|
||||
Usage: python ur_farm.py --count 5 [--proxies 5] [--bank bank.jsonl]
|
||||
"""
|
||||
import argparse, json, os, ssl, subprocess, sys, time, urllib.request, urllib.error
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
BASE = "https://api.bringyour.com"
|
||||
CTX = ssl.create_default_context()
|
||||
CTX.check_hostname = False
|
||||
CTX.verify_mode = ssl.CERT_NONE
|
||||
CODES = ["us", "de", "nl", "fr", "gb", "ca", "br", "se", "pl", "ch", "jp", "sg", "it", "es", "at"]
|
||||
|
||||
|
||||
PROXY = None
|
||||
|
||||
|
||||
def call(path, method="GET", payload=None, tok=None, timeout=60):
|
||||
if PROXY:
|
||||
return call_curl(path, method, payload, tok, timeout)
|
||||
data = json.dumps(payload).encode() if payload is not None else None
|
||||
h = {"Accept": "application/json", "User-Agent": "Mozilla/5.0"}
|
||||
if data:
|
||||
h["Content-Type"] = "application/json"
|
||||
if tok:
|
||||
h["Authorization"] = "Bearer " + tok
|
||||
req = urllib.request.Request(BASE + path, data=data, headers=h, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=timeout, context=CTX) as r:
|
||||
body = r.read(60000).decode("utf-8", "replace")
|
||||
try:
|
||||
return r.status, json.loads(body)
|
||||
except Exception:
|
||||
return r.status, body
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, e.read(2000).decode("utf-8", "replace")[:400]
|
||||
except Exception as e:
|
||||
return 0, "%s: %s" % (type(e).__name__, str(e)[:120])
|
||||
|
||||
|
||||
def call_curl(path, method, payload, tok, timeout):
|
||||
cmd = ["curl", "-s", "-m", str(timeout), "--proxy", PROXY, "-X", method,
|
||||
BASE + path, "-H", "Accept: application/json",
|
||||
"-H", "User-Agent: Mozilla/5.0"]
|
||||
if tok:
|
||||
cmd += ["-H", "Authorization: Bearer " + tok]
|
||||
if payload is not None:
|
||||
cmd += ["-H", "Content-Type: application/json", "-d", json.dumps(payload)]
|
||||
try:
|
||||
out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout + 20).stdout
|
||||
try:
|
||||
return 200, json.loads(out)
|
||||
except Exception:
|
||||
return 0, out[:400]
|
||||
except Exception as e:
|
||||
return 0, "%s: %s" % (type(e).__name__, str(e)[:100])
|
||||
|
||||
|
||||
def one(idx, nproxy, country_offset):
|
||||
st, d = call("/auth/network-create", "POST",
|
||||
{"terms": True, "product_updates": False})
|
||||
if not isinstance(d, dict) or "network" not in d:
|
||||
return {"idx": idx, "error": "create %s %s" % (st, str(d)[:160])}
|
||||
net = d["network"]
|
||||
jwt = net.get("by_jwt")
|
||||
if not jwt:
|
||||
return {"idx": idx, "error": "no jwt"}
|
||||
rec = {"idx": idx, "network_id": net.get("network_id"),
|
||||
"name": net.get("network_name"), "jwt": jwt, "proxies": []}
|
||||
|
||||
st, sd = call("/auth/regenerate-seedphrase", "POST", {}, jwt)
|
||||
seed = sd.get("seedphrase") if isinstance(sd, dict) else None
|
||||
if isinstance(seed, list):
|
||||
seed = " ".join(seed)
|
||||
rec["seed"] = seed
|
||||
|
||||
st, kd = call("/account/api-key", "POST", {"name": "farm-%d" % idx}, jwt)
|
||||
key = kd.get("api_key") if isinstance(kd, dict) else None
|
||||
if not key:
|
||||
rec["error"] = "api-key %s %s" % (st, str(kd)[:120])
|
||||
return rec
|
||||
rec["urn"] = key
|
||||
|
||||
for i in range(nproxy):
|
||||
cc = CODES[(country_offset + i) % len(CODES)]
|
||||
st, pd = call("/network/auth-client", "POST", {
|
||||
"description": "HTTPS proxy · %s" % cc.upper(),
|
||||
"device_spec": "resident proxy",
|
||||
"proxy_config": {"initial_device_state": {"country_code": cc}}}, key)
|
||||
r = (pd or {}).get("proxy_config_result") if isinstance(pd, dict) else None
|
||||
if r and r.get("https_proxy_url"):
|
||||
rec["proxies"].append({"cc": cc, "url": r["https_proxy_url"],
|
||||
"socks": r.get("socks_proxy_url"),
|
||||
"client_id": pd.get("client_id")})
|
||||
else:
|
||||
err = (pd or {}).get("error") if isinstance(pd, dict) else pd
|
||||
rec.setdefault("proxy_errors", []).append("%s: %s" % (cc, str(err)[:80]))
|
||||
time.sleep(1.3)
|
||||
return rec
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--count", type=int, default=5)
|
||||
ap.add_argument("--proxies", type=int, default=5)
|
||||
ap.add_argument("--bank", default="bank.jsonl")
|
||||
ap.add_argument("--start", type=int, default=100)
|
||||
ap.add_argument("--proxy", default="", help="http(s) proxy URL for the whole run")
|
||||
ap.add_argument("--proxy-file", default="", help="file with one proxy URL per line (rotates)")
|
||||
a = ap.parse_args()
|
||||
|
||||
global PROXY
|
||||
pool = []
|
||||
if a.proxy_file and os.path.exists(a.proxy_file):
|
||||
pool = [l.strip() for l in open(a.proxy_file, encoding="utf-8") if l.strip()]
|
||||
made, okp = 0, 0
|
||||
for n in range(a.count):
|
||||
if a.proxy:
|
||||
PROXY = a.proxy
|
||||
elif pool:
|
||||
PROXY = pool[n % len(pool)]
|
||||
idx = a.start + n
|
||||
rec = one(idx, a.proxies, n * 3)
|
||||
with open(a.bank, "a", encoding="utf-8") as fh:
|
||||
fh.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
||||
if rec.get("urn"):
|
||||
made += 1
|
||||
okp += len(rec.get("proxies", []))
|
||||
print("acct%d %-16s proxies=%d %s" % (idx, rec.get("name"),
|
||||
len(rec.get("proxies", [])), ",".join(p["cc"] for p in rec.get("proxies", []))))
|
||||
else:
|
||||
print("acct%d FAIL %s" % (idx, rec.get("error")))
|
||||
time.sleep(1.5)
|
||||
print(json.dumps({"accounts_ok": made, "proxies_ok": okp, "bank": a.bank}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user