Страницы

Поиск по вопросам

Показаны сообщения с ярлыком xpath. Показать все сообщения
Показаны сообщения с ярлыком xpath. Показать все сообщения

воскресенье, 29 марта 2020 г.

Определить xpath locator элемента на странице

#python #selenium #xpath




Мне нужно проверить/убедиться, что текст "(carrier specific)" существует и лежит
в нужном месте.

Я делаю

try: self.assertEqual("(carrier specific)", sel.get_table("//form/fieldset[4]/table.2.1"))


но он никак не хочет "подцепить" этот текст (обращается к пустому полю National prefix,
но не к тексту сразу за ним). Мне нужно как-то определить локейшн этого текста на страничке,
т.е. обратиться к этому элементу через xpath/css.

Dialing Location


Ответы

Ответ 1



xpath для получения текста из описанной вами ноды: //input[@name='dl-ntp']/../text()[boolean(string-length(normalize-space(.)))] xpath для проверки совпадения ожидаемого текста в описанной ноде: //input[@name='dl-ntp']/ancestor::*[1][contains(.,'carrier specific')] Если используете python, то может пригодиться: driver.execute_script("return document.evaluate('//input[@name='dl-ntp']/../text()[boolean(string-length(normalize-space(.)))]', document, null, XPathResult.ANY_TYPE, null).iterateNext().data")

среда, 26 февраля 2020 г.

Как поснимать checkbox

#html #python_3x #selenium #selenium_webdriver #xpath


Имеется Чек Бокс вот такого вида, как на него нажать, при помощи, Python + Selenium?    



    


Ответы

Ответ 1



Альтернативный, более лаконичный, и, кстати, быстрый способ нахождения этого элемента - это "by css selector": checkbox = browser.find_by_css_selector("input[testid=ns-chbox]") checkbox.click()

Ответ 2



checkbox1 = browser.find_element_by_xpath("//input[@testid='ns-chbox']") checkbox1.click()

суббота, 8 февраля 2020 г.

Xpath text()

#xpath


Здравствуйте.
Подскажите как мне найти тег по тексту внутри, если часть информации динамическая.
Я понимаю как найти статику:

    Ссылка


Xpath:
//body/a[text()="Ссылка"]

А если я знаю только часть текста?
Спасибо.    


Ответы

Ответ 1



Так: //body/a[text()[contains(.,'Ссылка')]]

Ответ 2



Можно воспользоваться следующим вариантом, он производит поиск всех тэгов "а", которые содержать "часть текста" //a[contains(text(),'часть текста')]

воскресенье, 2 февраля 2020 г.

c# Net core Поиск номера строки ошибки в файле XML, имея путь к тегу (cases XPath, Regex, JSON?)

#c_sharp #регулярные_выражения #json #xpath #net_core


Здравствуйте. Ситуация: есть модель(дисериализованный файл), довольно большая. В
ней много строк и вложенных объектов. (Модель YML каталога).

[XmlRoot("yml_catalog")]
public class YMLCatalog
{
    /// 
    /// Дата и время генерации YML файла на стороне магазина
    /// 
    [Required]
    [XmlAttribute("date")]
    public string Date { get; set; }

    /// 
    /// Магазин
    /// 
    [Required]
    [ValidateObject]
    [XmlElement(ElementName = "shop")]
    public Shop Shop { get; set; }
}

/// 
/// Точка продаж
/// https://yandex.ru/support/webmaster/goods-prices/technical-requirements.html
/// 
public class Shop
{
    /// 
    /// Название магазина.
    /// 
    [Required]
    [XmlElement("name")]
    public string Name { get; set; }

    /// 
    /// Название компании
    /// 
    [Required]
    [XmlElement("company")]
    public string Company { get; set; }
    ... и тд.
}


При валидации модели, в случае ошибки, я получаю (при помощи магии. См. краткое описание
в комментариях) путь к ошибке. Например для YML файла с ошибкой в теге price, 0го оффера,
в виде отсутствия цены, я получаю путь: shop/offers/offer['0 или 1', смотря как удобнее.
Для XPath лучше 1]/price Value: Текст ошибки. (Value - поле со значением тега, аналогично
может быть для атрибутов)

Нас интересует: shop/offers/offer[0]/price

