Mastering Python and Selenium: A Simple Guide to Scraping Anytime Touchdown Scorers from FanDuel and DraftKings


Summary

This article provides a comprehensive guide on mastering Python and Selenium to scrape touchdown scorer data from popular sports betting platforms, highlighting its significance for sports analysts and enthusiasts alike. Key Points:

  • Selenium is a powerful tool for scraping dynamic websites like FanDuel and DraftKings, enabling efficient data extraction despite heavy JavaScript usage.
  • Understanding key data points such as player stats, team performance, and betting odds is essential for analyzing touchdown scorers effectively.
  • Data cleaning and preprocessing are crucial steps to ensure accuracy and consistency in your analysis, including addressing missing values and formatting issues.
Overall, this guide equips you with the knowledge to ethically scrape valuable data while ensuring compliance with platform policies.

Today, we will be analyzing both FanDuel and DraftKings to identify positive expected value (EV) bets for the opening Sunday of the NFL season.
Key Points Summary
Insights & Summary
  • Sports betting involves predicting sports outcomes and placing wagers on them.
  • It is one of the most popular forms of gambling worldwide.
  • Various platforms offer live betting, allowing users to place bets as events unfold.
  • Different states in the US have distinct regulations regarding online and mobile sports betting.
  • Users can bet on a wide range of sports, including horse racing, AFL, rugby, and more.
  • Many sportsbooks provide apps for easy access to odds and features.

Sports betting is an exciting way for fans to engage with their favorite games by predicting outcomes and placing bets. With various platforms available today, it has become easier than ever to join in on the action. Whether you`re at home or on the go, there`s always an opportunity to get involved and perhaps even win some money while enjoying the thrill of the game.

Extended Comparison:
PlatformSports OfferedLive Betting OptionsMobile App AvailabilityRegulatory Compliance
FanDuelNFL, NBA, MLB, NHL, College SportsYesiOS and Android Apps AvailableFully compliant in states like NJ, PA, IL
DraftKingsNFL, NBA, MLB, NHL, Soccer, GolfYesiOS and Android Apps AvailableFully compliant in states like CO, IN, WV
BetMGMNFL, NBA, MLB, NHL, TennisYesiOS and Android Apps AvailableFully compliant in states like NV, NJ
Caesars SportsbookNFL, NBA, MLB, NHL,Yes iOS and Android Apps Available Fully compliant in states like NJ
PointsBet NFL,NBA ,MLB ,NHL Yes iOS and Android Apps Available Fully compliant in states like IL

As previously noted, we will utilize Selenium to gather the betting odds. First, let's import the essential libraries and establish two driver methods, allowing us to scrape data from both FanDuel and DraftKings simultaneously. Be sure to update service = Service(executable_path=r'PATH') with your specific path for the ChromeDriver.
from supabase import create_client import json import pandas as pd from datetime import date import statsmodels import numpy as np import datetime from datetime import datetime import time import pandas as pd import numpy as np import math #The Python math module from scipy import stats #The SciPy stats module import time from selenium import webdriver from selenium.webdriver import ChromeOptions from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from webdriver_manager.chrome import ChromeDriverManager import time from selenium.webdriver.common.keys import Keys from pybettor import implied_prob  def driver_code():     options = ChromeOptions()     service = Service(executable_path=r'PATH')      useragentarray = [         "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.76 Mobile Safari/537.36"     ]      options.add_argument("--disable-blink-features=AutomationControlled")     options.add_argument("--no-sandbox")     options.add_argument("--disable-dev-shm-usage")     options.add_argument("--disable-search-engine-choice-screen")     # options.add_argument(f"--user-data-dir=./profile{driver_num}")      options.add_experimental_option("excludeSwitches", ["enable-automation"])     options.add_experimental_option("useAutomationExtension", False)     options.add_argument("disable-infobars")     options.add_argument("disable-blink-features=AutomationControlled")      driver = webdriver.Chrome(         options=options     )     driver.execute_script(         "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"     )      driver.execute_cdp_cmd(         "Network.setUserAgentOverride", {"userAgent": useragentarray[0]}     )      options.add_argument("--disable-popup-blocking")     #     driver.execute_script(     #         """setTimeout(() => window.location.href="https://www.bet365.com.au", 100)"""     #     )     driver.get("https://sportsbook.fanduel.com")     time.sleep(1)     return driver  def driver_codeDK():     options = ChromeOptions()     service = Service(executable_path=r'PATH')      useragentarray = [         "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.76 Mobile Safari/537.36"     ]      options.add_argument("--disable-blink-features=AutomationControlled")     options.add_argument("--no-sandbox")     options.add_argument("--disable-dev-shm-usage")     options.add_argument("--disable-search-engine-choice-screen")     # options.add_argument(f"--user-data-dir=./profile{driver_num}")      options.add_experimental_option("excludeSwitches", ["enable-automation"])     options.add_experimental_option("useAutomationExtension", False)     options.add_argument("disable-infobars")     options.add_argument("disable-blink-features=AutomationControlled")      driver = webdriver.Chrome(         options=options     )     driver.execute_script(         "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"     )      driver.execute_cdp_cmd(         "Network.setUserAgentOverride", {"userAgent": useragentarray[0]}     )      options.add_argument("--disable-popup-blocking")     #     driver.execute_script(     #         """setTimeout(() => window.location.href="https://www.bet365.com.au", 100)"""     #     )     driver.get("https://sportsbook.draftkings.com/event/ten-titans-%40-chi-bears/30568594?category=odds&subcategory=td-scorers")     time.sleep(1)     return driver

