Поиск следующего элемента ввода с помощью Mechanize?

Можно ли с помощью Mechanize найти в HTML-коде страницы фразу, например, «электронная почта», найти следующую после нее <input* и заполнить это поле ввода и только это поле?


person Joe    schedule 29.03.2013    source источник


Ответы (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 дадут вам много необходимой информации, чтобы понять, как делать все остальное.

person the Tin Man    schedule 29.03.2013
comment
Я очень извиняюсь за поздний ответ, болезнь взяла верх надо мной. Спасибо LOADS за все усилия, которые вы приложили к ответу, это действительно очень помогло :) Теперь все работает. Еще раз спасибо! :) - person Joe; 31.03.2013

Сначала найдите элемент с текстом фразы:

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'
person pguardiario    schedule 29.03.2013

Для правильной HTML-страницы элемент input должен иметь label, показывающий, для чего предназначен input. В этом случае вы можете перебрать все label, найти тот, который содержит текст "email", и получить связанный input по атрибуту for файла label.

Однако не все HTML-страницы имеют правильный формат. Нет атрибута label, нет атрибута for или других ошибок.

Если вы имеете в виду input сразу после какого-то элемента в DOM. Вы можете выполнить обход DOM, чтобы определить, есть ли рядом с элементом, содержащим "email", элемент input.

Если вы имеете в виду input рядом с элементом на отображаемой странице, вы должны определить, что находится «рядом с». И я думаю, что вы не можете получить то, что хотите, без больших усилий. Какой-то элемент, расположенный после элемента «email», может быть помещен перед ним с помощью некоторого трюка CSS. Вам нужен графический API, чтобы найти этот файл input. Однако я не вижу этого в документации API watir.

person Arie Xiao    schedule 29.03.2013