Как использовать EC.presence_of_element_located((By.ID, "myDynamicElement")), кроме как указать класс, а не идентификатор
Я пытаюсь использовать Python для веб-очистки веб-сайта, который динамически загружает его HTML, используя встроенные файлы javascript, которые отображают данные как ответ в HTML. Поэтому, если я использую только BeautifulSoup, я не смогу получить эти данные, которые мне нужны, поскольку моя программа очистит их до того, как Javascript загрузит данные. Из-за этого я интегрирую библиотеку селена в свой код, чтобы моя программа ждала, пока не будет найден определенный элемент, прежде чем он очистит веб-сайт.
Изначально я сделал это:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.ID, "tabla_evolucion")))
Но вместо этого я хочу указать класс, сделав что-то вроде:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.class, "ng-binding ng-scope")))
Вот остальная часть моего кода:
driver_path = 'C:/webDrivers/chromedriver.exe'
driver = webdriver.Chrome(executable_path=driver_path)
driver.header_overrides = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36'}
url = "myurlthatIamscraping.com"
response = driver.get(url)
html = driver.page_source
characters = len(html)
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.class, "ng-binding ng-scope")))
print(html)
print(characters)
time.sleep(10)
driver.quit()
У меня это не работает, и я нигде не могу найти правильный синтаксис.
4 ответа
Соответствующий HTML помог бы нам составить более канонический ответ. Однако, чтобы начать с вашей первой строки кода:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.ID, "tabla_evolucion")))
в значительной степени законно, если вторая строка кода:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.class, "ng-binding ng-scope")))
Вызовет ошибку как:
Сообщение: недопустимый селектор: имена составных классов не разрешены
поскольку вы не можете пройти несколько классов через By.class
.
Вы можете найти подробное обсуждение в Invalid selector: составные имена классов не разрешены с использованием find_element_by_class_name с Webdriver и Python
Решение
Вам нужно позаботиться о нескольких вещах, а именно:
- Без какой-либо видимости вашего варианта использования, функционально вызывая WebDriverWait в сочетании с EC как
presence_of_element_located()
просто подтверждает присутствие элемента в дереве DOM. Предположительно, продвигаясь вперед, вам нужно получить атрибуты, напримерvalue
,innerText
и т. д., иначе вы могли бы взаимодействовать с элементом. Так что вместоpresence_of_element_located()
вам нужно использовать либоvisibility_of_element_located()
илиelement_to_be_clickable()
Вы можете найти подробное обсуждение в WebDriverWait, который не работает должным образом
Для оптимального результата вы можете объединить
ID
а такжеCLASS
атрибуты, и вы можете использовать любую из следующих стратегий локатора:С помощью
CSS_SELECTOR
:element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".ng-binding.ng-scope#tabla_evolucion")))
С помощью
XPATH
:element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//*[@class='ng-binding ng-scope' and @id='tabla_evolucion']")))
Это в документации.
Набор поддерживаемых стратегий локатора.
CLASS_NAME = 'имя класса'
CSS_SELECTOR = 'css selector'
ID = 'id'
LINK_TEXT = 'текст ссылки'
NAME = 'name'
PARTIAL_LINK_TEXT = 'частичный текст ссылки'
TAG_NAME = 'имя тега'
XPATH = 'xpath'
Примечание. В вашем коде есть не класс, а два класса. Это не сработает, если вы используетеBy.CLASS_NAME()
потому что он ожидает только одного класса. Вместо этого вам нужен селектор CSS.
EC.presence_of_element_located((By.CSS_SELECTOR, ".ng-binding.ng-scope")))
В синтаксисе селектора CSS .
указывает класс. См. Документацию W3C для получения дополнительной информации о синтаксисе селектора CSS.
У меня есть решение, попробуйте это - измените свой класс
class
к
CLASS_NAME
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.CLASS_NAME , "ng-binding ng-scope")))
попробуйте следующее:
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.CLASS_NAME, "ng-binding")))
или же
element = WebDriverWait(driver,100).until(EC.presence_of_element_located((By.CLASS_NAME, "ng-scope")))
Следует упомянуть, что вы пытаетесь передать два имени класса, т.е. ng-binding - это один класс, а ng-scope - другой.