Set up two drivers
driver = driver_code() driverDK = driver_codeDK()

Now, let's develop a function that transforms American odds into decimal odds, as I believe they are easier to interpret. If you prefer to keep the odds in their American format, you can skip this step.
def american_to_decimal(american_odds):     try:         # Ensure the odds are numeric by converting strings to integers         american_odds = int(american_odds)          # Convert American odds to Decimal format         if american_odds > 0:             return (american_odds / 100) + 1         else:             return (100 / abs(american_odds)) + 1     except ValueError:         # If conversion to integer fails (for example if it's NaN or a non-numeric string)         return None

To begin, both drivers should navigate to the game that you wish to scrape. In FanDuel, locate the TD Scorer Props section and then click on Under Touchdown scorers before selecting Show More.

To find TD Scorers, navigate through DK.

When working on DK, it's essential to verify that each player has three sets of odds available. This is where it gets a bit tricky. I am implementing a hardcoded list comprehension to organize the data by Market Name, Player Name, and Odds for First TD, Anytime, and 2+ TDs. If any player lacks all three sets of odds, we will eliminate that player along with their corresponding odds by using their specific position in the list.
del data[-13:]

In certain edge cases, you can simply execute the following code to gather data and categorize it into three distinct lists for most games.
table = driverDK.find_elements(             By.CSS_SELECTOR, ".cb-market__template.cb-market__template--4-columns"         ) for i in table:     res_list = i.text.splitlines()      data = res_list data while 'No Touchdown Scorer' in data:     index = data.index('No Touchdown Scorer')     del data[index:index + 2]  # Remove the element and its following price  markets = data[:3]  # First 3 elements are market names players = data[3::4]  # Every 4th element starting from the 4th is a player name prices = [data[i:i + 3] for i in range(4, len(data), 4)]  # Prices come in sets of 3 for each player  print("Markets:", markets) print("Players:", players) print("Prices:", prices)

Carry out the same procedure for the FD odds.
table = driver.find_elements(             By.CSS_SELECTOR, ".am.an.ao.ap.cl.cv.af.fl.s.hk.hl.bl.h.i.j.ah.ai.m.aj.o.ak.q.al"         ) for i in table:     res_listFD = i.text.splitlines()      dataFD = res_listFD dataFD  while 'No Touchdown Scored' in dataFD:     index = dataFD.index('No Touchdown Scored')     del dataFD[index:index + 3]  marketsFD = dataFD[:3]  playersFD = dataFD[3::4]  pricesFD = [dataFD[i:i + 3] for i in range(4, len(dataFD), 4)]   print("Markets:", marketsFD) print("Players:", playersFD) print("Prices:", pricesFD)

The data for DK should be presented in the following manner.

And for FD

Next, let's merge all of our individual lists into a single dataframe.
df_dk = pd.DataFrame(prices, index=players, columns=[market + " DK" for market in markets])  # Convert FD data into DataFrame df_fd = pd.DataFrame(pricesFD, index=playersFD, columns=[market + " FD" for market in marketsFD])  # Merge both DataFrames on player names, using outer join to retain all players df_combined = pd.merge(df_dk, df_fd, left_index=True, right_index=True, how='outer') df = df_combined.applymap(lambda x: x.replace('+', '') if isinstance(x, str) else x)

To translate American odds into decimal format, simply execute the following code.
df_decimal = df.applymap(american_to_decimal)  # Show the converted dataframe df_decimal

Let's compile the roster of players.
players = list(df_decimal.index.values)

