Skip to content

Commit bc30417

Browse files
committed
Adds new price fetching method.
1 parent 533a37f commit bc30417

File tree

3 files changed

+119
-59
lines changed

3 files changed

+119
-59
lines changed

grc_price_utils.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import random
2+
from typing import Union
3+
4+
import requests
5+
from bs4 import BeautifulSoup
6+
7+
AGENTS = (
8+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
9+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
10+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
11+
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0",
12+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14.5; rv:128.0) Gecko/20100101 Firefox/128.0",
13+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0",
14+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15",
15+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.2592.113",
16+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.2592.113"
17+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
18+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
19+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
20+
)
21+
22+
GRC_PRICE_URLS = ("https://www.bybit.com/en/coin-price/gridcoin-research/", "https://coinstats.app/coins/gridcoin/", "https://marketcapof.com/crypto/gridcoin-research/")
23+
24+
25+
def get_grc_price_from_site() -> tuple[Union[float, None], str, list, list, list]:
26+
headers = requests.utils.default_headers()
27+
headers["User-Agent"] = random.choice(AGENTS)
28+
found_prices = []
29+
url_messages = []
30+
info_logger_messages = []
31+
error_logger_messages = []
32+
33+
for url in GRC_PRICE_URLS:
34+
try:
35+
response = requests.get(url, headers=headers, timeout=5)
36+
except requests.exceptions.Timeout as error:
37+
error_logger_messages.append(f"Error fetching stats from {url}: {error}")
38+
continue
39+
40+
soup = BeautifulSoup(response.content, "html.parser")
41+
42+
if url == "https://www.bybit.com/en/coin-price/gridcoin-research/":
43+
pre_price = soup.find("div", attrs={"data-cy": "coinPrice"})
44+
45+
if pre_price is not None:
46+
try:
47+
price = pre_price.text.replace("$", "").strip()
48+
float_price = float(price)
49+
found_prices.append(float_price)
50+
info_logger_messages.append(f"Found GRC price of {float_price} from {url}")
51+
except Exception:
52+
url_messages.append(f"Error getting info from {url}")
53+
else:
54+
url_messages.append(f"Error getting info from {url}")
55+
elif url == "https://coinstats.app/coins/gridcoin/":
56+
pre_price = soup.find("div", class_="CoinOverview_mainPrice__YygaC")
57+
58+
if pre_price is not None:
59+
try:
60+
price = pre_price.p.text.replace("$", "").strip()
61+
float_price = float(price)
62+
found_prices.append(float_price)
63+
info_logger_messages.append(f"Found GRC price of {float_price} from {url}")
64+
except Exception:
65+
url_messages.append(f"Error getting info from {url}")
66+
else:
67+
url_messages.append(f"Error getting info from {url}")
68+
elif url == "https://marketcapof.com/crypto/gridcoin-research/":
69+
pre_pre_price = soup.find("div", class_="price")
70+
71+
if pre_pre_price is not None:
72+
pre_price = pre_pre_price.find(string=True, recursive=False)
73+
74+
if pre_price is not None:
75+
try:
76+
price = pre_price.replace("$", "").strip()
77+
float_price = float(price)
78+
found_prices.append(float_price)
79+
info_logger_messages.append(f"Found GRC price of {float_price} from {url}")
80+
except Exception:
81+
url_messages.append(f"Error getting info from {url}")
82+
else:
83+
url_messages.append(f"Error getting info from {url}")
84+
else:
85+
url_messages.append(f"Error getting info from {url}")
86+
87+
if len(found_prices) > 0:
88+
table_message = f"Found GRC price {sum(found_prices) / len(found_prices)}"
89+
return sum(found_prices) / len(found_prices), table_message, url_messages, info_logger_messages, error_logger_messages
90+
91+
table_message = "Unable to find GRC price"
92+
return None, table_message, url_messages, info_logger_messages, error_logger_messages

main.py

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from requests.auth import HTTPBasicAuth
2727
from typing import List, Union, Dict, Tuple, Set, Any
2828
import sys, signal
29+
from grc_price_utils import get_grc_price_from_site
2930

