Статьи

Сборка вашего первого веб-скребка, часть 1

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

  • Соскоб?
  • разрешение
  • Проблема
  • Nokogiri
  • Добыча?
  • страницы
  • API
  • Навигация по узлам

Есть более причудливые термины, чем соскоб в сети или на экране. Веб-сбор и извлечение веб-данных в значительной степени сразу скажут вам, что происходит. Мы можем автоматизировать извлечение данных с веб-страниц — и это не так сложно.

В некотором смысле, эти инструменты позволяют имитировать и автоматизировать просмотр веб-страниц человеком. Вы пишете программу, которая извлекает только те данные, которые вас интересуют. Ориентация на конкретные данные почти так же проста, как использование селекторов CSS.

Несколько лет назад я подписался на какой-то онлайн-видео курс, в котором было около миллиона коротких видео, но у меня не было возможности их массового скачивания. Я должен был пройти каждую ссылку самостоятельно и сделать страшную «сохранить как» я сам. Это было что-то вроде человеческой паутины — то, что нам часто нужно делать, когда нам не хватает знаний для автоматизации такого рода вещей. Сам курс был в порядке, но после этого я больше не пользовался их услугами. Это было слишком утомительно.

Сегодня я бы не слишком заботился о таком умопомрачительном UX. Скребок, который должен был сделать загрузку для меня, занял бы всего пару минут, чтобы бросить все вместе. Нет, важная персона!

Позвольте мне разобраться очень быстро, прежде чем мы начнем. Все это можно сжать в пару шагов. Сначала мы выбираем веб-страницу с нужными нам данными. Затем мы ищем на этой странице и определяем информацию, которую хотим извлечь.

Последний шаг — нацелить эти биты, нарезать их, если необходимо, и решить, как и где вы хотите их хранить. Хорошо написанный HTML часто является ключом к тому, чтобы сделать этот процесс простым и приятным. Для более сложного извлечения может возникнуть боль, если вам приходится иметь дело с плохо структурированной разметкой.

А как насчет API? Очень хороший вопрос Если у вас есть доступ к сервису с API, часто нет необходимости писать собственный скребок. Этот подход в основном для веб-сайтов, которые не предлагают такого удобства. Без API это часто единственный способ автоматизировать извлечение информации с веб-сайтов.

Вы можете спросить, как эта штуковина на самом деле работает? Короткий ответ не вдаваясь в глубокий конец, заключается в обходе древовидных структур данных. Nokogiri строит эти структуры данных из документов, которые вы передаете, и позволяет вам выбирать интересующие вас фрагменты для извлечения. Например, CSS — это язык, написанный для обхода дерева, для поиска древовидных структур данных, и мы можем использовать его для извлечения данных.

Есть много подходов и решений, с которыми можно играть. У Rubyland есть два драгоценных камня, которые занимают центр внимания в течение ряда лет. Многие люди по-прежнему полагаются на Nokogiri и Mechanize для удовлетворения потребностей HTML. Оба были протестированы и зарекомендовали себя как простые в использовании, но при этом обладают высокой способностью. Мы посмотрим на них обоих. Но перед этим я хотел бы уделить немного времени решению проблемы, которую мы собираемся решить в конце этой короткой вводной серии.

Прежде чем начать очистку, убедитесь, что у вас есть разрешение сайтов, к которым вы пытаетесь получить доступ для извлечения данных. Например, если на сайте есть API или RSS-канал, может быть не только легче получить желаемый контент, но и законный выбор.

Не все оценят это, если вы сделаете огромную проверку на их сайтах — понятно, что так. Получите образование на конкретном сайте, который вас интересует, и не попадайте в неприятности. Шансы на то, что вы нанесете серьезный урон, невелики, но неосознанно рискуйте неприятностями.

Мне нужно было создать новый подкаст. Дизайн был не там, где я хотел, и я ненавидел способ публикации новых постов. Черт, Черт возьми! Немного контекста. Около двух лет назад я создал первую версию своего подкаста. Идея заключалась в том, чтобы поиграть с Синатрой и создать что-то сверхлегкое. Я столкнулся с несколькими неожиданными проблемами, так как я сделал почти все.

