Проблема с использованием Selenium для Chrome для поиска элемента в HTML-файле с помощью C#

Я использую Selenium для поиска элементов в HTML-документе, отображаемом в браузере Chrome. HTML создан не мной, и, похоже, у него много проблем. У меня нет возможности изменить его поколение, мне просто приходится работать с тем, что у меня есть.

Вот фрагмент HTML-кода элемента, который я пытаюсь найти по его тексту «>Общая юридическая информация по аренде».

<div class = "TableTitlebar HeaderedTableTitlebar">
<div class = "FastTitlebar">
<div class = "FastTitlebarCaptionWrapper">
<h3 id = "caption2_Dd-53" class = " FastTitlebarCaption">General Lease Legal Information</h3>
</div>

Это много уровней в очень запутанной конструкции. Я пробовал разные комбинации критериев поиска для FindElement. Я всегда получаю сообщение об ошибке «Элемент не найден».

Большая проблема заключается в том, что веб-сайт, генерирующий этот HTML-код, будет время от времени заново генерировать идентификаторы элементов при обновлении страницы. Таким образом, использование поиска по идентификатору в конечном итоге сломается. Кроме того, атрибуты, такие как имена классов, являются просто повторениями идентификаторов и не дают стабильного представления того, что представляет собой элемент.

Вот как попасть на веб-страницу. Откройте браузер и перейдите по адресу: https://oktap.tax.ok.gov/OkTAP/web?link=PUBLICPUNLKP

Установите переключатель «Поиск по PUN:». Введите значение «029-123551-0-0000» Прокрутите страницу вниз и выберите кнопку «Поиск». Чуть выше кнопки «Поиск» будет строка текста с выделенным в крайнем левом углу «029-123551-0-0000». Выберите эту ссылку. На новой странице выберите вкладку «Доступ для печати» в правой части строки меню. На новой странице прокрутите вниз, чтобы найти таблицу с общей юридической информацией по аренде.

Поскольку аннотации в HTML очень плохие, единственный способ найти следующий элемент таблицы, содержащий искомые данные, без жесткого кодирования идентификатора для поиска текста заголовка в опубликованном мной фрагменте HTML, а затем выполнить поиск первой таблицы. элемент после этого.

Это действительно беспорядок. Я не уверен, что сайт можно очистить из-за плохой конструкции HTML. Я использую C#, поскольку это уровень владения мной и другими программистами в моей компании. Я открыт для предложений о том, как найти нужный элемент, а также провести реинжиниринг всего приложения.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, в чем проблема... на этой странице МНОГО идентификаторов, и они согласованы (не случайны при каждой загрузке страницы и т. д.).

Приведенный ниже код работает в соответствии с предоставленными вами шагами и печатает все ячейки в таблице «Общая юридическая информация по аренде». Он не использует никаких идентификаторов, поскольку вы сказали, что это проблема.

IWebDriver driver = new ChromeDriver();
driver.Manage().Window.Maximize();
string url = "https://oktap.tax.ok.gov/OkTAP/web?link=PUBLICPUNLKP";
driver.Url = url;

string pun = "029-123551-0-0000";

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.ElementIsVisible(By.Id("caption2_Dd-5"))); // wait for element on page to make sure page is loaded
ReadOnlyCollection<IWebElement> inputs = driver.FindElements(By.XPath("//tr[.//span[text()='Search By PUN:']]//input"));
inputs.ElementAt(0).Click(); // Search By PUN radio button
inputs.ElementAt(1).SendKeys(pun); // Search By PUN field
driver.FindElement(By.XPath("//span[text()='Search']")).Click(); // Search button
wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//table[@data-delmsg][.//a[text()='PUN']]//td//a"))).Click(); // Click first result link
wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath("//span[text()='Printable']"))).Click(); // Click "Printable" tab

IWebElement table = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//div[contains(@class,'TableContainer')][.//h3[text()='General Lease Legal Information']]//table[contains(@class,'DocTableNormal')]")));
string headers = string.Join(",", table.FindElements(By.CssSelector("th")).Select(e => e.Text).ToArray());
Console.WriteLine(headers); // write headers

ReadOnlyCollection<IWebElement> cells = table.FindElements(By.CssSelector("td"));
string cellText = string.Join(",", cells.Select(e => e.Text).ToArray());
Console.WriteLine(cellText); // write cells

Выход

Q4,Q3,Q2,Q1,Section,Township,Range
,,,AL,36,01N,09E

Вы можете записать это в CSV-файл и открыть его как лист Excel или что-то еще, что вам нужно.

Вы можете удалить цикл row in rows, если в этой таблице есть только одна строка. Я не был уверен, поэтому на всякий случай добавил цикл.

