Я играю с Nokogiri, просто чтобы изучить его, и пытаюсь написать небольшой парсер для CL. Прямо сейчас я пытаюсь сопоставить каждое государство на главной странице с городами внизу. Ниже приведен фрагмент HTML:

<div class="colmask">
<div class="box box_1">
<h4>Alabama</h4>
<ul>
<li><a href="//auburn.craigslist.org/">auburn</a></li>
<li><a href="//bham.craigslist.org/">birmingham</a></li>
<li><a href="//dothan.craigslist.org/">dothan</a></li>
<li><a href="//shoals.craigslist.org/">florence / muscle shoals</a></li>
<li><a href="//gadsden.craigslist.org/">gadsden-anniston</a></li>
<li><a href="//huntsville.craigslist.org/">huntsville / decatur</a></li>
<li><a href="//mobile.craigslist.org/">mobile</a></li>
<li><a href="//montgomery.craigslist.org/">montgomery</a></li>
<li><a href="//tuscaloosa.craigslist.org/">tuscaloosa</a></li>
</ul>
<h4>Alaska</h4>
<ul>
<li><a href="//anchorage.craigslist.org/">anchorage / mat-su</a></li>
<li><a href="//fairbanks.craigslist.org/">fairbanks</a></li>
<li><a href="//kenai.craigslist.org/">kenai peninsula</a></li>
<li><a href="//juneau.craigslist.org/">southeast alaska</a></li>
</ul>

Я уже могу достаточно легко вытащить только этот div-класс "colmask". Но сейчас я просто пытаюсь получить UL сразу после каждого h4, но пока не могу найти способ сделать это. Предложения?

0
cashman04 5 Янв 2016 в 19:06

2 ответа

Лучший ответ

Вы можете получить элементы ul после h4, используя following-sibling:

require 'nokogiri'

html = <<-EOF
<div class="colmask">
<div class="box box_1">
<h4>Alabama</h4>
<ul>
<li><a href="//auburn.craigslist.org/">auburn</a></li>
<li><a href="//bham.craigslist.org/">birmingham</a></li>
<li><a href="//dothan.craigslist.org/">dothan</a></li>
<li><a href="//shoals.craigslist.org/">florence / muscle shoals</a></li>
<li><a href="//gadsden.craigslist.org/">gadsden-anniston</a></li>
<li><a href="//huntsville.craigslist.org/">huntsville / decatur</a></li>
<li><a href="//mobile.craigslist.org/">mobile</a></li>
<li><a href="//montgomery.craigslist.org/">montgomery</a></li>
<li><a href="//tuscaloosa.craigslist.org/">tuscaloosa</a></li>
</ul>
<h4>Alaska</h4>
<ul>
<li><a href="//anchorage.craigslist.org/">anchorage / mat-su</a></li>
<li><a href="//fairbanks.craigslist.org/">fairbanks</a></li>
<li><a href="//kenai.craigslist.org/">kenai peninsula</a></li>
<li><a href="//juneau.craigslist.org/">southeast alaska</a></li>
</ul>
EOF

doc = Nokogiri::HTML(html)
doc.xpath('//h4/following-sibling::ul').each do |node|
  puts node.to_html
end

Чтобы выбрать ul после h4 с точным текстом:

puts doc.xpath("//h4[text()='Alabama']/following-sibling::ul")[0].to_html
1
Rustam A. Gasanov 5 Янв 2016 в 16:40

Я бы сделал что-то вроде этого:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<h4>Alabama</h4>
<ul>
<li><a href="//auburn.craigslist.org/">auburn</a></li>
<li><a href="//bham.craigslist.org/">birmingham</a></li>
</ul>
<h4>Alaska</h4>
<ul>
<li><a href="//anchorage.craigslist.org/">anchorage / mat-su</a></li>
<li><a href="//fairbanks.craigslist.org/">fairbanks</a></li>
</ul>
EOT

states = doc.search('h4')
states_and_cities = states.map{ |state|
  cities = state.next_element.search('li a')
  [state.text, cities.map(&:text)]
}.to_h

На данный момент states_and_cities - это хеш массивов:

states_and_cities
# => {"Alabama"=>["auburn", "birmingham"],
#     "Alaska"=>["anchorage / mat-su", "fairbanks"]}

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

Однако, если вы запускаете этот код для генерации контента для веб-страницы «на лету», то вы ошибаетесь. Информация о штатах и ​​городах должна быть помещена в базу данных, где к ней можно будет получить доступ гораздо быстрее. Тогда вам не придется делать это каждый раз при создании страницы.

Важно быть добрым и нежным по отношению к другим сайтам; Изучите HTTP-запрос HEAD. Это ваш ключ к определению, следует ли вам получить страницу полностью. Кроме того, узнайте, как извлекать информацию из кеша из заголовка HTTP, возвращаемого сервером. Это говорит вам, какой должна быть минимальная частота обновления. Также обратите внимание на файл robots.txt, который сообщает вам, что они считают безопасным для парсинга; игнорирование этого может привести к бану.

1
the Tin Man 7 Янв 2016 в 16:39