'Selenium can't locate an element that is on web page

Parts of code that work: I enter the USGS site and go to the latest earthquakes page. Now what I want to do is download the csv file of latest earthquakes. The download button is at the end of the page and when I run the script it returns selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element. Any ideas how to fix this are welcome. Thanks in advance

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

ser = Service('C:\\chromedriver.exe')
opt = webdriver.ChromeOptions()

web = webdriver.Chrome(service=ser, options=opt)
web.get('https://www.usgs.gov/')

web.find_element(by=By.CSS_SELECTOR, value= '#block-tools > div > p > a:nth-child(1)').click()
web.maximize_window()

web.find_element(by=By.CSS_SELECTOR, value= 'body > usgs-root > div > usgs-list > cdk-virtual-scroll-viewport > div.cdk-virtual-scroll-content-wrapper > usgs-download-button > div > button > span.mat-button-wrapper').click()

downloadCsv = web.find_element(by=By.CSS_SELECTOR, value='#mat-dialog-1 > usgs-download-options > div.mat-dialog-content > ul > li:nth-child(2) > a')
downloadCsv.click()


Solution 1:[1]

you need to wait for the element to load, with a explicit wait or you can add an implicit wait web.implicitly_wait(10) you can use sleep(10) to test if it is the problem

see https://selenium-python.readthedocs.io/waits.html'

also, you need to switch to the new tab

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# used this lib to update my chrome driver automatically
from webdriver_manager.chrome import ChromeDriverManager

opt = webdriver.ChromeOptions()

web = webdriver.Chrome(ChromeDriverManager().install(), options=opt)
web.get('https://www.usgs.gov/')


try:
    web.maximize_window()
    element = WebDriverWait(web, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#block-tools > div > p > a:nth-child(1)'))
    )
    element.click()

    # after click you need to switch to the new tab
    web.switch_to.window(web.window_handles[1])

    element = WebDriverWait(web, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, 'body > usgs-root > div > usgs-list > cdk-virtual-scroll-viewport > div.cdk-virtual-scroll-content-wrapper > usgs-download-button > div > button > span.mat-button-wrapper'))
    )
    element.click()

    # your css selector did not work so I changed it

    element = WebDriverWait(web, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, 'usgs-download-options > div.mat-dialog-content > ul > li:nth-child(2) > a'))
    )
    element.click()
finally:
    web.quit()

P.S. If your whole selenium is just for this I think you can use a much more simple and faster script to download the CSV direct, as the CSV as a direct download link,, except i missing something

import csv
import requests

CSV_URL = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.csv'

with requests.Session() as s:
    download = s.get(CSV_URL)

    decoded_content = download.content.decode('utf-8')

    cr = csv.reader(decoded_content.splitlines(), delimiter=',')
    my_list = list(cr)
    for row in my_list:
        print(row)

#             or write to file
    local_filename = CSV_URL.split('/')[-1]

    with open(local_filename, 'wb') as f:
        for chunk in download.iter_content(chunk_size=8192):
            # If you have chunk encoded response uncomment if
            # and set chunk_size parameter to None.
            # if chunk:
            f.write(chunk)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1