извлекать одну строку из HTML с помощью Ruby / Mechanize (и Nokogiri)

Я извлекаю данные с форума. Мой сценарий на основе работает нормально. Теперь мне нужно извлечь дату и время (21 декабря 2009 г., 20:39) из одного сообщения. Я не могу заставить его работать. Я использовал FireXPath для определения xpath.

Образец кода:

 require 'rubygems'
 require 'mechanize'

   post_agent = WWW::Mechanize.new
    post_page = post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')
    puts  post_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div[2]/text()').to_s.strip
    puts  post_page.parser.at_xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div[2]/text()').to_s.strip
    puts post_page.parser.xpath('//[@id="post1960370"]/tbody/tr[1]/td/div[2]/text()')

все мои попытки заканчиваются пустой строкой или ошибкой.


Я не могу найти никакой документации по использованию Nokogiri в Mechanize. В документации Mechanize внизу страницы говорится:

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

Но какими методами? Где я могу прочитать о них с примерами и объяснением синтаксиса? Я также ничего не нашел на сайте Нокогири.


person Radek    schedule 22.01.2010    source источник


Ответы (2)


Радек. Я покажу вам, как ловить рыбу.

Когда вы звоните Mechanize::Page::parser, он выдает вам документ Nokogiri. Итак, ваши вызовы «xpath» и «at_xpath» вызывают Nokogiri. Проблема в ваших xpaths. В общем, начните с самого общего xpath, с которым вы можете работать, а затем сузьте его. Так, например, вместо этого:

puts  post_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div[2]/text()').to_s.strip

начнем с этого:

puts post_page.parser.xpath('//table').to_html

Он получает любые таблицы в любом месте, а затем печатает их как html. Изучите HTML, чтобы увидеть, какие таблицы он вернул. Вероятно, он захватил несколько, когда вам нужен только один, поэтому вам нужно будет сказать ему, как выбрать один стол, который вам нужен. Если, например, вы заметили, что у нужной таблицы есть класс CSS "userdata", попробуйте следующее:

puts post_page.parser.xpath("//table[@class='userdata']").to_html

Каждый раз, когда вы не получаете обратно массив, вы обманываете xpath, поэтому исправьте его, прежде чем продолжить. Как только вы получите нужную таблицу, попробуйте получить строки:

puts post_page.parser.xpath("//table[@class='userdata']//tr").to_html

Если это сработало, снимите "to_html", и теперь у вас есть массив узлов Nokogiri, каждая из которых представляет собой строку таблицы.

Вот как вы это делаете.

