-
-
Save sashaboulouds/d6cf5e034e2a505c2337a26e76cf2a83 to your computer and use it in GitHub Desktop.
# ============================================================================= | |
# Title: DexScreener Crypto Live Prices Scraper | |
# Description: This script scrape the first 200 h6 trending Solana pairs from DexScreener β every 10 seconds | |
# Author: Sasha Bouloudnine | |
# Date: 2024-03-13 | |
# | |
# Usage: | |
# - Install websocket using `pip install websockets`. | |
# - Launch the script. | |
# | |
# ============================================================================= | |
import asyncio | |
import websockets | |
from datetime import datetime | |
import os | |
import base64 | |
import json | |
import csv | |
import time | |
def generate_sec_websocket_key(): | |
random_bytes = os.urandom(16) | |
key = base64.b64encode(random_bytes).decode('utf-8') | |
return key | |
TYPES = ['pairs', 'latestBlock'] | |
DATA = [] | |
FIELDNAMES = [ | |
"chain_id", | |
"dex_id", | |
"pair_address", | |
"token_address", | |
"token_name", | |
"token_symbol", | |
"token_m5_buys", | |
"token_m5_sells", | |
"token_h1_buys", | |
"token_h1_sells", | |
"token_h1_to_m5_buys", | |
"token_liquidity", | |
"token_market_cap", | |
"token_created_at", | |
"token_created_since", | |
"token_eti", | |
"token_header", | |
"token_website", | |
"token_twitter", | |
"token_links", | |
"token_img_key", | |
"token_price_usd", | |
"token_price_change_h24", | |
"token_price_change_h6", | |
"token_price_change_h1", | |
"token_price_change_m5" | |
] | |
async def dexscreener_scraper(): | |
headers = { | |
"Host": "io.dexscreener.com", | |
"Connection": "Upgrade", | |
"Pragma": "no-cache", | |
"Cache-Control": "no-cache", | |
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", | |
"Upgrade": "websocket", | |
"Origin": "https://dexscreener.com", | |
"Sec-WebSocket-Version": 13, | |
"Accept-Encoding": "gzip, deflate, br, zstd", | |
"Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7", | |
"Sec-WebSocket-Key": generate_sec_websocket_key() | |
} | |
uri = "wss://io.dexscreener.com/dex/screener/pairs/h24/1?rankBy[key]=trendingScoreH6&rankBy[order]=desc" | |
async with websockets.connect(uri, extra_headers=headers) as websocket: | |
while True: | |
message_raw = await websocket.recv() | |
message = json.loads(message_raw) | |
_type = message["type"] | |
assert _type in TYPES | |
if _type == 'pairs': | |
pairs = message["pairs"] | |
assert pairs | |
for pair in pairs: | |
chain_id = pair["chainId"] | |
dex_id = pair["dexId"] | |
pair_address = pair["pairAddress"] | |
assert pair_address | |
token_address = pair["baseToken"]["address"] | |
token_name = pair["baseToken"]["name"] | |
token_symbol = pair["baseToken"]["symbol"] | |
token_txns = pair["txns"] | |
token_m5_buys = token_txns["m5"]["buys"] | |
token_m5_sells = token_txns["m5"]["sells"] | |
token_h1_buys = token_txns["h1"]["buys"] | |
token_h1_sells = token_txns["h1"]["sells"] | |
token_h1_to_m5_buys = round(token_m5_buys*12/token_h1_buys, 2) if token_m5_buys else None | |
token_liquidity = pair["liquidity"]["usd"] | |
token_market_cap = pair["marketCap"] | |
token_created_at_raw = pair["pairCreatedAt"] | |
token_created_at = token_created_at_raw / 1000 | |
token_created_at = datetime.utcfromtimestamp(token_created_at) | |
now_utc = datetime.utcnow() | |
token_created_since = round((now_utc - token_created_at).total_seconds() / 60, 2) | |
token_eti = pair.get("eti", False) | |
token_header = pair.get("profile", {}).get("header", False) | |
token_website = pair.get("profile", {}).get("website", False) | |
token_twitter = pair.get("profile", {}).get("twitter", False) | |
token_links = pair.get("profile", {}).get("linkCount", False) | |
token_img_key = pair.get("profile", {}).get("imgKey", False) | |
token_price_usd = pair["priceUsd"] | |
token_price_change_h24 = pair["priceChange"]["h24"] | |
token_price_change_h6 = pair["priceChange"]["h6"] | |
token_price_change_h1 = pair["priceChange"]["h1"] | |
token_price_change_m5 = pair["priceChange"]["m5"] | |
VALUES = [ | |
chain_id, | |
dex_id, | |
pair_address, | |
token_address, | |
token_name, | |
token_symbol, | |
token_m5_buys, | |
token_m5_sells, | |
token_h1_buys, | |
token_h1_sells, | |
token_h1_to_m5_buys, | |
token_liquidity, | |
token_market_cap, | |
token_created_at, | |
token_created_since, | |
token_eti, | |
token_header, | |
token_website, | |
token_twitter, | |
token_links, | |
token_img_key, | |
token_price_usd, | |
token_price_change_h24, | |
token_price_change_h6, | |
token_price_change_h1, | |
token_price_change_m5 | |
] | |
print(token_name, token_price_usd) | |
row = dict(zip(FIELDNAMES, VALUES)) | |
DATA.append(row) | |
file_created_at = int(time.time()) | |
filename = 'dexscreener_%s.csv' % file_created_at | |
with open(filename, 'w') as f: | |
writer = csv.DictWriter(f, fieldnames=FIELDNAMES, delimiter='\t') | |
writer.writeheader() | |
for row in DATA: | |
writer.writerow(row) | |
print('done %s' % filename) | |
print('pause 10s :Β°') | |
time.sleep(10) | |
if __name__ == "__main__": | |
asyncio.run(dexscreener_scraper()) |
@Sputchik if you figure this out lmk will gladly pay you a handsome sum of $, iv been running a scanning service for a long time that depended on this WS feed.
@Sputchik if you figure this out lmk will gladly pay you a handsome sum of $, iv been running a scanning service for a long time that depended on this WS feed.
dm t.me/kufla
Does anyone have any further info on the schema?
OK. I've done it (sort of).
I worked through the data structure and manually mapped the data out of the binary format into a readable JSON format.
It's a bit messy when I get down to the links and making adjustments for tokens that are launched on moonshot, but it works.
I won't share the code here, but HMU if you want to review my work and continue to build on it.
There is a stats section at the beginning of the binary data for global tx volume. After that each token follows this format:
{
"chainId": "solana",
"dexId": "raydium",
"pairAddress": "FRsKKpxtoLjTzg45dzMvHu1EyGpU7wUvwUJDXEBxoWKk",
"baseToken": {
"address": "6gvWSka7SnJDn4mqV7Ydn4q7AyVNSo2aX4TNGjBg7Cct",
"name": "MUMMAT",
"symbol": "MUMMAT",
"decimals": 9
},
"quoteToken": {
"address": "So11111111111111111111111111111111111111112",
"name": "Wrapped SOL",
"symbol": "SOL",
"decimals": 9
},
"quoteTokenSymbol": "SOL",
"price": "0.000001850",
"priceUsd": "0.0004465",
"txns": {
"m5": {
"buys": 0,
"sells": 0
},
"h1": {
"buys": 1,
"sells": 1
},
"h6": {
"buys": 12,
"sells": 9
},
"h24": {
"buys": 4674,
"sells": 87
}
},
"buyers": {
"m5": 0,
"h1": 1,
"h6": 12,
"h24": 4663
},
"sellers": {
"m5": 0,
"h1": 1,
"h6": 8,
"h24": 72
},
"makers": {
"m5": 0,
"h1": 1,
"h6": 18,
"h24": 4725
},
"volume": {
"h1": 187.5,
"h6": 1149.02,
"h24": 36701.15
},
"volumeBuy": {
"h1": 93.87,
"h6": 820.33,
"h24": 18622.85
},
"volumeSell": {
"h1": 93.63,
"h6": 328.68,
"h24": 18078.3
},
"priceChange": {
"m5": 0,
"h1": -0.63,
"h6": 1.52,
"h24": 5.86
},
"liquidity": {
"usd": 200383.9,
"base": 224190430,
"quote": 415.56
},
"marketCap": 365385,
"fdv": 365385,
"pairCreatedAt": 1721569640000,
"cmsProfile": {
"headerId": "Dh0VAaWTabr9NBn2",
"iconId": "iloOynWhLGzK-19k",
"description": "Yo, so Mummat woke up in some dark AF pyramid. Dude gets up, shakes off the ancient dust, and starts remembering his past life of total degenerate vibes β think vices and max laziness. Heβs like, βTime to clean up my act and live straight.β\r\n\r\nAfter wandering around, Mummat finds this lit planet called Solana. It's a crazy place with dope creatures and tech that's outta this world. He soon meets the squad: Pepe, Andy, Landwolf, and Brett β the \"Boys Club.\" These guys are all about blazing up, doing lines, and trading crypto.\r\n\r\nLooks like the universe wasnβt about to let Mummat chill and go straight LMAO.",
"links": [
{
"url": "https://mummat.org/"
},
{
"type": "twitter",
"url": "https://x.com/mummatfree"
},
{
"type": "telegram",
"url": "https://t.me/MummatSolana"
}
]
},
"isBoostable": true,
"c": "a",
"a": "solamm",
"moonshot": {
"progress": 100,
"quoteMcap": 0,
"curvePos": "0",
"curveType": "",
"coefB": "",
"mcapThreshold": "0",
"creator": "2TcnXHpFJfu35xihxsGkrvyPh83sf67EXoXXXrtTJ8Ar",
"migrationDex": "raydium"
}
}
Tokens are static for all fields before and including pairCreatedAt.
After that they differ depending on token type, launchpad, etc. I've not fully mapped those fields.
Here is an example map for a pair and the data I have working:
b'\x0csolana\x0eraydium\x00XFEeo6Hof4tLCTcgbwCeJru4veVRHnXpRYzdA3accFrE3X74ZnBs4M4q2icYPLKry6RDFhCEKwgYNZAqq5Hxjkpump\x08goob\x08goob\x02\x00\x00\x00\x00\x00\x00\x18@\x00VSo11111111111111111111111111111111111111112\x16Wrapped SOL\x06SOL\x02\x00\x00\x00\x00\x00\x00"@\x06SOL\x160.000001964\x02\x120.0004781\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00$@\x00\x00\x00\x00\x00\x00(@\x00\x00\x00\x00\x00\xc0W@\x00\x00\x00\x00\x00\x00Q@\x00\x00\x00\x00\x00\xb0}@\x00\x00\x00\x00\x00@w@\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x80Q@\x00\x00\x00\x00\x00`p@\x02\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00 @\x00\x00\x00\x00\x00\x80I@\x00\x00\x00\x00\x00@n@\x02\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x000@\x00\x00\x00\x00\x00\x00W@\x00\x00\x00\x00\x00\x90u@\x02\xecQ\xb8\x1e\x85\x1be@\x023333\xb3M\xab@\x02\xcd\xcc\xcc\xcct\xfc\xf0@\x02\x85\xebQ\xb8j\xfa\x0bA\x02\x00\x02\xa4p=\n\xd7=\x8f@\x02\x00\x00\x00\x00\xd8#\xe1@\x02\x1f\x85\xebQ\xd4\x8c\xfb@\x02\x02\xecQ\xb8\x1e\x85\x1be@\x02\x1f\x85\xebQ8~\xa3@\x02{\x14\xaeG\x11\xd5\xe0@\x02\\\x8f\xc2\xf5\x00h\xfc@\x02\xe1z\x14\xaeG\xe1\xca\xbf\x02\x00\x00\x00\x00\x00\x00\x12\xc0\x02\x1f\x85\xebQ\xb8\x1e\t@\x02\xecQ\xb8\x1e\x85k \xc0\x02H\xe1z\x14\x8e\xcf\xfc@\x00\x00\x00$\xbdl\x9dA\xca\xc3B\xadiJn@\x02\x00\x00\x00\x00\xf8\x1e\x1bA\x02\x00\x00\x00\x00\xf8\x1e\x1bA\x02\x00\x00\xf2\xb8\xd62yB\x02\x01\x02\x01\x02\x01\x00\x02\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00@\x02\x0caa65ec\x00\x01\x00\x02a\x0csolamm\x02\x00\x00'
{'chainId': 'solana', 'dexId': 'raydium', 'labels': [], 'pairAddress': 'ChUNGiiC4LjHRXY1rHi8y2pGTDumyfQaEiMSdjhF8xu2', 'baseToken': {'address': 'Gg7yp9ZL4Fszk26zPmVToCvEqSXWLRR25KsgKQdFpump', 'name': 'SOL RACCOON', 'symbol': 'RACCOON', 'decimals': 6}, 'quoteToken': {'address': 'So11111111111111111111111111111111111111112', 'name': 'Wrapped SOL', 'symbol': 'SOL', 'decimals': 9}, 'quoteSymbol': 'SOL', 'price': '0.000003900', 'priceUsd': '0.0009495', 'txns': {'m5': {'buys': 92, 'sells': 79}, 'h1': {'buys': 1649, 'sells': 1248}, 'h6': {'buys': 16066, 'sells': 14433}, 'h24': {'buys': 49388, 'sells': 33272}}, 'buyers': {'m5': 81, 'h1': 1224, 'h6': 12333, 'h24': 37374}, 'sellers': {'m5': 68, 'h1': 899, 'h6': 8995, 'h24': 14724}, 'makers': {'m5': 124, 'h1': 1714, 'h6': 17118, 'h24': 38718}, 'volume': {'m5': 23324.79, 'h1': 401164.58, 'h6': 6699571.2, 'h24': 16246400.3}, 'volumeBuy': {'m5': 10799.88, 'h1': 203351.66, 'h6': 3335607.43, 'h24': 8151975.68}, 'volumeSell': {'m5': 12524.91, 'h1': 197812.91, 'h6': 3363963.76, 'h24': 8094424.61}, 'priceChange': {'m5': -3.93, 'h1': 15.67, 'h6': -54.4, 'h24': 424.0}, 'liquidity': {'usd': 152295.23, 'base': 80279977.0, 'quote': 312.4312}, 'marketCap': 949560, 'fdv': 949560, 'pairCreatedAt': 1732712673000}
did anyone found solution?
b'\n1.3.0\x08pair\x02\x0csolana\x0eraydium\x00X83G6VzJzLRCnHBsLATj94VCpRimyyqwuN6ZfL11McADLXGtDZKAqvMZMnti46ZewMiXCa4oXF4bZxwQPoKzXPFxZn\x0cnubcat\x06nub\x02\x00\x00\x00\x00\x00\x00"@\x00VSo11111111111111111111111111111111111111112\x16Wrapped SOL\x06SOL\x02\x00\x00\x00\x00\x00\x00"@\x06SOL\x140.00008376\x02\x0e0.02034\x00\x00\x00\x00\x00\x00.@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\xc0R@\x00\x00\x00\x00\x00\x00M@\x00\x00\x00\x00\x00\x10u@\x00\x00\x00\x00\x00\xc0u@\x00\x00\x00\x00\x00\xf8\x92@\x00\x00\x00\x00\x00<\x92@\x02\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x00M@\x00\x00\x00\x00\x00\xe0h@\x00\x00\x00\x00\x00\xf0\x82@\x02\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00J@\x00\x00\x00\x00\x00\xe0i@\x00\x00\x00\x00\x00\x88\x81@\x02\x00\x00\x00\x00\x00\x002@\x00\x00\x00\x00\x00@Y@\x00\x00\x00\x00\x00pu@\x00\x00\x00\x00\x00\xd0\x8d@\x02\xe1z\x14\xaeg\xec\xce@\x02\n\xd7\xa3p\xfd\x0f\xf7@\x02H\xe1z\x14+^\x13A\x02\n\xd7\xa30#g2A\x02\x02\n\xd7\xa3p=\xc2\xa8@\x02\xa4p=\n\x97\xcb\xe3@\x02\xa4p=\n#\x08\x02A\x02\xaeG\xe1z\xe7/"A\x02\x02\x1f\x85\xebQ\xd8\xbb\xc8@\x02R\xb8\x1e\x85cT\xea@\x02\xecQ\xb8\x1e3\xb4\x04A\x02\x14\xaeG\xe1^\x9e"A\x02H\xe1z\x14\xaeG\xfd\xbf\x02\x8f\xc2\xf5(\\\x8f\xe2\xbf\x02H\xe1z\x14\xaeG\x1f\xc0\x02\x85\xebQ\xb8\x1e\x85\r\xc0\x02\xe1z\x14\xce\x92=BA\x00\x00\x00\xa0\x17\x0e\x8cAH\xe1z\x14\xee4\xb3@\x02\x00\x00\x00\xb0\xfdesA\x02\x00\x00\x00\xb0\xfdesA\x02\x00\x80\xa4\x9f6\xe7xB\x02\x01\x02\x01\x0'
for this encoding?
@prodpeak , Hi, how can i contact you regarding your work?
@prodpeak , Hi, how can i contact you regarding your work?
Share your telegram username and I'll DM you
Hi, how can i contact you regarding your work?
I have been looking for an answer to this problem for a long time
v4
now that's doesn't work:')
@prodpeak hi sir please how can i joind you on telegram
@prodpeak heya, I wanna checkout your code, tele is https://t.me/stevegremory
Hi @prodpeak , were you able to find a solution to this. can i please have a look at the code my telegram is https://t.me/kratkrish
Hi, how can i contact you regarding your work?
@BOTtellegrams
I have been looking for an answer to this problem for a long time
@Sputchik if you figure this out lmk will gladly pay you a handsome sum of $, iv been running a scanning service for a long time that depended on this WS feed.