Исходя из Rails, это было определенно образовательное путешествие, которое я ценю, но я быстро пожалел, что не использовал статический сайт, который я мог бы развернуть через GitHub через страницы GitHub. Развертыванию новых эпизодов и их обслуживанию не хватало той простоты, которую я искал. Некоторое время я решил, что мне нужно жарить больше рыбы, и сосредоточился на производстве нового материала для подкаста.

Прошлым летом я начал серьезно относиться к работе и работал на сайте Middleman, который размещается на страницах GitHub. Для второго сезона шоу я хотел что-то свежее. Новый, упрощенный дизайн, Markdown для публикации новых эпизодов и никаких кулачных боев с Heroku — небеса! Дело в том, что у меня было 139 эпизодов, которые нужно было импортировать и конвертировать в первую очередь, чтобы работать с Middleman.

В сообщениях Middleman использует файлы .markdown которые имеют так называемый frontmatter для данных, что в основном заменяет мою базу данных. Выполнение этого перевода вручную — не вариант для 139 эпизодов. Вот для чего нужны вычисления. Мне нужно было найти способ разобрать HTML-код моего старого веб-сайта, очистить соответствующий контент и перенести его в записи блога, которые я использую для публикации новых эпизодов подкастов на Middleman.

Поэтому в следующих трех статьях я собираюсь познакомить вас с инструментами, обычно используемыми в Rubyland для таких задач. В конце мы рассмотрим мое решение, чтобы показать вам что-то практичное.

Даже если вы совершенно новичок в Ruby / Rails, очень велики шансы, что вы уже слышали об этом маленьком жемчужине. Имя часто отбрасывается и легко запоминается. Я не уверен, что многие знают, что нокогири в переводе с японского означает «пила».

Это подходящее имя, когда вы понимаете, что делает инструмент. Создатель этого драгоценного камня — прекрасный Тендерлоув, Аарон Паттерсон . Nokogiri преобразует документы XML и HTML в структуру данных — точнее, в древовидную структуру данных. Инструмент быстрый и предлагает приятный интерфейс. В целом, это очень мощная библиотека, которая заботится о множестве ваших потребностей в очистке HTML.

Вы можете использовать Nokogiri не только для разбора HTML; XML тоже честная игра. Он предоставляет вам опции как языка XML-пути, так и CSS-интерфейсов для прохождения документов, которые вы загружаете. XML path Language, или XPath для краткости, является языком запросов.

Это позволяет нам выбирать узлы из документов XML. Селекторы CSS, скорее всего, более знакомы новичкам. Как и в случае со стилями, которые вы пишете, CSS-селекторы позволяют фантастически легко ориентироваться на определенные разделы страниц, которые представляют интерес для извлечения. Вам просто нужно сообщить Nokogiri, что вы ищете, когда вы нацелены на конкретное место назначения.

То, с чего нам всегда нужно начинать, — это получение нужной нам страницы. Мы указываем, какой документ Nokogiri мы хотим проанализировать — например, XML или HTML:

1
2
3
Nokogiri::XML
 
Nokogiri::HTML
1
2
3
4
5
6
7
require «nokogiri»
 
require «open-uri»
 
page = Nokogiri::XML(File.open(«some.xml»))
 
page = Nokogiri::HTML(File.open(«some.html»))

Nokogiri:XML и Nokogiri:HTML может принимать объекты ввода-вывода или строковые объекты. То, что происходит выше, просто. Это открывает и выбирает назначенную страницу, используя open-uri а затем загружает ее структуру, ее XML или HTML в новый документ Nokogiri. XML не то, с чем начинающим приходится сталкиваться очень часто.

Поэтому я бы порекомендовал сосредоточиться на разборе HTML. Почему open-uri ? Этот модуль из стандартной библиотеки Ruby позволяет без особого труда захватить сайт. Поскольку объекты ввода-вывода являются честной игрой, мы можем легко использовать open-uri .

