Парсинг веб-страниц с использованием Nokogiri
Table Of Content
Как говорят, "Парси то, что тебе дала мама"
Что такое парсинг веб-страниц?
Очень часто при создании приложений нам нужны данные. Данные обычно поступают в виде API (Application Program Interfaces), которые мы находим или разрабатываем сами. Эти API улучшают наши приложения, предоставляя большую часть контента, на котором работают наши страницы, и могут быть настолько обширными, что поиск API, подходящего для ваших нужд, может показаться выигрышем в лотерею.
Однако часто мы оказываемся в ситуации, когда нам нужны данные, которые настолько узкоспециализированы или специфичны, что для них не существует подходящего API. Решение - парсинг веб-страниц. Парсинг веб-страниц - это то, как звучит, "скрэпинг" (скрэпинг) веб-страниц (или, более точно, HTML конкретных страниц) с помощью мелкозубой гребенки, чтобы получить информацию, которую мы хотим использовать сами, не копируя ее дословно.
Например, предположим, вы большой фанат тенниса и создаете приложение, которое позволяет пользователям отслеживать своих любимых игроков Женской теннисной ассоциации (WTA) и их текущие рейтинги, возможно, получая уведомления о их матчах и рейтинговых очках. У нас уже есть проблема. Существует так много игроков WTA, и в любой момент может появиться новые игроки, уходят в отставку, и рейтинги меняются ежедневно. Можно сказать, что маловероятно, что для этого будет API.
Если мы перейдем по адресу https://www.wtatennis.com/rankings/singles, мы увидим список всех игроков и их текущий рейтинг и очки. Это данные, которые мы хотим получить, и мы можем получить их с помощью парсинга. В консоли инструментов разработчика (я использую, конечно, Chrome) вы можете увидеть HTML-код сайта, и когда вы наводите указатель мыши на отдельных игроков, вы можете увидеть точное место в HTML-коде, где находится этот текст, как показано ниже.
Как видите, наша мышь наведена на Ашли Барти и подсвечивается в элементах инструмента. (Мы тебя любим, Аш, поздравляю с уходом на пенсию в 25 лет, это моя мечта). Итак, мы можем найти и выбрать этот <td>
для каждого игрока, пройтись по ним и добавить их в нашу базу данных!
Вот пошаговая инструкция, что мы сделаем.
require 'nokogiri'
require 'open-uri'
require 'pry'
- Получите URL, который вы хотите использовать, и используйте метод open из 'open-uri', чтобы установить его в переменную.
html = URI.open("[http://www.tennisnow.com/Rankings/WTA-Singles.aspx](http://www.tennisnow.com/Rankings/WTA-Singles.aspx)")
- Получите доступ к HTML с помощью Nokogiri и только что созданной переменной html, и установите его в переменную.
doc = Nokogiri::HTML(html)
4a. (Дополнительный рефакторинг) Объедините две предыдущие строки кода.
doc = Nokogiri::HTML(URI.open("[http://www.tennisnow.com/Rankings/WTA-Singles.aspx](http://www.tennisnow.com/Rankings/WTA-Singles.aspx)"))
- Используйте binding.pry, чтобы выбрать нужную вам информацию. Вот что у вас должно получиться на данный момент.
**require** 'nokogiri'
**require** 'open-uri'
**require** 'pry'_def_ create_playerinfo **=** Nokogiri::HTML(URI.open("http://www.tennisnow.com/ Rankings/WTA-Singles.aspx"))binding.pry_end_create_player //вызов функции для входа в сеанс pry
В вашем сеансе pry используйте метод .css для переменной info, чтобы попробовать выбрать нужные элементы. Вы можете выбирать практически все в HTML. Используйте '#' для идентификаторов, "." для классов и обычные кавычки для тегов элементов (например, .css('.thisIsAClass') или .css('#thisIsAnID') или .css('h1')).
Таким образом, мы можем видеть, что имена являются частью таблицы (этот веб-сайт действительно состоит из множества div-элементов, ужас, но, эй, что было бы с парсингом без драмы). В любом случае, кажется, что это хорошее место для начала! Если мы попробуем это, мы должны получить огромный ответ.
pry(main)> info.css('table')
Это выглядит дико, но именно то, что нам нужно! Следующий шаг - найти эти имена.
- Давайте попробуем добавить еще один .css, чтобы выбрать каждое имя.
pry(main)> info.css('table').css('td span')
Это даст нам все спаны для каждой строки. Если мы добавим .text, мы должны получить некоторые данные, которые нам знакомы.
pry(main)> info.css('table').css('td span').text
Как видите, у нас есть каждый td span. Поскольку у каждого игрока есть 3 td span, мы получаем их рейтинг, имя и текущие очки. (Кстати, вау, как Ашли изменилась с момента, когда я начал писать этот блог до того, как я его закончил).
Если мы хотим получить только их имя, нам придется немного поработать, чтобы просеять данные. Вот что я сделал.
_def_ create_player
info **=** Nokogiri::HTML(URI.open("http://www.tennisnow.com/ Rankings/WTA-Singles.aspx")) info.css('table').css('td span').each **do** |player|
_if_ **!**player.text.strip.scan(/\D/).empty?
puts player.text.strip
_end endend_
По сути, поскольку этот веб-сайт состоял из множества div-элементов и мне было трудно выбрать то, что я хотел, я перебрал все <td>``<spans>
и сказал, что если в них нет цифр, выводить их в терминал. Я признаю, что это не красивое решение и надеюсь, что вы найдете что-то лучшее. Но в мире парсинга, если это работает, то это работает.
Дальнейшие шаги
Шаг 8. Вместо того, что у меня в строке 10 выше, если у вас есть модель с именем player, вы можете легко создать игрока в своей базе данных с каждой итерацией, например, так.
Player.create(name: player.text.strip)
И вуаля, за считанные секунды вы добавили всех этих игроков в свою базу данных.
Заключение
Хотя этот блог только касается поверхности парсинга (прошу прощения за эту шутку), важно понимать, что парсинг может быть борьбой, но это стоит того в конце концов. Парсинг можно использовать для экономии часов и даже дней времени, так что попробуйте на своем любимом веб-сайте и посмотрите. Нам есть, за что благодарить гем Nokogiri.
TL:DR;
require 'nokogiri'
require 'open-uri'
require 'pry'
- Получите HTML с веб-сайта, который вы выбрали
doc = Nokogiri::HTML(URI.open("ВСТАВЬТЕСЮДАВАШURL"))
-
Войдите в сеанс pry и используйте метод .css, чтобы найти нужные элементы
-
Используйте эти элементы для заполнения вашей базы данных. Это так просто!
-
Как только вы добьетесь успеха, похвалите себя. Ашли гордится.