Как скребть с помощью Ruby и Nokogiri и сопоставить данные

1656611890 kak skrebt s pomoshhyu ruby i nokogiri i sopostavit dannye

Эндрю Бейлза

wyKNKmXzrlVgCz82nl0TcZG1obswvgcheAUI
Ruby, JSON и Nokogiri

Иногда вы хотите получить данные с веб-сайта для вашего собственного проекта. Итак, что вы используете? Ruby, Nokogiri и JSON в помощь!

Недавно я работал над проектом картографирования данных о мостах. Используя Nokogiri, я мог получить данные моста города из таблицы. Затем я использовал ссылку в той же таблице, чтобы очистить связанные страницы. Наконец я превратил собранные данные в JSON и использовал их для заполнения карты Google.

В этой статье вы узнаете, какие инструменты я использовал и как работает код!

Полный код смотрите в моем репозитории GitHub.

Живая демонстрация карты здесь.

Проект

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

pTodl03NV9GsnFl6mYtcO0-rPk6F8AUjRyBb
Идея: HTML-таблица для отображения

Чтобы это произошло, мне нужно:

  1. Снимите данные с оригинального веб-сайта.
  2. Превратите эти данные в объект JSON.
  3. Используйте данные для создания новой интерактивной карты.

Ваш проект, конечно, будет отличаться – сколько людей пытаются нанести на карту старинные мосты? — но я надеюсь, что этот процесс будет полезен вашему контексту.

Нокогири

У Ruby есть удивительный драгоценный камень, который называется Нокогири. Среди других функций он позволяет искать документы HTML с помощью селекторов CSS. Это означает, что если мы знаем идентификаторы, классы или даже типы элементов, где данные хранятся в DOM, мы сможем их удалить.

Скребок

Если вы следите за репо GibHub, вы можете найти мой скрепер на bridges_scraper.rb

require 'open-uri'require 'nokogiri'require 'json'

Open-uri позволяет нам открывать HTML как файл и передавать его Нокогири для тяжелой работы.

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

url=" = open(url)
doc = Nokogiri::HTML(html)bridges = []table = doc.at('table')
table.search('tr').each do |tr|  bridges.push(    carries: cells[1].text,    crosses: cells[2].text,    location: cells[3].text,    design: cells[4].text,    status: cells[5].text,    year_build: cells[6].text.to_i,    year_recon: cells[7].text,    span_length: cells[8].text.to_f,    total_length: cells[9].text.to_f,    condition: cells[10].text,    suff_rating: cells[11].text.to_f,    id: cells[12].text.to_i  )end
json = JSON.pretty_generate(bridges)File.open("data.json", 'w') { |file| file.write(json) }

У Nokogiri есть много методов (вот шпаргалка и руководство для начала!). Мы используем только несколько.

Таблица найдена с .at(‘таблица’), возвращающий первое вхождение элемента таблицы в DOM. Это отлично работает для этой относительно простой страницы.

Со столом в руках, .search(‘tr’) предоставляет массив элементов строки, которые мы берем .каждый. В каждой строке данные очищаются и помещаются в одну запись для массива мостов.

После того, как собраны все строки, данные преобразуются в JSON и сохраняются в новом файле под названием «data.json».

Объединение данных по нескольким страницам

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

Мне нужно было написать код, который бы выполнял несколько вещей:

  • Собранные ссылки из первой ячейки таблицы.
  • Создан новый объект Nokogiri из HTML на этой странице.
  • Определите широту и долготу.
  • Переведите программу в спящий режим, пока этот процесс не завершится.
cells = tr.search('th, td')  links = {}  cells[0].css('a').each do |a|    links[a.text] = a['href']  end    got_coords = false    if links['NBI report']    nbi = links['NBI report']    report = " + nbi    report_html = open(report)    sleep 1 until report_html    r = Nokogiri::HTML(report_html)        lat = r.css('span.latitude').text.strip.to_f    long = r.css('span.longitude').text.strip.to_f
    got_coords = true  else    got_coords = true  end    sleep 1 until got_coords == true
  bridges.push(        links: links,        latitude: lat,        longitude: long,        carries: cells[1].text,        ..., # all other previous key/value pairs  )end

Здесь следует обратить внимание на несколько дополнительных вещей:

  • Я использую got_coords как простой двоичный файл. Это установлено на ошибочный по умолчанию и переключается, когда данные захвачены ИЛИ просто недоступны.
  • Широта и долгота расположены в промежутках с соответствующими классами. Это упрощает защиту данных: .css(‘span.latitude’) За этим следует .текст, .полоска и .to_f который 1) получает текст из span; 2) удаляет любые лишние пробелы и 3) превращает строку в число с плавающей точкой.

JSON → Карта Google

Обновленный объект JSON необходимо изменить, чтобы он соответствовал API Карт Google. Я сделал это с помощью JavaScript внутри map.js

Данные JSON доступны внутри map.js поскольку он был перемещен в папку JS, присвоен переменной под названием «bridge_data» и включен в тег