Давайте применим это на практике на мини-примере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
header = page.at_css(«h2.post-title»)
 
title = header.text
 
puts «This is the raw header of the latest episode: #{header}»
 
puts «This is the title of the latest episode: #{title}»

То, что мы здесь сделали, представляет собой все этапы, которые обычно связаны с очисткой веб-страниц — просто на микроуровне. Мы решаем, какой URL нам нужен и какой сайт нам нужно получить, и загружаем их в новый документ Nokogiri. Затем мы открываем эту страницу и нацеливаемся на определенный раздел.

Здесь я только хотел узнать название последнего эпизода. Использование метода at_css и CSS-селектор для h2.post-title — это все, что мне нужно для нацеливания на точку извлечения. Тем не менее, с помощью этого метода мы только очистим этот единственный элемент. Это дает нам весь селектор, который в большинстве случаев не совсем то, что нам нужно. Поэтому мы извлекаем только внутреннюю текстовую часть этого узла с помощью text метода. Для сравнения вы можете проверить вывод как для заголовка, так и для текста ниже.

1
2
3
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/142/»>David Heinemeier Hansson</a></h2>
 
This is the title of the latest episode: David Heinemeier Hansson

Хотя этот пример имеет очень ограниченное применение, он содержит все ингредиенты, все шаги, которые вам нужно понять. Я думаю, это круто, как это просто. Поскольку это может быть неочевидно из этого примера, я хотел бы указать, насколько мощным может быть этот инструмент. Давайте посмотрим, что еще мы можем сделать с помощью скрипта Nokogiri.

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

В Chrome вам просто нужно щелкнуть правой кнопкой мыши элемент на веб-сайте и выбрать опцию проверки. Это откроет небольшое окно в нижней части вашего браузера, которое показывает вам что-то вроде рентгеновского снимка DOM сайта. У него много других вариантов, и я бы порекомендовал потратить некоторое время на Google, чтобы обучить себя. Это время, проведенное с умом!

Метод css даст нам не только один элемент выбора, но и любой элемент, который соответствует критериям поиска на странице. Довольно аккуратно и просто!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
headers = page.css(«h2.post-title»)
 
headers.each do |header|
  puts «This is the raw title of the latest episode: #{header}»
end
 
headers.each do |header|
  puts «This is the title of the latest episode: #{header.text}»
end
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/142/»>David Heinemeier Hansson</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/141/»>Zach Holman</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/140/»>Joel Glovier</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/139/»>João Ferreira</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/138/»>Corwin Harrell</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/137/»>Roberto Machado</a></h2>
This is the raw title of the latest episode: <h2 class=»post-title»><a href=»episodes/136/»>James Edward Gray II</a></h2>
 
This is the title of the latest episode: David Heinemeier Hansson
This is the title of the latest episode: Zach Holman
This is the title of the latest episode: Joel Glovier
This is the title of the latest episode: João Ferreira
This is the title of the latest episode: Corwin Harrell
This is the title of the latest episode: Roberto Machado
This is the title of the latest episode: James Edward Gray II

Единственная небольшая разница в этом примере заключается в том, что я сначала перебираю необработанные заголовки Я также извлек его внутренний текст с помощью метода text . Nokogiri автоматически останавливается в конце страницы и не пытается автоматически выполнять нумерацию страниц.

Допустим, мы хотим получить немного больше информации, скажем, дату и субтитры для каждого эпизода. Мы можем просто расширить пример выше. В любом случае, это хорошая идея — шаг за шагом. Получите небольшой кусочек работы и добавьте больше сложности по пути.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
articles = page.css(«article.index-article»)
 