JeffC 02.04.2024 07:44

«Большая проблема заключается в том, что веб-сайт, генерирующий этот HTML-код, будет время от времени заново генерировать идентификаторы элементов при обновлении страницы». Я предполагаю, что это кэшировано

matt sharp 02.04.2024 07:47

@mattsharp Я запускал свой код более 10 раз и ни разу не заметил, чтобы идентификаторы изменились... Я не знаю.

JeffC 02.04.2024 07:55

@mattsharp Я добавил версию, которая не использует никаких идентификаторов, если вам интересно.

JeffC 02.04.2024 08:30

Вы могли бы предположить, что он кэширован до <1 часа, так что, возможно, вы правы, или, может быть, они обновляют его при развертывании (идентификаторы восстанавливаются) или что-то в этом роде. Независимо от того, выглядит ли ваш код, он должен работать

matt sharp 02.04.2024 10:22

Идентификаторы не меняются каждый раз при перезагрузке страницы. Но в генерации HTML на стороне сервера есть что-то такое, что, как я предполагаю, в логике генерации HTML вносится корректировка, тогда в идентификаторах может произойти одно или несколько изменений. Это делает очистку движущейся целью.

BartAtRanch 02.04.2024 19:14

@BartAtRanch Понятно. Я обновил код, чтобы не использовать какие-либо идентификаторы, и он работает нормально. Вы пробовали?

JeffC 02.04.2024 19:17

Спасибо за пример кода. Использование «подождать» может помочь. Но даже в вашем «неидентификационном» коде ваши идентификаторы могут быть изменены. Значения типа «caption2_Dd-5» будут меняться при изменении идентификаторов подключенных элементов. Кроме того, различные разделы HTML настолько идентичны, без какого-либо уникального объяснения того, для чего используется элемент, что типы или классы стилей повторяются, так что при поиске можно получить любой из связанных элементов, а не тот, который вам нужен. .

BartAtRanch 02.04.2024 19:22

Затем дополнительный вопрос о том, как Selenium анализирует HTML. Судя по поведению и логике рабочего процесса в коде, который мне изначально дал первоначальный автор, похоже, что когда Selenium выполняет FindElement, он перемещает начальный указатель для следующего поиска в позицию последнего успешного поиска. Я могу с этим работать, если это так. Мне просто нужно будет строго подходить к структуре HTML. Но что произойдет с указателем начала поиска, если запрошенный элемент не будет найден?

BartAtRanch 02.04.2024 19:25

Являются ли вызовы Selenium, такие как FindElement, синхронными или асинхронными в зависимости от завершения возврата управления вызывающей программе и действий на целевой веб-странице? Я предполагаю, что асинхронно, если есть необходимость подождать. Просто хочу убедиться, что понимаю, как работает драйвер.

BartAtRanch 02.04.2024 19:29

Код не подлежит изменению идентификаторов, если я не использую какие-либо идентификаторы для поиска элементов. Вы пробовали его запустить? Это сработало?

JeffC 02.04.2024 20:30

Я не понимаю ваш второй комментарий. Весь код Selenium синхронен... выполнение кода блокируется на каждом этапе. Ожидание необходимо из-за различий во времени загрузки страниц и т. д.

JeffC 02.04.2024 20:32

Я пробую ваш код. Прекрасно работает. Ты делаешь это; wait.Until(ExpectedConditions.ElementIsVisible(By.Id("captio‌​n2_Dd-5"))); // ждем элемента на странице, чтобы убедиться, что страница загружена. Из-за изменения идентификаторов при регенерации HTML то, что изначально было «Caption2_Dd-5», когда был написан код, могло быть изменено на «Caption2_Dd-8». Такое уже случалось раньше, и я уверен, что это произойдет снова. Я обошел эту проблему, вместо того чтобы использовать элементы записи PUN в качестве цели поиска «подождать, пока не станет видимым».

BartAtRanch 03.04.2024 00:17

Я удалил первый блок кода, содержащий идентификаторы. Используйте оставшийся блок кода... он должен работать без проблем и не требует постоянного обслуживания.

JeffC 03.04.2024 00:28

Конечно... Я хотел вернуться и найти новую цель для этой проверки, в которой не использовался идентификатор. По какой-то причине мне было трудно использовать ожидания со многими элементами с идентификаторами, поэтому я просто выбрал элемент на странице, чтобы убедиться, что страница загружена и запущена с ним.

JeffC 03.04.2024 00:30

Джефф, если вы рассмотрите возможность небольшой консультационной работы, напишите по адресу [email protected].

BartAtRanch 03.04.2024 20:30

@BartAtRanch Только что отправил вам письмо.

JeffC 03.04.2024 20:40

Другие вопросы по теме