Удаление/игнорируя ненужный текст не является проблемой Nokogiri, это проблема обработки строк:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
li class="object-props-item price"
<strong>CHF 14'900.-</strong>
<li class="object-props-item milage">61'000 km</li>
EOT
str = doc.at('strong').text # => "CHF 14'900.-"
В этот момент str
содержит текст узла <strong>
.
Простое регулярное выражение будет извлечь, который является простым способом, чтобы захватить данные:
str[/[\d']+/] # => "14'900"
sub
может быть использован для удаления 'CHF '
подстроку:
str.sub('CHF ', '') # => "14'900.-"
delete
может быть использован для удаления символы C
, H
, F
и
:
str.delete('CHF ') # => "14'900.-"
tr
может быть использован для удаления всего, что не 0
.. 9
, '
, .
или -
:
str.tr("^0-9'.-", '') # => "14'900.-"
Изменить один из выше, если вы не хотите '
, .
или -
.
почему данные пробеги не отображая
Поскольку у вас есть несоответствие между селектором CSS и фактическим class
параметром:
require 'nokogiri'
doc = Nokogiri::HTML('<li class="object-props-item milage">61'000 km</li>')
doc.at('.mileage').text # =>
# ~> NoMethodError
# ~> undefined method `text' for nil:NilClass
# ~>
# ~> /var/folders/yb/whn8dwns6rl92jswry5cz87dsgk2n1/T/seeing_is_believing_temp_dir20160428-96035-1dajnql/program.rb:5:in `<main>'
Вместо этого он должен быть:
doc.css('.milage').text # => "61'000 km"
Но это еще не все. Есть тонкая проблема, ожидающая укусить вас позже.
css
или search
возвращает набор узлов, тогда как at
или at_css
возвращает элемент:
doc.css('.milage').class # => Nokogiri::XML::NodeSet
doc.at('.milage').class # => Nokogiri::XML::Element
Вот что происходит, когда text
передается NodeSet, содержащее множество узлов, соответствующих:
doc = Nokogiri::HTML('<p>foo</p><p>bar</p>')
doc.search('p').class # => Nokogiri::XML::NodeSet
doc.search('p').text # => "foobar"
doc.at('p').class # => Nokogiri::XML::Element
doc.at('p').text # => "foo"
Когда text
используется с NodeSet он возвращает текст всех узлов, конкатенированных в одну строку. Это может сделать очень трудным отделить текст от одного узла от другого. Вместо этого используйте at
или один из эквивалентов at_*
, чтобы получить текст с одного узла. Если вы хотите, чтобы извлечь текст из каждого узла в отдельности и получить использование массива:
doc.search('p').map(&:text) # => ["foo", "bar"]
См «How to avoid joining all text from Nodes when scraping» также.
Наконец, обратите внимание, что ваш HTML образец не является действительным:
doc = Nokogiri::HTML(<<EOT)
li class="object-props-item price"
<strong>CHF 14'900.-</strong>
<li class="object-props-item milage">61'000 km</li>')
EOT
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body>
# >> <p>li class="object-props-item price"
# >> <strong>CHF 14'900.-</strong>
# >> </p>
# >> <li class="object-props-item milage">61'000 km</li>')
# >> </body></html>
Вот что происходит:
doc = Nokogiri::HTML(<<EOT)
li class="object-props-item price"
<strong>CHF 14'900.-</strong>
<li class="object-props-item milage">61'000 km</li>')
EOT
doc.at('.price') # => nil
Nokogiri должен сделать исправления в систему, чтобы иметь смысл первой строки, поэтому он обертывает его в <p>
. Таким образом, класс .price
больше не существует, поэтому ваш код снова сработает.
Фиксирование результатов тегов в правильном ответе:
doc = Nokogiri::HTML(<<EOT)
<li class="object-props-item price">
<strong>CHF 14'900.-</strong>
</li>
<li class="object-props-item milage">61'000 km</li>')
EOT
doc.at('.price').to_html # => "<li class=\"object-props-item price\">\n<strong>CHF 14'900.-</strong>\n</li>"
Вот почему очень важно, чтобы убедиться, что ваш вход правилен. Без него сложно дублировать свою проблему.
Я не думаю, что это причина вашей проблемы, но вы открываете файл для записи в двоичном режиме ('wb'). CSV - это текстовое представление, поэтому я уверен, что вы должны открывать его в текстовом режиме ('w'). –
Когда вы спрашиваете о проблеме с вашим кодом, мы должны увидеть вашу попытку решить проблему. В вашем коде вы не показываете, где вы пытаетесь удалить данные CHF и KM; Пожалуйста, добавьте это. Без этого похоже, что вы спрашиваете нас, как написать свой код, для чего это не так. Кроме того, ваш «результат» не должен быть ссылкой на изображение. Вместо этого представите эту информацию в самом вопросе. «[mcve]» описывает то, что нам нужно. Чтобы удалить эту информацию, используйте «delete» или «sub» в извлеченном тексте или лучше, используйте 'tr', чтобы удалить то, что вы не хотите, или написать регулярное выражение, чтобы извлечь только то, что вы хотите. –
Кроме того, ваш входной код HTML недопустим. См. Мой ответ для объяснения, почему это важно. –