3031
# This is needed for some async stuff
3132
import nest_asyncio
@@ -145,20 +146,6 @@
145146
) # Keeps cache of saved stats databases so we don't write more often than we need too
146147
# Dictionary for places we query in format key=url, value=Tuple[nickname,regex].
147148
# Note they all must match group 2
148-
PRICE_URL_DICT: Dict[str, Tuple[str, Union[str, re.Pattern]]] = {
149-
"https://finance.yahoo.com/quote/GRC-USD/": (
150-
"yahoo.com",
151-
r'(data-field="regularMarketPrice" data-trend="none" data-pricehint="\d" value=")(\d*\.\d*)',
152-
),
153-
"https://www.coingecko.com/en/coins/gridcoin-research": (
154-
"coingecko",
155-
re.compile(
156-
r'(data-coin-id="243" data-coin-symbol="grc" data-target="price.price">\$)(\d*\.\d*)(</span>)',
157-
flags=re.MULTILINE | re.IGNORECASE,
158-
),
159-
),
160-
}
161-
162149

163150
def resolve_url_database(url: str) -> str:
164151
"""
@@ -190,7 +177,7 @@ def resolve_url_database(url: str) -> str:
190177
from config import *
191178
except Exception as e:
192179
print("Error opening config.py, using defaults! Error is: {}".format(e))
193-
# Import addl user settings from user_config
180+
# Import additional user settings from user_config
194181
if os.path.isfile("user_config.py"):
195182
try:
196183
from user_config import * # You can ignore an unresolved reference error here in pycharm since user is expected to create this file
@@ -982,48 +969,28 @@ def get_grc_price(sample_text: str = None) -> Union[float, None]:
982969
Raises:
983970
Exception: An error occurred accessing an online GRC price source.
984971
"""
985-
import requests as req
972+
price, table_message, url_messages, info_log_messages, error_log_messages = get_grc_price_from_site()
986973

987-
found_prices = []
988-
headers = req.utils.default_headers()
989-
headers.update(
990-
{
991-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
992-
}
993-
)
994-
for url, info in PRICE_URL_DICT.items():
995-
regex = info[1]
996-
name = info[0]
997-
resp = ""
998-
if sample_text:
999-
resp = sample_text
1000-
else:
1001-
try:
1002-
resp = req.get(url, headers=headers).text
1003-
except Exception as e:
1004-
log.error("Error fetching stats from {}: {}".format(name, e))
1005-
regex_result = re.search(regex, resp)
1006-
if regex_result:
1007-
try:
1008-
answer = float(regex_result.group(2))
1009-
except Exception as e:
1010-
DATABASE["TABLE_STATUS"] = "Error getting info from {}".format(name)
1011-
print_and_log("Error getting info from {}".format(name), "ERROR")
1012-
else:
1013-
log.info("Found GRC price of {} from {}".format(answer, name))
1014-
found_prices.append(answer)
1015-
else:
1016-
DATABASE["TABLE_STATUS"] = "Error getting info from {}".format(name)
1017-
print_and_log("Error getting info from {}".format(name), "ERROR")
1018-
# Return average of all found prices
1019-
if len(found_prices) > 0:
1020-
DATABASE["TABLE_STATUS"] = "Found GRC price {}".format(
1021-
sum(found_prices) / len(found_prices)
1022-
)
1023-
return sum(found_prices) / len(found_prices)
1024-
else:
1025-
DATABASE["TABLE_STATUS"] = "Unable to find GRC price"
1026-
return None
974+
for log_message in info_log_messages:
975+
log.info(log_message)
976+
977+
for log_message in error_log_messages:
978+
log.error(log_message)
979+
980+
if price:
981+
DATABASE["TABLE_STATUS"] = table_message
982+
983+
for url_message in url_messages:
984+
print_and_log(url_message, "ERROR")
985+
986+
return price
987+
988+
DATABASE["TABLE_STATUS"] = table_message
989+
990+
for url_message in url_messages:
991+
print_and_log(url_message, "ERROR")
992+
993+
return DATABASE.get("GRCPRICE", 0)
1027994

1028995

1029996
def get_approved_project_urls_web(query_result: str = None) -> Dict[str, str]:
@@ -2460,8 +2427,8 @@ def print_table(
24602427
bottom_bar_2 = left_align("Info: {}".format(status), total_len=60, min_pad=1)
24612428
bottom_bar_3 = (
24622429
left_align(
2463-
"GRC Price: {:.4f}".format(DATABASE.get("GRCPRICE", 0.00000)),
2464-
total_len=17,
2430+
"GRC Price: {:.6f}".format(DATABASE.get("GRCPRICE", 0.00000)),
2431+
total_len=19,
24652432
min_pad=1,
24662433
)
24672434
+ "*"

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ typing
1414
urllib3
1515
xmltodict
1616
zope.interface
17-
nest-asyncio
17+
nest-asyncio
18+
beautifulsoup4

0 commit comments

Comments
 (0)