Skip to content

Instantly share code, notes, and snippets.

@honno
Last active September 15, 2025 12:05
Show Gist options
  • Save honno/262d58c7327cfe531ae528aa318018e9 to your computer and use it in GitHub Desktop.
Save honno/262d58c7327cfe531ae528aa318018e9 to your computer and use it in GitHub Desktop.
Scraper for Health Lotto gambling game Quick Win

Health Lottery Quick Win Draws Scraper

The Health Lottery in the UK runs an online lottery that runs every 3 minutes called Quick Win, where they employ the services of an online casino games supplier called Gamevy.

And so, scraper.py collates the numbers resulting from each draw to generate a .csv file.

Gamevy has seemingly exposed every past draw of the lottery in one API endpoint that only requires a (publicly available) session token from another endpoint. As of May 2019, that's over 300 000 draws!

I made this as part of a learning exercising to test the "randomness" of this lottery game by way of statistical analysis.

const fetch = require("node-fetch");
const next_draw_api_url = "https://bornlucky-prod.gamevy.com/health-lottery/next-draw";
const draw_api_url = "https://bornlucky-prod.gamevy.com/health-lottery/draws/";
const bet_api_url = "https://bornlucky-prod.gamevy.com/health-lottery/bet";
const refer_base = "https://games.gamevy.com/d/";
const refer_queries = "/index.html?env=prod&region=LON&platform=geneity&mode=real&currency=GBP&lang=en-GB&operator=health-lottery&numbers=&lobbyUrl=&clientType=desktop&sid=";
const time_before_spam = 200;
var sid = process.argv[2];
var app_id = process.argv[3];
var sid_header = { "x-gamevy-session-token": sid };
var bet_header = {
"User-Agent": "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0",
"Accept": "*/*",
"Accept-Language": "en-GB,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Origin": "https://games.gamevy.com",
"Connection": "keep-alive",
"Referer": refer_base + app_id + refer_queries + sid,
"x-gamevy-session-token": sid,
"Content-type": "application/json; charset=UTF-8"
};
async function get_next_draw() {
var res = await fetch(next_draw_api_url, { headers: sid_header });
if(!res.ok) { process.exit() };
var info = await res.json();
return info['nextDraw'];
}
async function get_draw_nums(draw_url) {
var res = await fetch(draw_url, { headers: sid_header });
var info = await res.json();
return info['numbers'];
}
async function bet(draw_id, draw_nums) {
p(`bet initiated with numbers ${draw_nums}`);
var json = JSON.stringify({ drawId: draw_id, lines: [{ numbers: draw_nums }], version: "default" });
var res = await fetch(bet_api_url, {
method: 'POST',
headers: bet_header,
body: json,
});
p(res);
var res_body = await res.json();
p(res_body);
return res;
}
async function spam(draw_id) {
p(`spam initiated with draw_id ${draw_id}`);
var draw_url = draw_api_url + draw_id;
var betted = false;
while(!betted) {
var draw_nums = await get_draw_nums(draw_url);
if(draw_nums != null) {
var res = bet(draw_id, draw_nums);
betted = true;
}
};
}
if (require.main === module) {
get_next_draw().then((info) => {
var draw_id = info['id'];
var draw_at = info['drawAt'];
var draw_date = new Date(draw_at);
var time_til_action = draw_date.getTime() - Date.now() - time_before_spam;
p(`time_til_action: ${time_til_action}ms`);
setTimeout(spam, time_til_action, draw_id);
});
}
function p(msg) {
console.log(msg);
}
#!/usr/bin/env python3
import getopt
import csv
import json
import time
import sys
import logging
import requests
DRAWS_FILE = "health_lotto_quick_win_draws.csv"
LOG_FILE = "draws_log.txt"
GUEST_SESSION_URL = "https://bornlucky-test.gamevy.com/anonym/guest-session"
DRAW_API_URL = "https://bornlucky-prod.gamevy.com/health-lottery/draws/"
RATE_LIMIT = 1 # in s
def get_sid():
res = requests.post(GUEST_SESSION_URL)
sid = res.json()['sessionToken']
logging.info("Using session token %s", sid)
return sid
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename=LOG_FILE, format="%(asctime)s - %(message)s")
logging.info("Script initiated")
with open(DRAWS_FILE, 'a') as record:
writer = csv.writer(record, delimiter=',')
# Start at draw in 's' argument, otherwise start from 1
draw_id = 1
opts, args = getopt.getopt(sys.argv[1:], "s:")
for opt, arg in opts:
if opt == "-s":
draw_id = int(arg)
logging.info("Starting from draw %s", draw_id)
sid = get_sid()
while True:
logging.info("Finding record for draw %s", draw_id)
url = DRAW_API_URL + str(draw_id)
header = { "x-gamevy-session-token": sid }
res = requests.get(url, params=header)
status = res.status_code
info = res.json()
logging.info("Response text: %s", res.text)
if status == 200: # expect draw results in response
numbers = info['numbers']
row = [
info['id'],
info['drawAt'],
info['charity'],
numbers[0],
numbers[1],
numbers[2],
numbers[3],
numbers[4],
info['bonusNumber']
]
writer.writerow(row)
logging.info("Wrote record %s", ','.join(str(e) for e in row))
draw_id += 1
time.sleep(RATE_LIMIT)
elif status == 401: # expect token has expired
sid = get_sid()
elif status == 404: # expect no more draws to extract
sys.exit(0)
@RyanbosG
Copy link

You've raised an interesting point in the context of the lottery. You've created a great educational exercise aimed at testing the randomness of this lottery. I've always been interested in the topic of lotteries and gambling, luck, and probability theory. Currently, I'm passionate about gambling and practice playing on various online platforms, which can be found at https://casino358.com/casino-bonukset/ with valuable information about bonuses at online casinos in Finland. I'm also enthusiastic about programming because writing code requires logical and algorithmic thinking. These skills can be valuable in various aspects of life. Additionally, it's a great hobby for creating simple games and other applications.

@Hareawda
Copy link

Hareawda commented Apr 6, 2025

While visiting family in Cairns, my older brother enthusiastically mentioned something about 25 free spins no deposit needed read more. I gave it a try out of boredom and quickly got hooked—the pokies were enjoyable and effortless, like snorkelling near the Great Barrier Reef. A few spins later, I had won enough to cover our entire family's lunch. Who knew boredom could be so rewarding?

@seversdvds
Copy link

Hey, I totally get where you're coming from — I was in the same boat not long ago, trying to find a solid platform that isn’t sketchy but still gives that thrill. After checking out a few, I landed on 1win and honestly, it’s been smooth sailing ever since. The site’s super clean, runs like a charm on both desktop and mobile, and there’s a crazy variety of games and sports to bet on — from football to e-sports, even live casino stuff that feels real AF. Plus, that juicy welcome bonus had me hooked from day one. If you're looking for a place that’s both fun and feels legit, give 1win a shot.

@jackbacklang
Copy link

The Astronaut Crash Game https://astronaut.game/ utilizes a Provably Fair mechanism, ensuring transparency and fairness in every round. This system combines a player's seed with a server seed to generate a unique hash, determining the outcome of each game. Players can verify the fairness of each round by checking the game's history and comparing the generated hash with the one provided. This feature builds trust and confidence among players, knowing that the game's results are not manipulated and are entirely based on chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment