pythondateselenium-webdriverweb-scrapingselenium-chromedriver

Error when scraping data on selection of date


Im trying to scrape excel data by clicking on multiple dropdown and picking dates in the following page. Have reproduced my python code below. The weblink I'm trying to scrape: https://www.niftyindices.com/reports/historical-data

So i first select P/E, P/B & Div.Yield values, then i select "Equity" then "NIFTY 500" in Index, then chose the from and to dates and then submit.

import os
import time
import traceback
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select, WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ✅ ChromeDriver Path
chrome_driver_path = r"C:\Users\abcd\Documents\chromedriver-win64\chromedriver.exe"

# ✅ Download directory
download_path = r"C:\Users\abcd\Downloads\Indices"

# ✅ Chrome Options
options = Options()
options.add_argument("--window-size=1920x1080")
options.add_argument("--disable-popup-blocking")
options.add_argument("--disable-blink-features=AutomationControlled")

# ✅ Initialize WebDriver
service = Service(chrome_driver_path)
service.start()
driver = webdriver.Remote(service.service_url, options=options)

driver.set_page_load_timeout(300)
wait = WebDriverWait(driver, 60)

try:
    # ✅ Open the webpage
    url = "https://www.niftyindices.com/reports/historical-data"
    print("🔹 Opening webpage...")
    driver.get(url)

    # ✅ Wait for the page to fully load
    time.sleep(5)

    # ✅ Check if there's an iframe and switch to it
    iframes = driver.find_elements(By.TAG_NAME, "iframe")
    if iframes:
        print("🔹 Switching to iframe...")
        driver.switch_to.frame(iframes[0])  # Switch to the first iframe

    # ✅ Select "P/E, P/B & Div. Yield values"
    print("🔹 Clicking Historical Menu...")
    menu_button = wait.until(EC.element_to_be_clickable((By.ID, "HistoricalMenu")))
    menu_button.click()
    time.sleep(2)

    print("🔹 Selecting 'P/E, P/B & Div. Yield values'...")
    div_yield_option = wait.until(
        EC.element_to_be_clickable((By.XPATH, "//li[contains(text(), 'P/E, P/B & Div.Yield values')]"))
    )
    div_yield_option.click()
    time.sleep(2)

    # ✅ Select "Equity" from the dropdown
    print("🔹 Selecting 'Equity' dropdown...")
    equity_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "ddlHistoricaldivtypee")))
    Select(equity_dropdown).select_by_value("Equity")
    time.sleep(2)

    # ✅ Select "NIFTY 500" from the dropdown
    print("🔹 Selecting 'NIFTY 500' dropdown...")
    index_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "ddlHistoricaldivtypeeindex")))
    Select(index_dropdown).select_by_value("NIFTY 500")
    time.sleep(2)

    # ✅ Function to Select Date
    def select_date(date_field_id, target_day, target_month, target_year):
        print(f"🔹 Selecting date: {target_day}-{target_month}-{target_year}")
    
        try:
            # ✅ Check if date picker is inside an iframe
            iframes = driver.find_elements(By.TAG_NAME, "iframe")
            if iframes:
                print(f"🔹 {len(iframes)} iframe(s) found. Switching to first iframe...")
                driver.switch_to.frame(iframes[0])
                time.sleep(2)  
    
            # ✅ Wait for the date picker field to be clickable
            date_field = wait.until(EC.element_to_be_clickable((By.ID, date_field_id)))
    
            # ✅ Scroll into view if it's off-screen
            driver.execute_script("arguments[0].scrollIntoView(true);", date_field)
            time.sleep(1)
    
            # ✅ Remove 'readonly' attribute (if applicable) to allow interaction
            driver.execute_script("arguments[0].removeAttribute('readonly');", date_field)
    
            # ✅ Click the date field to open the calendar
            date_field.click()
            time.sleep(2)  # Wait for the calendar to appear
    
            # ✅ Select the year
            year_dropdown = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "ui-datepicker-year")))
            Select(year_dropdown).select_by_value(str(target_year))
            time.sleep(1)
    
            # ✅ Select the month
            month_dropdown = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "ui-datepicker-month")))
            Select(month_dropdown).select_by_value(str(target_month - 1))  # Month values are 0-indexed
            time.sleep(1)
    
            # ✅ Select the day
            day_xpath = f"//td[@data-handler='selectDay'][@data-month='{target_month - 1}'][@data-year='{target_year}']/a[text()='{target_day}']"
            day_element = wait.until(EC.element_to_be_clickable((By.XPATH, day_xpath)))
            day_element.click()
            time.sleep(2)
    
            print(f"✅ Successfully selected {target_day}-{target_month}-{target_year}")
    
            # ✅ Switch back to default content after selection
            driver.switch_to.default_content()
    
        except Exception as e:
            print(f"❌ Error selecting date: {target_day}-{target_month}-{target_year}")
            print(traceback.format_exc())

    # ✅ Select the FROM date (01-Jan-2024)
    select_date("datepickerFromDivYield", target_day=1, target_month=1, target_year=2024)
    
    # ✅ Select the TO date (31-Jan-2025)
    select_date("datepickerToDivYield", target_day=31, target_month=1, target_year=2025)


    # ✅ Click Submit button
    print("🔹 Clicking Submit button...")
    submit_button = wait.until(EC.element_to_be_clickable((By.ID, "submit_buttonDivdata")))
    submit_button.click()

    # ✅ Wait for CSV download link
    print("🔹 Waiting for CSV download link...")
    csv_link = wait.until(EC.element_to_be_clickable((By.ID, "exporthistoricaldiv")))
    csv_link.click()

    # ✅ Wait for file download
    print("🔹 Waiting for file download...")
    time.sleep(15)

    # ✅ Verify if file is downloaded
    print("🔹 Checking downloaded files...")
    files = os.listdir(download_path)
    csv_files = [f for f in files if f.endswith(".csv")]

    if csv_files:
        print(f"✅ CSV file downloaded successfully: {csv_files[-1]}")
    else:
        print("❌ No CSV file downloaded.")