articles.each do |article|
  header = article.at_css(«h2.post-title»)
  date = article.at_css(«.post-date»)
  subtitle = article.at_css(«.topic-list»)
 
  puts «This is the raw header: #{header}»
  puts «This is the raw date: #{date}»
  puts «This is the raw subtitle: #{subtitle}\n\n»
  
  puts «This is the text header: #{header.text}»
  puts «This is the text date: #{date.text}»
  puts «This is the text subtitle: #{subtitle.text}\n\n»
end
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
This is the raw header: <h2 class=»post-title»><a href=»episodes/142/»>David Heinemeier Hansson</a></h2>
This is the raw date: <span class=»post-date»>Oct 18 |
This is the raw subtitle: <h3 class=»topic-list»>Rails community |
 
This is the text header: David Heinemeier Hansson
This is the text date: Oct 18 |
This is the text subtitle: Rails community |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/141/»>Zach Holman</a></h2>
This is the raw date: <span class=»post-date»>Oct 12 |
This is the raw subtitle: <h3 class=»topic-list»>Getting Fired |
 
This is the text header: Zach Holman
This is the text date: Oct 12 |
This is the text subtitle: Getting Fired |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/140/»>Joel Glovier</a></h2>
This is the raw date: <span class=»post-date»>Oct 10 |
This is the raw subtitle: <h3 class=»topic-list»>Digital Product Design |
 
This is the text header: Joel Glovier
This is the text date: Oct 10 |
This is the text subtitle: Digital Product Design |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/139/»>João Ferreira</a></h2>
This is the raw date: <span class=»post-date»>Aug 26 |
This is the raw subtitle: <h3 class=»topic-list»>Masters @ Work |
 
This is the text header: João Ferreira
This is the text date: Aug 26 |
This is the text subtitle: Masters @ Work |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/138/»>Corwin Harrell</a></h2>
This is the raw date: <span class=»post-date»>Aug 06 |
This is the raw subtitle: <h3 class=»topic-list»>Q&amp;A |
 
This is the text header: Corwin Harrell
This is the text date: Aug 06 |
This is the text subtitle: Q&A |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/137/»>Roberto Machado</a></h2>
This is the raw date: <span class=»post-date»>Aug 03 |
This is the raw subtitle: <h3 class=»topic-list»>CEO @ Subvisual |
 
This is the text header: Roberto Machado
This is the text date: Aug 03 |
This is the text subtitle: CEO @ Subvisual |
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/136/»>James Edward Gray II</a></h2>
This is the raw date: <span class=»post-date»>Jul 30 |
This is the raw subtitle: <h3 class=»topic-list»>Screencasting |
 
This is the text header: James Edward Gray II
This is the text date: Jul 30 |
This is the text subtitle: Screencasting |

На данный момент у нас уже есть некоторые данные для игры. Мы можем структурировать или разделить его так, как нам нравится. Вышесказанное должно просто показать, что у нас читается. Конечно, мы можем углубиться в каждое из них, используя регулярные выражения с методом text .

Мы рассмотрим это более подробно, когда приступим к решению проблемы с подкастами. Это не будет урок по регулярному выражению, но вы увидите еще кое-что в действии — но не беспокойтесь, не настолько, чтобы заставить ваш мозг кровоточить.

На этом этапе может быть полезно извлечь информацию для отдельных эпизодов. Это не может быть проще.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
articles = page.css(«article.index-article»)
 
articles.each do |article|
  header = article.at_css(«h2.post-title»)
  date = article.at_css(«.post-date»)
  subtitle = article.at_css(«.topic-list»)
  link = article.at_css(«h2.post-title a»)
  podcast_url = «http://betweenscreens.fm/»
 
  puts «This is the raw header: #{header}»
  puts «This is the raw date: #{date}»
  puts «This is the raw subtitle: #{subtitle}»
  puts «This is the raw link: #{link}\n\n»
 
  puts «This is the text header: #{header.text}»
  puts «This is the text date: #{date.text}»
  puts «This is the text subtitle: #{subtitle.text}»
  puts «This is the raw link: #{podcast_url}#{link[:href]}\n\n»
end