По этому пути, мне нужно определить номер строки, где находиться этот тег. Чтобы
указать пользователю где ошибка.

Что я пробовал:

1) Сделал через  регулярные выражения. Сначала последовательно нахожу индекс элементов
по пути, как получу индекс начала тега Price в файле. Затем собираю список строк в
файле и нахожу номер строки для вывода, относительно всего файла. - Это работает, но
меня не устраивает. Слишком медленно, а у меня могут быть очень большие файлы

2) Попробовал сделать через XPath. Т.е например можно легко получить элемент тега
вот так: 

XmlDocument document = new XmlDocument();
document.LoadXml(text);
var node = document.SelectSingleNode("//shop/offers/offer[1]/price");// это для примера


3) Есть вариант с созданием своего дессериализатора + атрибутов валидации для него,
чтобы к каждому полю в модели приписывать в метаданных IXmlLineInfo - который в стандартном
XmlSerializer к сожалению используется только при выдаче информации об ошибке - но
это долго, а те готовые, что я нашел, не поддерживаются в net core... UPD: также в
таком случае требуется поддержка не только составных объектов, но и простых + простых
атрибутов (string, int, long и тп)

Вопрос 1: XPath как-нибудь позволяет получить кол-во элементов выше (или лучше их
список)  ? Вроде комбинировать preceding и ancestor нельзя (ссылка) - Но опять же,
даже если это получиться, придется искать индекс, создавая список строк файла. - Не
очень хорошо, хотелось бы узнать номер строки ошибки другим способом

Пробовал "//shop/offers/offer[ 1 ]/price/preceding::*", но в таком случае игнорируются
все элементы выше shop, почему не знаю. (когда использовал count(...), получал 27 элементов)
- Думаю это всяко лучше только регулярных выражений

Знаете еще способ? Прошу в ответы:)

Главный вопрос: Так как лучше всего найти номер строки ошибки, имея XML и путь к тегу?

P.S Производительность решения приветствуется)
    


Ответы

Ответ 1



Не выдержал, решил дать свой ответ. Во-первых, XmlSerializer выдаёт ошибку не только при ошибке синтаксиса XML (например, незакрытый тег), но и в том случае, если тип данных не соответствует ожидаемому (например, свойство Price имеет тип decimal, а в узле Price пусто или нечисловая строка). При этом в выбрасываемом исключении содержится сообщение, содержащее номер и позицию ошибки: В документе XML (4, 18) присутствует ошибка. На мой взгляд, это уже фактически решает вопрос. Строка с ошибкой известна, можно её исправлять. Чуть погуглив, я легко выяснил, что для документов YML имеется схема. Скачать её можно здесь. При валидации по схеме будет выдаваться описание ошибки наподобие следующего: Элемент "Price" недействителен: значение "" недействительно с точки зрения его типа данных "http://www.w3.org/2001/XMLSchema:decimal" - Строка "" не является допустимым значением Decimal. Это даёт огромное удобство: пользователь легко поймёт и исправит ошибку. Сама валидация делается в несколько строк: var xs = new XmlSerializer(typeof(Test)); var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; var schemas = new XmlSchemaSet(); schemas.Add(null, "schema.xsd"); settings.Schemas = schemas; settings.ValidationEventHandler += Settings_ValidationEventHandler; using (var xr = XmlReader.Create("test.xml", settings)) //while (xr.Read()) ; item = (Test)xs.Deserialize(xr); private void Settings_ValidationEventHandler(object sender, ValidationEventArgs e) { Console.WriteLine(e.Severity); Console.WriteLine(e.Message); Console.WriteLine(e.Exception.LineNumber + " " + e.Exception.LinePosition); } В данном коде валидация происходит в процессе чтения xml. То есть нет лишних проходов/загрузок, всё максимально эффективно по скорости и объёму памяти. Если нужно только валидация без десериализации, то раскомментируйте строку с while, закомментировав следующую. В том подходе, который используете вы сейчас, всё делается, имхо, очень неэффективно. Десериализация - отдельно (проход по xml, потребление памяти). Валидация - отдельно (ещё проход, ещё память). Поиск строки с ошибкой с помощью XPath - ещё одна загрузка xml в XmlDocument/XDocument (опять полный парсинг xml, опять тратится время и память). Кроме того, если xml синтаксически некорректен (незакрытый тег), то он вообще не загрузится в XmlDocument/XDocument и вы никогда не узнаете, где же ошибка... Кроме того, вы вручную расставляете атрибуты валидации и пишете код валидации... Лишняя работа.