except Exception as e:
    print(f"⚠️ An error occurred: {e}")
    print(traceback.format_exc())

finally:
    driver.quit()


The error i get:

❌ Error selecting date: 1-1-2024
Traceback (most recent call last):
  File "c:\users\am364971\documents\python scripts\download_nse_indices.py", line 84, in select_date
    date_field = wait.until(EC.element_to_be_clickable((By.ID, date_field_id)))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\AM364971\AppData\Local\anaconda3\Lib\site-packages\selenium\webdriver\support\wait.py", line 146, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 


🔹 Selecting date: 31-1-2025
❌ Error selecting date: 31-1-2025
Traceback (most recent call last):
  File "c:\users\am364971\documents\python scripts\download_nse_indices.py", line 84, in select_date
    date_field = wait.until(EC.element_to_be_clickable((By.ID, date_field_id)))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\AM364971\AppData\Local\anaconda3\Lib\site-packages\selenium\webdriver\support\wait.py", line 146, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 


🔹 Clicking Submit button...
🔹 Waiting for CSV download link...
⚠️ An error occurred: Message: 

Traceback (most recent call last):
  File "c:\users\am364971\documents\python scripts\download_nse_indices.py", line 136, in <module>
    csv_link = wait.until(EC.element_to_be_clickable((By.ID, "exporthistoricaldiv")))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\AM364971\AppData\Local\anaconda3\Lib\site-packages\selenium\webdriver\support\wait.py", line 146, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:

Kindly help in debugging.