Наиболее важные биты, на которые следует обратить внимание, это [:href] и podcast_url . Если вы пометите [:] вы можете просто извлечь атрибут из целевого селектора. Я немного абстрагировался, но вы можете увидеть более четко, как это работает ниже.

1
2
3
4
5
 
href = article.at_css(«h2.post-title a»)[:href]
 

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

1
2
3
4
5
6
7
 
podcast_url = «http://betweenscreens.fm/»
 
puts «This is the raw link: #{podcast_url}#{link[:href]}\n\n»
 

Давайте кратко рассмотрим вывод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
This is the raw header: <h2 class=»post-title»><a href=»episodes/143/»>Jason Long</a></h2>
This is the raw date: <span class=»post-date»>Oct 25 |
This is the raw subtitle: <h3 class=»topic-list»>Open source |
This is the raw link: <a href=»episodes/143/»>Jason Long</a>
 
This is the text header: Jason Long
This is the text date: Oct 25 |
This is the text subtitle: Open source |
This is the href: http://betweenscreens.fm/episodes/143/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/142/»>David Heinemeier Hansson</a></h2>
This is the raw date: <span class=»post-date»>Oct 18 |
This is the raw subtitle: <h3 class=»topic-list»>Rails community |
This is the raw link: <a href=»episodes/142/»>David Heinemeier Hansson</a>
 
This is the text header: David Heinemeier Hansson
This is the text date: Oct 18 |
This is the text subtitle: Rails community |
This is the href: http://betweenscreens.fm/episodes/142/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/141/»>Zach Holman</a></h2>
This is the raw date: <span class=»post-date»>Oct 12 |
This is the raw subtitle: <h3 class=»topic-list»>Getting Fired |
This is the raw link: <a href=»episodes/141/»>Zach Holman</a>
 
This is the text header: Zach Holman
This is the text date: Oct 12 |
This is the text subtitle: Getting Fired |
This is the href: http://betweenscreens.fm/episodes/141/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/140/»>Joel Glovier</a></h2>
This is the raw date: <span class=»post-date»>Oct 10 |
This is the raw subtitle: <h3 class=»topic-list»>Digital Product Design |
This is the raw link: <a href=»episodes/140/»>Joel Glovier</a>
 
This is the text header: Joel Glovier
This is the text date: Oct 10 |
This is the text subtitle: Digital Product Design |
This is the href: http://betweenscreens.fm/episodes/140/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/139/»>João Ferreira</a></h2>
This is the raw date: <span class=»post-date»>Aug 26 |
This is the raw subtitle: <h3 class=»topic-list»>Masters @ Work |
This is the raw link: <a href=»episodes/139/»>João Ferreira</a>
 
This is the text header: João Ferreira
This is the text date: Aug 26 |
This is the text subtitle: Masters @ Work |
This is the href: http://betweenscreens.fm/episodes/139/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/138/»>Corwin Harrell</a></h2>
This is the raw date: <span class=»post-date»>Aug 06 |
This is the raw subtitle: <h3 class=»topic-list»>Q&amp;A |
This is the raw link: <a href=»episodes/138/»>Corwin Harrell</a>
 
This is the text header: Corwin Harrell
This is the text date: Aug 06 |
This is the text subtitle: Q&A |
This is the href: http://betweenscreens.fm/episodes/138/
 
This is the raw header: <h2 class=»post-title»><a href=»episodes/137/»>Roberto Machado</a></h2>
This is the raw date: <span class=»post-date»>Aug 03 |
This is the raw subtitle: <h3 class=»topic-list»>CEO @ Subvisual |
This is the raw link: <a href=»episodes/137/»>Roberto Machado</a>
 
This is the text header: Roberto Machado
This is the text date: Aug 03 |
This is the text subtitle: CEO @ Subvisual |
This is the href: http://betweenscreens.fm/episodes/137/

Аккуратно, не правда ли? Вы можете сделать то же самое, чтобы извлечь [:class] селектора.

1
2
3
4
5
6
7
8
9
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
body_classes = page.at_css(«body»)[:class]

