This post is obsolete as I just found out that USCF has a feature to email you when your rating changes - I mean why wouldn't they? I am leaving the post here as a reference should someone want/need to extract ratings for other players from the site. If you have a team/club and want to keep track of everyone's rating, this can be easily extended to pull the data from the site for each chess id.
Chess results take hours to days to post on the USCF site depending on when the tournament director posts the results. Instead of monitoring the site every few hours to see if there is an update, this tool polls the site every few minutes and sends you a notification when the rating changes.
This tool is VERY complicated to setup, but the basic steps are
- Create a free AWS Account (do not need a paid version)
- Create a lambda
- Enter the code below and adjust for your USCF ID
- Be ready to debug and pull your hair out - may require a degree in CS or help from a kid that knows Python
This tool meets our own needs, but If there is sufficient interest, I will make this into a web app usable by anyone and support notification via email or txt message. Send me an email if you would like to see this made into an app.
###################Begin Python Code#########################
import json
import requests
#from botocore.vendored import requests
import time
import boto3
from bs4 import BeautifulSoup, Comment
def lambda_handler(event, context):
##################
# Update slack secret key here
##################
slack_webhook_url = "https://hooks.slack.com/services/T5BND675M/B06S7UX2UCD/<SECRET KEY>"
#send_slack_notification(slack_webhook_url, "test message")
check_count(slack_webhook_url)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
# Function to send notification to Slack via webhook
def send_slack_notification(webhook_url, message):
payload = {
"text": message
}
response = requests.post(webhook_url, json=payload)
if response.status_code != 200:
print(f"Failed to send notification to Slack. Status code: {response.status_code}")
# Function to get the current count
def get_count():
####################
# Update USCF ID HERE
####################
url = "https://www.uschess.org/msa/MbrDtlTnmtHst.php?<USCF_CHESS_ID>"
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# Find all <b> tags
b_tags = soup.find_all('b')
# Iterate through <b> tags to find the one containing the desired text
for b in b_tags:
if "Events for this player since late 1991:" in b.text:
count_text = b.text
break
else:
raise ValueError("Text not found")
# Extract the count from the text
count = int(count_text.split(":")[-1].strip())
return count
def extract_detail(html_response):
# Parse the HTML
soup = BeautifulSoup(html_response, 'html.parser')
# Find the comment containing the desired detail
detail_comment = soup.find(string=lambda text: isinstance(text, Comment) and 'Detail: 1' in text)
if detail_comment:
print(detail_comment)
# Extract the detail from the comment's parent element
detail_table = detail_comment.find_parent('table')
if detail_table:
detail_rows = detail_table.find_all('tr')[2:3]
detail_string = ""
for row in detail_rows:
cells = row.find_all('td')
if cells:
end_date = cells[0].get_text().strip()
event_name = cells[1].get_text().strip()
regular_rating = cells[2].get_text().strip()
quick_rating = cells[3].get_text().strip()
blitz_rating = cells[4].get_text().strip()
detail_string += f"End Date: {end_date}\n"
detail_string += f"Event Name: {event_name}\n"
detail_string += f"Regular Rating: {regular_rating}\n"
detail_string += f"Quick Rating: {quick_rating}\n"
detail_string += f"Blitz Rating: {blitz_rating}\n"
return detail_string.strip()
else:
print("detail table not found")
else:
print("Detail not found")
return "Detail not found."
def get_count_and_table_data():
# #######################
# Set USCF ID HERE
# #######################
url = "https://www.uschess.org/msa/MbrDtlTnmtHst.php?<USCF_CHESS_ID>"
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# Get the count
b_tags = soup.find_all('b')
for b in b_tags:
if "Events for this player since late 1991:" in b.text:
count_text = b.text
break
else:
raise ValueError("Text not found")
count = int(count_text.split(":")[-1].strip())
table_data = extract_detail(response.content)
print(table_data)
return count, table_data
def store_count_to_s3(count):
# Initialize the S3 client
s3_client = boto3.client('s3')
# Specify the bucket name and object key
bucket_name = 'uscf-chess-monitor'
object_key = 'count.txt'
# Convert count to string before storing
count_str = str(count)
# Upload count to S3
s3_client.put_object(Bucket=bucket_name, Key=object_key, Body=count_str)
def retrieve_count_from_s3():
# Initialize the S3 client
s3_client = boto3.client('s3')
# Specify the bucket name and object key
bucket_name = 'uscf-chess-monitor'
object_key = 'count.txt'
try:
# Retrieve count from S3
response = s3_client.get_object(Bucket=bucket_name, Key=object_key)
count_str = response['Body'].read().decode('utf-8')
count = int(count_str)
return count
except Exception as e:
# Handle exceptions (e.g., object not found)
print(f"Error retrieving count from S3: {e}")
return None
# Function to continuously check for the count increase and send Slack notification
def check_count(webhook_url):
current_count = retrieve_count_from_s3()
if current_count == None:
message = "Failed to get current count from S3, defaulting to 0"
current_count=0
send_slack_notification(webhook_url, message)
print(message)
new_count, new_table_data = get_count_and_table_data()
print("New Count: ("+str(new_count)+") current count ("+str(current_count)+")")
if new_count > current_count:
message = f"The count has increased to {new_count}. Latest results:\n{new_table_data}"
print("Sending slack notification of new count")
print("----------------------")
print(message)
print("----------------------")
send_slack_notification(webhook_url, message)
current_count = new_count
store_count_to_s3(new_count)
###################End Python Code#########################
Create Your Own Website With Webador