Skip to content

Instantly share code, notes, and snippets.

@btc100k
Last active December 21, 2024 18:46
Show Gist options
  • Save btc100k/b622a5ad8e97559f3563ad6d0308f0c3 to your computer and use it in GitHub Desktop.
Save btc100k/b622a5ad8e97559f3563ad6d0308f0c3 to your computer and use it in GitHub Desktop.
import requests
import datetime
from bs4 import BeautifulSoup
import sys
# This python script scrapes Ocean.xyz and creates a csv of the payouts to a given BTC address.
#
# This will be useful for anyone mining on Ocean.xyz who wants to keep track of their earnings in BTC or USD
#
# Example output:
# Please enter the address you're using to mine on Ocean.xyz: <3QomtEj5nfzEkxPXoVD3hvxgJDzA6M6evt>
# Row, Block_Height, Date, BTCUSD, BTC_Earned, USD_Earned, BTC_Fee, USD_Fee
# 1, 829513, 02-08-2024, $44335.00, 0.43437323, $19257.94, 0.00000000, 0.0
# 2, 829267, 02-06-2024, $42658.30, 0.35614859, $15192.69, 0.00000000, 0.0
# 3, 828232, 01-31-2024, $42937.72, 0.13227494, $5679.58, 0.00000000, 0.0
# 4, 827750, 01-28-2024, $42126.55, 0.03297256, $1389.02, 0.00000000, 0.0
#
# How it does it:
# 1. it visits Ocean.xyz and grabs your "Latest Earnings"
# 2. it takes the hash from the earning to mempool.space to get the date of the earning
# 3. it takes the date to coinbase's api to get the BTCUSD
# 4. it does the math to calculate $ earned & $ fee paid
# 5. it formats this into a nice CSV for you to import into Excel/Quickbooks/etc.
#
# Is there value here for you?
# Value 4 Value: [email protected]
#
def fetch_block_details(block_hash: str):
url = f"https://mempool.space/api/block/{block_hash}"
response = requests.get(url)
if response.status_code == 200:
data = response.json()
height = data.get('height')
timestamp = data.get('timestamp')
datetime_obj = datetime.datetime.utcfromtimestamp(timestamp)
formatted_date = datetime_obj.strftime("%m-%d-%Y")
return height, formatted_date
else:
return None, None
def get_bitcoin_price_on_date(mmddyyyy_str: str):
month, day, year = mmddyyyy_str.split("-")
date_formatted = f"{year}-{month}-{day}"
url = f"https://api.coinbase.com/v2/prices/BTC-USD/spot?date={date_formatted}"
try:
response = requests.get(url)
if response.status_code == 200:
data = response.json()
# The price is in the 'data' field, under 'amount'
btc_price = data['data']['amount']
return float(btc_price)
else:
return "Error: Unable to fetch Bitcoin price data"
except Exception as e:
return f"Error: {str(e)}"
def output_for_address(ocean_addr: str, maximum_page_number: int = 20, oldest_to_newest: bool = True):
page_index = 0
output_data = []
while page_index < maximum_page_number:
url = f"https://ocean.xyz/template/workers/earnings/rows?user={ocean_addr}&epage={page_index+1}&page={page_index}&sortParam="
page_index = page_index + 1
print(f"Working on page {page_index}")
# Fetch the webpage
response = requests.get(url)
html = response.text
# Parse the HTML
soup = BeautifulSoup(html, 'html.parser')
rows = soup.find_all("tr", class_="table-row")
if not rows:
break
for row in soup.find_all("tr", class_="table-row"):
cells = row.find_all("td", class_="table-cell")
block_hash = cells[0].get_text(strip=True).split()[0]
btc_earned = cells[2].get_text(strip=True).split()[0]
btc_fee = cells[3].get_text(strip=True).split()[0]
height, mmdddyyyy_str = fetch_block_details(block_hash)
btcusd = get_bitcoin_price_on_date(mmdddyyyy_str)
usd_earned = float(btc_earned) * float(btcusd)
usd_fee_paid = float(btc_fee) * float(btcusd)
output = (f"{height}, "
f"{mmdddyyyy_str}, "
f"${btcusd:.2f}, "
f"{btc_earned}, "
f"${usd_earned:0.2f}, "
f"{btc_fee}, "
f"{usd_fee_paid}")
output_data.append(output)
if oldest_to_newest:
output_data.reverse()
output_row_number = 1
print("Row", "Block_Height", "Date", "BTCUSD", "BTC_Earned", "USD_Earned", "BTC_Fee", "USD_Fee", sep=", ")
for one_row in output_data:
print(output_row_number, one_row, sep=", ")
output_row_number += 1
if __name__ == "__main__":
old_first = True
pages = 10
if len(sys.argv) > 1:
btc_address = sys.argv[1]
else:
btc_address = input("Please enter the address you're using to mine on Ocean.xyz: ")
#
# I'm not really documenting it, but you can pass in the # of pages to fetch in the 2nd argument
#
if len(sys.argv) > 2:
pages = int(sys.argv[2])
#
# I'm not really documenting it, but you can pass "false" as arg #3 if you want it sorted newest-to-oldest"
#
if len(sys.argv) > 3:
old_first = False if sys.argv[3].lower() == "false" else True
if len(btc_address):
print("")
output_for_address(ocean_addr=btc_address, maximum_page_number=pages, oldest_to_newest=old_first)
print("")
else:
print("\nNext time, enter a BTC address on the command line, or at the prompt. \nHappy Hashing!")
@BitcoinMechanic
Copy link

Had to change L38 from utcfromtimestamp to just datetime_obj = datetime.datetime.fromtimestamp(timestamp) because some newer version of python kept throwing horrible messages at me.

@BitcoinMechanic
Copy link

Also found it helpful to modify 83-102 to limit iterations for the latest ~3 blocks. (It'd be cool to take this in as an argument actually):

output_data = []
counter = 0
for row in earnings_table.find_all('tr')::#iterating through only three rows
    # Extract data from each cell
    cells = row.find_all('td')
    data = [cell.get_text(strip=True) for cell in cells]
    if len(data):
        block_hash = data[0]
        btc_earned = data[2].split()[0]
        btc_fee = data[3].split()[0]
        height, mmdddyyyy_str = fetch_block_details(block_hash)
        btcusd = get_bitcoin_price_on_date(mmdddyyyy_str)
        usd_earned = float(btc_earned) * float(btcusd)
        usd_fee_paid = float(btc_fee) * float(btcusd)
        output = (f"{height}, "
                  f"{mmdddyyyy_str}, "
                  f"${btcusd:.2f}, "
                  f"{btc_earned}, "
                  f"${usd_earned:0.2f}, "
                  f"{btc_fee}, "
                  f"{usd_fee_paid}")
        output_data.append(output)
        counter += 1 # incrementing the counter after each loop iteration
        if counter == 3: # exit the loop when counter reaches three
            break

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