Solution

  • You are complicating the process too much. The code gets a timeout exception when it tries to select the dates.

    The problem is When you are using to scroll to the element script and this causes the element to be hidden under the header menu.

    Also, you should click on the parent div instead of the read-only input element.

    I have disabled the script lines and updated the selector for the date selection button.

    The following code downloads the CSV files.

    import os
    import time
    import traceback
    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import Select, WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    # ✅ ChromeDriver Path
    chrome_driver_path = r"C:\\Users\\abcd\\Documents\\chromedriver-win64\\chromedriver.exe"
    
    # ✅ Download directory
    download_path = r"C:\\Users\\abcd\\Downloads"
    
    # ✅ Chrome Options
    options = Options()
    options.add_argument("--window-size=1920x1080")
    options.add_argument("--disable-popup-blocking")
    options.add_argument("--disable-blink-features=AutomationControlled")
    
    # ✅ Initialize WebDriver
    service = Service(chrome_driver_path)
    service.start()
    driver = webdriver.Remote(service.service_url, options=options)
    driver.set_page_load_timeout(300)
    wait = WebDriverWait(driver, 60)
    
    try:
        # ✅ Open the webpage
        url = "https://www.niftyindices.com/reports/historical-data"
        print("🔹 Opening webpage...")
        driver.get(url)
    
        # ✅ Wait for the page to fully load
        time.sleep(5)
    
        # ✅ Check if there's an iframe and switch to it
        iframes = driver.find_elements(By.TAG_NAME, "iframe")
        if iframes:
            print("🔹 Switching to iframe...")
            driver.switch_to.frame(iframes[0])  # Switch to the first iframe
    
        # ✅ Select "P/E, P/B & Div. Yield values"
        print("🔹 Clicking Historical Menu...")
        menu_button = wait.until(EC.element_to_be_clickable((By.ID, "HistoricalMenu")))
        menu_button.click()
        time.sleep(2)
    
        print("🔹 Selecting 'P/E, P/B & Div. Yield values'...")
        div_yield_option = wait.until(
            EC.element_to_be_clickable((By.XPATH, "//li[contains(text(), 'P/E, P/B & Div.Yield values')]"))
        )
        div_yield_option.click()
        time.sleep(2)
    
        # ✅ Select "Equity" from the dropdown
        print("🔹 Selecting 'Equity' dropdown...")
        equity_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "ddlHistoricaldivtypee")))
        Select(equity_dropdown).select_by_value("Equity")
        time.sleep(2)
    
        # ✅ Select "NIFTY 500" from the dropdown
        print("🔹 Selecting 'NIFTY 500' dropdown...")
        index_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "ddlHistoricaldivtypeeindex")))
        Select(index_dropdown).select_by_value("NIFTY 500")
        time.sleep(2)
    
        # ✅ Function to Select Date
        def select_date(date_field_id, target_day, target_month, target_year):
            print(f"🔹 Selecting date: {target_day}-{target_month}-{target_year}")
        
            try:
                # ✅ Check if date picker is inside an iframe
                iframes = driver.find_elements(By.TAG_NAME, "iframe")
                if iframes:
                    print(f"🔹 {len(iframes)} iframe(s) found. Switching to first iframe...")
                    driver.switch_to.frame(iframes[0])
                    time.sleep(2)  
        
                # ✅ Wait for the date picker field to be clickable
                date_field = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, f"div.dateHolder:has(#{date_field_id})")))
        
                # ✅ Click the date field to open the calendar
                date_field.click()
                wait.until(EC.visibility_of_element_located((By.ID,"ui-datepicker-div")))  # Wait for the calendar to appear
        
                # ✅ Select the year
                year_dropdown = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "ui-datepicker-year")))
                Select(year_dropdown).select_by_value(str(target_year))
                time.sleep(1)
        
                # ✅ Select the month
                month_dropdown = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "ui-datepicker-month")))
                Select(month_dropdown).select_by_value(str(target_month - 1))  # Month values are 0-indexed
                time.sleep(1)
        
                # ✅ Select the day
                day_xpath = f"//td[@data-handler='selectDay'][@data-month='{target_month - 1}'][@data-year='{target_year}']/a[text()='{target_day}']"
                day_element = wait.until(EC.element_to_be_clickable((By.XPATH, day_xpath)))
                day_element.click()
                time.sleep(2)
        
                print(f"✅ Successfully selected {target_day}-{target_month}-{target_year}")
        
                # ✅ Switch back to default content after selection
                driver.switch_to.default_content()
        
            except Exception as e:
                print(f"❌ Error selecting date: {target_day}-{target_month}-{target_year}")
                print(traceback.format_exc())
    
        # ✅ Select the FROM date (01-Jan-2024)
        select_date("datepickerFromDivYield", target_day=1, target_month=1, target_year=2024)
        
        # ✅ Select the TO date (31-Jan-2025)
        select_date("datepickerToDivYield", target_day=31, target_month=1, target_year=2025)
    
    
        # ✅ Click Submit button
        print("🔹 Clicking Submit button...")
        submit_button = wait.until(EC.element_to_be_clickable((By.ID, "submit_buttonDivdata")))
        submit_button.click()
    
        # ✅ Wait for CSV download link
        print("🔹 Waiting for CSV download link...")
        csv_link = wait.until(EC.element_to_be_clickable((By.ID, "exporthistoricaldiv")))
        csv_link.click()
    
        # ✅ Wait for file download
        print("🔹 Waiting for file download...")
        time.sleep(15)
    
        # ✅ Verify if file is downloaded
        print("🔹 Checking downloaded files...")
        files = os.listdir(download_path)
        csv_files = [f for f in files if f.endswith(".csv")]
    
        if csv_files:
            print(f"✅ CSV file downloaded successfully: {csv_files[-1]}")
        else:
            print("❌ No CSV file downloaded.")
    
    except Exception as e:
        print(f"⚠️ An error occurred: {e}")
        print(traceback.format_exc())
    
    finally:
        driver.quit()