Next, let's analyze the odds from both DraftKings and FanDuel to identify Positive EV Opportunities. We will examine each row of the dataframe; whenever there are valid values, we can extract the implied probabilities derived from decimal odds (for those using American odds, simply adjust category="dec" to category="us"). After converting these implied probabilities into floating-point numbers, we will determine the minimum and maximum values before calculating their difference. If this difference exceeds 0.05—indicating that the implied probabilities vary by more than 5%—we will consider this selection as noteworthy. Feel free to modify this threshold if you wish to filter results based on a higher or lower criterion.
for index, row in df_decimal.iterrows():     dkValue = row['ANYTIME TD SCORER DK']     fdValue = row['ANY TIME FD']     if(pd.notnull(dkValue) and pd.notnull(fdValue)):         dkImpliedProb = implied_prob(dkValue, category="dec")         fdImpliedProb = implied_prob(fdValue, category="dec")         floatdkImpliedProb = float(dkImpliedProb[0])         floatfdImpliedProb = float(fdImpliedProb[0])         minValue = min(floatdkImpliedProb,floatfdImpliedProb)         maxValue = max(floatdkImpliedProb,floatfdImpliedProb)         subtractionTemp = maxValue - minValue         if(subtractionTemp > 0.05):             if(maxValue == dkValue):                 print("Selection: Anytime Toucdown Scorer " + index)                 print(f"+EV Opportunity exists on DraftKings @ Odds {dkValue} Implied Probability is {floatdkImpliedProb}")                 print(f"FanDuel Odds: {fdValue} Implied Probability is {floatfdImpliedProb}")                 print()                 print("             ")             else:                 print("Selection: Anytime Touchdown Scorer " + index)                 print(f"+EV Opportunity exists on Fanduel @ Odds {fdValue} Implied Probability is {floatfdImpliedProb}")                 print(f"DraftKings Odds: {dkValue} Implied Probability is {floatdkImpliedProb}")                 print("           ")     else:         continue

The expected output should display the following data

Understanding Expected Value (EV) and Arbitrage Opportunities in Sports Betting

To enhance the understanding of sports betting strategies, it is crucial to delve into the concept of Expected Value (EV) in calculations. A "+EV Opportunity" signifies that a bet has a favorable expected outcome based on statistical analysis.

**1. Understanding the EV Calculation:** To properly calculate EV, one must consider several key components:

* **Implied Probability:** Sportsbooks provide odds that can be converted into implied probabilities. This conversion involves determining how likely an event is to occur based on the odds offered; for example, fractional odds of 2/1 imply a probability of 33.33% (1/(2+1)).

* **True Probability:** Bettors often assess the true probability of an event through various analytical techniques, including historical performance data, player statistics, and situational factors. This estimation may differ from the implied probability provided by sportsbooks.

* **EV Formula:** The basic formula for calculating Expected Value is:
\[
EV = (Probability\ of\ Winning \times Amount\ Won) - (Probability\ of\ Losing \times Amount\ Lost)
\]
This formula helps bettors identify whether a particular wager presents a positive value opportunity.

**2. Arbitrage Opportunities:** Finding arbitrage opportunities requires monitoring multiple sportsbooks due to varying odds they offer:

* **Arbitrage Definition:** Arbitrage in sports betting occurs when discrepancies between bookmakers’ odds allow bettors to place wagers on all possible outcomes and guarantee profit regardless of which outcome prevails.

* **Tools for Finding Arbitrage:** There are specialized tools like arbitrage calculators and websites designed to identify these profitable scenarios swiftly. Given that sports betting odds fluctuate constantly, acting quickly upon identifying an arbitrage opportunity is vital for securing guaranteed profits.
Rams @ Detroit
Selection: Anytime Touchdown Scorer Jared Goff
There’s a positive expected value opportunity on FanDuel with odds of 14.0, translating to an implied probability of approximately 7.14%. In contrast, DraftKings offers odds of 5.0, which corresponds to an implied probability of 20%.

Thank you for taking the time to read this. If you encounter any issues or have questions, feel free to leave a comment or reach out to me on X @PaulConish. If you enjoyed this content, please give it a clap! Wishing everyone a fantastic football season ahead!

References

TSLC - 台灣運彩官網

Live Betting · Game Results · Statistics · Membership · Betting News · Betting Results ... Taiwan Sports Lottery Company All Rights Reserved. Version: 1.6.2. ↑

Source: 運彩

Online Sports Betting & Live Betting Odds at SportsBetting.ag

SportsBetting.ag is the leading sports betting site in the industry bringing you the best odds for betting on sports online.

Source: Sports Betting.ag

Sports betting

Sports betting is the activity of predicting sports results and placing a wager on the outcome. Odds boards in a Las Vegas sportsbook.

Source: Wikipedia

Interactive U.S. Map: Sports Betting

Interactive US Map: Sports Betting. State-level detail on types of wagering allowed, key regulations, legal retail and online/mobile ...

Sports betting | Definition & History

Sports betting is a form of gambling that involves wagering on sports. It is one of the most popular forms of gambling. The growth of ...

Source: Britannica

Best Online Horse Racing and Sports Betting | Sportsbet

Bet on horse racing, AFL, rugby and other events with Sportsbet. Download the App & Get Access to Tons of Great Betting Features.

Source: Sportsbet

888 Sport: Sports Betting Odds | Bet on Sports Online

In-play betting and our mobile app. 888sport provides live sport odds for numerous events and fixtures, as they happen – every day.

Source: 888 Sport

Online Sports Betting & Parlays at BetMGM Online Sportsbook | BetMGM

Discover the best online sports betting and parlays at BetMGM Online Sportsbook. Get live odds and bet on your favorite sports today! ...

Source: BetMGM

SB

Experts

Discussions

❖ Columns