Ответ 2



а через LINQ to XML нельзя сделать? что-то вроде такого ... XDocument xdoc = XDocument.Load(file, LoadOptions.SetLineInfo); var node = xdoc.XPathSelectElement("//shop/offers/offer[1]/price"); var lineNumber = ((IXmlLineInfo)node).LineNumber;

Ответ 3



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

четверг, 23 января 2020 г.

Удалить кусок html используя xpath

#html #python #xpath


Задача может быть и простая, но я с таким не сталкивался. Как из html-кода удалить
определенный узел? Используя xpath шаблон. Ниже примерно описал алгоритм. Не знаю только
библиотеку и функцию, которые выполнили бы эту операцию.

import "какая_нибудь_стандартная_библиотека"
html_code = 'Заголовок и так далее ...'
xpath_parrent = '//title'
result = "функция_удалить"(html_code, xpath_parrent)
теперь узла title больше нету
можно выводить на экран
print title

    


Ответы

Ответ 1



Я бы из стандартного использовал бы регулярки. Используя модуль lxml, можно так: from lxml import html html_code = 'Заголовок' xpath = '//title' root = html.fromstring(html_code) print(html.tostring(root)) # b'Заголовок' for el in root.xpath(xpath): parent = el.getparent() parent.remove(el) print(html.tostring(root)) # b''

Ответ 2



Чистый xpath запрос не получится, потому что функция selectNodes выбирает Nod-ы из одного уровня xml, и фильтр можно поставить только на весь уровень. Но можно сделать, например, SelectNodes('/*/*[name(*/.)!="title"]') что выберет "второй" уровень (т.к. первый "root" т.е. весь документ тег html), при этом будет отброшена вся ветка head, от этого вы никак не уйдёте, т.к. если выбрать третий уровень - елементы второго уровня где нету третьего "уйдут" потеряются данные. Пример тут http://stackoverflow.com/questions/36260599/xpath-search-within-xpath-results Вариант 2. Можно использовать трансформацию xsl + xpath с рекурсией. Скрипт трансформации будет примерно такой: Базируется на функции copyif которая клонирует ноды, плюс в if - условие копирование (c которыи прийдётся помучатся, сравнение полного пути xpath 3.0 поддерживает). Шапку можно и 1.0, функции "базовые". Запрос большой, зато на питоне будет две-три строчки - загрузить два xml и сделать transform. это не самый лучший метод, но может пригодится как пример обращения с xml.

воскресенье, 12 января 2020 г.

Selenium и клик по кнопке

#xpath #selenium #java


Здравствуйте.
Есть такая кнопка: 


Пытаюсь нажать её так:

driver.findElement(By.xpath("//input[@class=\"button primary\"][0]")).click();

Не выходит.Прошу помощи.    


Ответы

Ответ 1



Привет. Используйте следующий код driver.findElements(By.xpath(".//input[@class='button primary']")).get(0).click

Ответ 2



Посмотри используя firebug находится ли твой элемент в пределах заданной страницы в коде css. Возможно при даже верном xpath тебе не удасться это сделать. Таким образом найдя видимый элеент кликай на него, можно пробовать js (JavascriptExecutor) или action (Actions) на крайняк. Кстати твой xpath можно написать так: //input[@value='Начать переписку'] //input[@type='submit'] //input[@accesskey='s'] //input[@class='button primary'] - наиболее подходит

Ответ 3



driver.findElement(By.xpath("//input[@class='button primary']")).click();

четверг, 9 января 2020 г.

локатор содержащий текст с переменным символом

#javascript #xpath #css_selectors


нужен локатор который будет искать элемент по тексту при этом допуская что в массиве
текста один символ может иметь одно из двух возможных значений.
например я ищу кнопку которая содержит число

//a[contains(.,"123,123")]


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

моя задача сделать локатор который находит элемент учитывая что в нём может быть
как точка так и запятая. 

