Можно ли с помощью Mechanize найти в HTML-коде страницы фразу, например, «электронная почта», найти следующую после нее <input*
и заполнить это поле ввода и только это поле?
Поиск следующего элемента ввода с помощью Mechanize?
Ответы (3)
Mechanize использует Nokogiri внутри для анализа DOM, что является основой его способности находить различные элементы на странице.
Можно получить доступ к проанализированному DOM и через него использовать Nokogiri для поиска элементов, которые Mechanize обычно не позволяет нам найти. Например:
require 'mechanize'
agent = Mechanize.new
page = agent.get('http://www.example.com')
# Use Nokogiri to find the content of the <h1> tag...
puts page.at('h1').content # => "Example Domain"
Для вашего поиска вы хотели бы использовать средство доступа XPath, чтобы определить, где на странице находится «электронная почта». Как только вы это сделаете, вы сможете найти следующий тег <input>
.
Начнем с простого HTML-фрагмента и представим, что это исходит от Mechanize:
page = Nokogiri::HTML('<div><form><p>email</p><input name="email"></form></div>')
puts page.to_html
Что выглядит так:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div><form>
<p>email</p>
<input name="email">
</form></div></body></html>
Поиск "электронной почты":
page.at("//*[contains(text(),'email')]")
#<Nokogiri::XML::Element:0x3ff50d0c4bc0 name="p" children=[#<Nokogiri::XML::Text:0x3ff50d0c497c "email">]>
Основываясь на этом, это получает тег <input>
:
input_tag = page.at("//*[contains(text(),'email')]/following-sibling::input")
#<Nokogiri::XML::Element:0x3ff50d09b75c name="input" attributes=[#<Nokogiri::XML::Attr:0x3ff50d09b5f4 name="name" value="email">]>
После того, как вы нашли этот входной тег, вы можете получить «имя» из тега с помощью Nokogiri, а затем указать Mechanize найти и заполнить это конкретное поле ввода:
input_tag['name']
=> "email"
Чтобы веб-форма работала правильно, она должна иметь имена для элементов. Они передаются на сервер при отправке формы. Без имен потребовалось бы много работы, чтобы определить, какой ввод отправил конкретную часть данных, и, поскольку программисты ленивы, мы не хотим много работать, поэтому вы можете рассчитывать на то, что у вас есть имя для работы.
Дополнительные сведения см. в разделе Ruby Mechanize, Nokogiri и Net::HTTP, а также поиск в Stack Overflow и чтение Документация и руководства по Nokogiri дадут вам много необходимой информации, чтобы понять, как делать все остальное.
Сначала найдите элемент с текстом фразы:
el = page.at('*[text()*="some phrase"]')
Оттуда вы можете получить первый следующий ввод:
input = el.at('./following::input')
Теперь найдите узел формы-предка этого ввода:
form_node = input.ancestors('form')[0]
Затем используйте это, чтобы получить объект Mechanize::Form.
form = page.form_with(:form_node => form_node)
И теперь вы можете заполнить значение
form[input[:name]] = 'foo'
Для правильной HTML-страницы элемент input
должен иметь label
, показывающий, для чего предназначен input
. В этом случае вы можете перебрать все label
, найти тот, который содержит текст "email"
, и получить связанный input
по атрибуту for
файла label
.
Однако не все HTML-страницы имеют правильный формат. Нет атрибута label
, нет атрибута for
или других ошибок.
Если вы имеете в виду input
сразу после какого-то элемента в DOM. Вы можете выполнить обход DOM, чтобы определить, есть ли рядом с элементом, содержащим "email"
, элемент input
.
Если вы имеете в виду input
рядом с элементом на отображаемой странице, вы должны определить, что находится «рядом с». И я думаю, что вы не можете получить то, что хотите, без больших усилий. Какой-то элемент, расположенный после элемента «email», может быть помещен перед ним с помощью некоторого трюка CSS. Вам нужен графический API, чтобы найти этот файл input
. Однако я не вижу этого в документации API watir
.