Skip to content

Instantly share code, notes, and snippets.

@honno
Last active October 24, 2023 14:31
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.

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