моё временное решение это проверять оба локатора ожидая что один из них пройдёт.

подойдёт решение в виде локатора css/xpath либо javascript 

xpath v1.решение должно воспроизводиться в этих вкладках 
    


Ответы

Ответ 1



Решение с использование JavaScript Находим нужный элемент и проверяем с помощью регулярного выражения document.querySelector("a").innerHTML.match(/123(.|,)123/); Более подробную информацию о том как написать регулярное выражение, можно найти в справочниках по функции match().

Ответ 2



Если кто-то ищет решение чисто на XPath, то можно воспользоваться оператором or: //a[contains(., "123.123") or contains(., "123,123")]

среда, 10 июля 2019 г.

LIKE подобный запрос, с использованием xpath в postrgesql

Добрый вечер! У меня имеется простая база данных, в которой хранится xml - данные, в данном случае автор книги и её текст. Вопрос как осуществить поиск типа LIKE, чтобы не писать полное содержание книги или полностью автора. На данный момент я делаю такой запрос:
SELECT * from storage where (xpath('//book/author/text()', documentcontent))[1]::text = 'Толстой Лев Николаевич'::text;


Ответ

Вообщем получилось у меня найти ответ, вышло их целых два.
Первый вариант вытаскивает только ОДНО значение вместе с тегами из XML документа хранящегося в таблице:
SELECT unnest(xpath('//ЗДЕСЬ УКАЗАТЬ УЗЕЛ/*[contains(text(),"ТУТ НАПИСАТЬ ИЛИ УКАЗАТЬ ЧАСТЬ ТЕКСТА, КОТОРЫЙ ХРАНИТСЯ В XML")]', ТУТ УКАЗАТЬ ИМЯ ПОЛЯ::xml))::text AS XMLDATA FROM ТУТ УКАЗАТЬ ИМЯ ТАБЛИЦЫ;
Второй вариант вытаскивает ВСЕ значение вместе с тегами из XML документа хранящиеся в таблице:
SELECT * from ТУТ УКАЗАТЬ ИМЯ ТАБЛИЦЫ where (xpath('//ЗДЕСЬ УКАЗАТЬ УЗЕЛ', ТУТ УКАЗАТЬ ИМЯ ПОЛЯ))[1]::text ILIKE '%ТУТ УКАЗАТЬ ФРАЗУ ЧАСТЬЮ ИЛИ ЦЕЛИКОМ'::text;
Надеюсь вам поможет.

среда, 3 апреля 2019 г.

c# Net core Поиск номера строки ошибки в файле XML, имея путь к тегу (cases XPath, Regex, JSON?)

Здравствуйте. Ситуация: есть модель(дисериализованный файл), довольно большая. В ней много строк и вложенных объектов. (Модель YML каталога).
[XmlRoot("yml_catalog")] public class YMLCatalog { ///

/// Дата и время генерации YML файла на стороне магазина /// [Required] [XmlAttribute("date")] public string Date { get; set; }
/// /// Магазин /// [Required] [ValidateObject] [XmlElement(ElementName = "shop")] public Shop Shop { get; set; } }
/// /// Точка продаж /// https://yandex.ru/support/webmaster/goods-prices/technical-requirements.html /// public class Shop { /// /// Название магазина. /// [Required] [XmlElement("name")] public string Name { get; set; }
/// /// Название компании /// [Required] [XmlElement("company")] public string Company { get; set; } ... и тд. }
При валидации модели, в случае ошибки, я получаю (при помощи магии. См. краткое описание в комментариях) путь к ошибке. Например для YML файла с ошибкой в теге price, 0го оффера, в виде отсутствия цены, я получаю путь: shop/offers/offer['0 или 1', смотря как удобнее. Для XPath лучше 1]/price Value: Текст ошибки. (Value - поле со значением тега, аналогично может быть для атрибутов)
Нас интересует: shop/offers/offer[0]/price
По этому пути, мне нужно определить номер строки, где находиться этот тег. Чтобы указать пользователю где ошибка.
Что я пробовал:
1) Сделал через регулярные выражения. Сначала последовательно нахожу индекс элементов по пути, как получу индекс начала тега Price в файле. Затем собираю список строк в файле и нахожу номер строки для вывода, относительно всего файла. - Это работает, но меня не устраивает. Слишком медленно, а у меня могут быть очень большие файлы
2) Попробовал сделать через XPath. Т.е например можно легко получить элемент тега вот так:
XmlDocument document = new XmlDocument(); document.LoadXml(text); var node = document.SelectSingleNode("//shop/offers/offer[1]/price");// это для примера
3) Есть вариант с созданием своего дессериализатора + атрибутов валидации для него, чтобы к каждому полю в модели приписывать в метаданных IXmlLineInfo - который в стандартном XmlSerializer к сожалению используется только при выдаче информации об ошибке - но это долго, а те готовые, что я нашел, не поддерживаются в net core... UPD: также в таком случае требуется поддержка не только составных объектов, но и простых + простых атрибутов (string, int, long и тп)
Вопрос 1: XPath как-нибудь позволяет получить кол-во элементов выше (или лучше их список) ? Вроде комбинировать preceding и ancestor нельзя (ссылка) - Но опять же, даже если это получиться, придется искать индекс, создавая список строк файла. - Не очень хорошо, хотелось бы узнать номер строки ошибки другим способом
Пробовал "//shop/offers/offer[ 1 ]/price/preceding::*", но в таком случае игнорируются все элементы выше shop, почему не знаю. (когда использовал count(...), получал 27 элементов) - Думаю это всяко лучше только регулярных выражений
Знаете еще способ? Прошу в ответы:)
Главный вопрос: Так как лучше всего найти номер строки ошибки, имея XML и путь к тегу?
P.S Производительность решения приветствуется)