person Wayne Conrad    schedule 22.01.2010
comment
PS: Это общий учебник, показывающий, как определить правильный xpath: вы не начинаете с полностью указанного xpath, потому что тогда вы понятия не имеете, что не так, если он ничего не возвращает. Начните с чего-то настолько общего, что гарантированно что-то вернет, а затем продолжайте делать это более конкретным, пока не получите то, что вам нужно. Делая это поэтапно, когда это не работает, вы знаете, что это последнее, что вы добавляли в xpath. - person Wayne Conrad; 22.01.2010
comment
@Wayne Conrad: Привет, Уэйн, спасибо за хороший урок. Я попробую то, что вы говорите, но я подумал, что, поскольку мне нужен только первый экземпляр элемента, было бы легко и быстро использовать абсолютный xpath. И это даст мне первый элемент из массива. - person Radek; 22.01.2010
comment
Итак, вы бы выполнили все эти шаги, даже если хотите узнать, сколько раз этот вопрос был просмотрен? - person Radek; 22.01.2010
comment
Да, я всегда итеративно вычисляю свои xpath. Кто-то, кто хорошо разбирается в xpath, может понять это с первого раза. Это не я. Это не xpath, который решает, получите ли вы одну вещь или много. Независимо от того, вызываете ли вы xpath или at_xpath. Если вы вызовете xpath, вы всегда получите одно; если совпадают несколько элементов, вы получите только первый. Если вы вызовете at_xpath, вы всегда получите массив, даже если вы сопоставили только одно. - person Wayne Conrad; 22.01.2010
comment
вау, это то, что я искал. разница между xpath и at_xpath. спасибо за это. Как вы это узнали? - person Radek; 22.01.2010
comment
Я не могу понять, почему не работает полный xpath !? Полный xpath + 'at_xpath' даст первое совпадение, и я был бы счастлив :-) - person Radek; 22.01.2010
comment
Вы пробовали то, что я сказал? Начните с '// table', затем заставьте его выбрать только одну таблицу, в которой есть нужные вам данные. - person Wayne Conrad; 22.01.2010
comment
Я почти у цели. У меня есть массив из 15 таблиц (= 15 постов), где в первой таблице есть данные, которые мне нужны. Xpath - это // div [@ id = 'posts'] / div / table, если я добавлю tbody, чтобы быть более конкретным, это не даст мне ничего - person Radek; 22.01.2010
comment
однострочное решение помещает post_page.parser.xpath (// div [@ id = 'posts'] / div / table / tr / td / div [2]) [0] .xpath ('text ()'). to_s .полоска - person Radek; 22.01.2010
comment
Что произойдет, если вы используете две косые черты перед tbody вместо одной? О чем тебе это говорит? - person Wayne Conrad; 22.01.2010
comment
// div [@ id = 'posts'] / div / table // tbody / tr / td тоже не дает - person Radek; 22.01.2010
comment
когда я использовал .at_xpath где-нибудь в этом упражнении, я не получил результатов - person Radek; 22.01.2010
comment
Даже когда вы используете at_xpath ('// table')? - person Wayne Conrad; 22.01.2010
comment
да, at_xpath ('// table') мне кое-что дает. Даже установка post_page.parser.at_xpath (// div [@ id = 'posts'] / div / table / tr / td / div [2]) дает мне то, что я хочу. Но для извлечения последнего фрагмента мне нужно использовать xpath, at_xpath дает мне пустую строку. - person Radek; 22.01.2010
comment
Вернитесь к другим ответам, которые я вам дал. Вы увидите что-то другое в конце финальных xpaths. - person Wayne Conrad; 22.01.2010
comment
Прошу прощения за то, что не могу четко общаться. Честно говоря, я не знаю, куда идти - теперь это индивидуальное занятие, которое, я не уверен, подходит для этого. Но меня это не беспокоит. Меня беспокоит, что я не понял, как передать ключевые концепции, которые хочу донести. Есть общие принципы решения проблем в программировании, о которых я хочу рассказать, которые помогут вам решить не только эту проблему, но и любую проблему. К сожалению, я не справляюсь с этой задачей. - person Wayne Conrad; 22.01.2010
comment
@Wayne Conrad: вы хорошо поработали. Теперь я могу ловить рыбу самостоятельно :-) Я отправлю отдельные вопросы для уточнения. Давайте закроем здесь. Большое спасибо. - person Radek; 22.01.2010

Я думаю, вы скопировали это из Firebug, firebug дает вам дополнительный tbody, которого может не быть в реальном коде ... поэтому я предлагаю удалить это tbody и попробовать еще раз. если это все еще не работает ... тогда следуйте процессу Уэйна Конрада, это лучше всего!

person RubyDubee    schedule 29.12.2010
comment
Источник внутри браузера всегда вызывает подозрение, потому что браузер может и будет делать много исправлений плохого HTML или просто преобразовывать его в формат, в котором они хотят, чтобы он был. Тег <tbody> - хороший пример. Я использую исходное представление браузера как нечто вроде этого представления, но получаю фактический HTML прямо с хоста и просматриваю его в редакторе, когда я пытаюсь разобрать, если что-то кажется чепухой. Достаточно часто использовать IRB с открытым и изучать проанализированный документ, но иногда требуется, чтобы редактор был открыт. - person the Tin Man; 30.12.2010