Если этот узел имеет более одного класса, вы получите список всех из них.

  • родитель
  • дети
  • previous_sibling
  • next_sibling

Мы привыкли иметь дело с древовидными структурами в CSS или даже с jQuery. Было бы больно, если бы Nokogiri не предлагал удобный API для перемещения по таким деревьям.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
header = page.at_css(«h2.post-title»)
header_children = page.at_css(«h2.post-title»).children
header_parent = page.at_css(«h2.post-title»).parent
header_prev_sibling = page.at_css(«h2.post-title»).previous_sibling
 
puts «#{header}\n\n»
puts «#{header_children}\n\n»
puts «#{header_parent}\n\n»
puts «#{header_prev_sibling}\n\n»
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
#header
<h2 class=»post-title»><a href=»episodes/143/»>Jason Long</a></h2>
 
#header_children
<a href=»episodes/143/»>Jason Long</a>
 
#header_parent
<article class=»index-article»>
  <span class=»post-date»>Oct 25 |
    <h3 class=»topic-list»>Open source |
    <div class=»soundcloud-player-small»>
    </div>
</article>
 
#header_previous_sibling
<span class=»post-date»>Oct 25 |

Как вы сами видите, это довольно мощный материал, особенно когда вы видите, что .parent удалось собрать за один раз. Вместо того, чтобы определять кучу узлов вручную, вы можете собрать их оптом.

Вы можете даже связать их для более сложных прохождений. Конечно, вы можете принять это так сложно, как захотите, но я бы предостерег вас от простоты. Это может быстро стать немного громоздким и трудным для понимания. Помните: «Будьте проще, глупый!»

1
2
3
4
5
6
 
header_parent_parent = page.at_css(«h2.post-title»).parent.parent
header_prev_sibling_parent_children = page.at_css(«h2.post-title»).previous_sibling.parent.children
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
require ‘nokogiri’
 
require «open-uri»
 
url = ‘http://betweenscreens.fm/’
 
page = Nokogiri::HTML(open(url))
 
header = page.at_css(«h2.post-title»)
header_prev_sibling_children = page.at_css(«h2.post-title»).previous_sibling.children
header_parent_parent = page.at_css(«h2.post-title»).parent.parent
header_prev_sibling_parent = page.at_css(«h2.post-title»).previous_sibling.parent
header_prev_sibling_parent_children = page.at_css(«h2.post-title»).previous_sibling.parent.children
 
puts «#{header}\n\n»
puts «#{header_prev_sibling_children}\n\n»
puts «#{header_parent_parent}\n\n»
puts «#{header_prev_sibling_parent}\n\n»
puts «#{header_prev_sibling_parent_children}\n\n»
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#header
<h2 class=»post-title»><a href=»episodes/143/»>Jason Long</a></h2>
 
#header_previous_sibling_children
Oct 25 |
 
#header_parent_parent
<li>
  <article class=»index-article»>
  <span class=»post-date»>Oct 25 |
    <h3 class=»topic-list»>Open source |
    <div class=»soundcloud-player-small»>
    </div>
  </article>
</li>
 
#header_previous_sibling_parent
<article class=»index-article»>
  <span class=»post-date»>Oct 25 |
    <h3 class=»topic-list»>Open source |
    <div class=»soundcloud-player-small»>
    </div>
</article>
 
#header_previous_sibling_parent_children
  <span class=»post-date»>Oct 25 |
    <h3 class=»topic-list»>Open source |
    <div class=»soundcloud-player-small»>
    </div>

Nokogiri — не огромная библиотека, но есть что предложить. Я рекомендую вам поиграть с тем, что вы уже узнали, и расширить свои знания с помощью документации, когда вы врезаетесь в стену. Но не попадите в неприятности!

Это небольшое вступление должно помочь вам понять, что вы можете сделать и как это работает. Я надеюсь, что вы исследуете это немного больше самостоятельно и повеселитесь с этим. Как вы сами поймете, это богатый инструмент, который продолжает давать.