Ответ

Не выдержал, решил дать свой ответ.
Во-первых, XmlSerializer выдаёт ошибку не только при ошибке синтаксиса XML (например, незакрытый тег), но и в том случае, если тип данных не соответствует ожидаемому (например, свойство Price имеет тип decimal, а в узле Price пусто или нечисловая строка). При этом в выбрасываемом исключении содержится сообщение, содержащее номер и позицию ошибки:
В документе XML (4, 18) присутствует ошибка.
На мой взгляд, это уже фактически решает вопрос. Строка с ошибкой известна, можно её исправлять.

Чуть погуглив, я легко выяснил, что для документов YML имеется схема. Скачать её можно здесь
При валидации по схеме будет выдаваться описание ошибки наподобие следующего:
Элемент "Price" недействителен: значение "" недействительно с точки зрения его типа данных "http://www.w3.org/2001/XMLSchema:decimal" - Строка "" не является допустимым значением Decimal.
Это даёт огромное удобство: пользователь легко поймёт и исправит ошибку.
Сама валидация делается в несколько строк:
var xs = new XmlSerializer(typeof(Test)); var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema };
var schemas = new XmlSchemaSet(); schemas.Add(null, "schema.xsd"); settings.Schemas = schemas; settings.ValidationEventHandler += Settings_ValidationEventHandler;
using (var xr = XmlReader.Create("test.xml", settings)) //while (xr.Read()) ; item = (Test)xs.Deserialize(xr);
private void Settings_ValidationEventHandler(object sender, ValidationEventArgs e) { Console.WriteLine(e.Severity); Console.WriteLine(e.Message); Console.WriteLine(e.Exception.LineNumber + " " + e.Exception.LinePosition); }
В данном коде валидация происходит в процессе чтения xml. То есть нет лишних проходов/загрузок, всё максимально эффективно по скорости и объёму памяти.
Если нужно только валидация без десериализации, то раскомментируйте строку с while, закомментировав следующую.

В том подходе, который используете вы сейчас, всё делается, имхо, очень неэффективно.
Десериализация - отдельно (проход по xml, потребление памяти). Валидация - отдельно (ещё проход, ещё память). Поиск строки с ошибкой с помощью XPath - ещё одна загрузка xml в XmlDocument/XDocument (опять полный парсинг xml, опять тратится время и память).
Кроме того, если xml синтаксически некорректен (незакрытый тег), то он вообще не загрузится в XmlDocument/XDocument и вы никогда не узнаете, где же ошибка...
Кроме того, вы вручную расставляете атрибуты валидации и пишете код валидации... Лишняя работа.

National Prefix (carrier specific)