Πώς να ξύσετε με τον Ruby και το Nokogiri και να χαρτογραφήσετε τα δεδομένα

Μερικές φορές θέλετε να πάρετε δεδομένα από έναν ιστότοπο για το δικό σας έργο. Τι χρησιμοποιείτε λοιπόν; Ruby, Nokogiri και JSON για τη διάσωση!

Πρόσφατα, δούλευα σε ένα έργο για τη χαρτογράφηση δεδομένων σχετικά με γέφυρες. Χρησιμοποιώντας το Nokogiri, κατάφερα να καταγράψω δεδομένα γέφυρας μιας πόλης από έναν πίνακα. Στη συνέχεια χρησιμοποίησα συνδέσμους εντός του ίδιου πίνακα για να ξύσω τις σχετικές σελίδες. Τέλος, μετέτρεψα τα αποκομμένα δεδομένα σε JSON και τα χρησιμοποίησα για τη συμπλήρωση ενός Χάρτη Google.

Αυτό το άρθρο σάς καθοδηγεί στα εργαλεία που χρησιμοποίησα και στον τρόπο λειτουργίας του κώδικα!

Δείτε ολόκληρο τον κωδικό στο GitHub repo μου.

Ζωντανή επίδειξη χάρτη εδώ.

Η εργασία

Ο στόχος μου ήταν να πάρω έναν πίνακα από έναν ιστότοπο δεδομένων γεφυρών και να τον μετατρέψω σε χάρτη Google με γεωγραφικά τοποθετημένες καρφίτσες που θα δημιουργούσαν ενημερωτικά αναδυόμενα παράθυρα για κάθε γέφυρα.

Για να συμβεί αυτό, θα πρέπει:

  1. Ξύστε δεδομένα από τον αρχικό ιστότοπο.
  2. Μετατροπή αυτών των δεδομένων σε αντικείμενο JSON.
  3. Εφαρμόστε αυτά τα δεδομένα για να δημιουργήσετε έναν νέο, διαδραστικό χάρτη.

Το έργο σας θα ποικίλει, σίγουρα - πόσα άτομα προσπαθούν να χαρτογραφήσουν αντίκες γέφυρες; - αλλά ελπίζω ότι αυτή η διαδικασία θα αποδειχθεί χρήσιμη για το περιβάλλον σας.

Νόκογκιρι

Το Ruby έχει ένα εκπληκτικό κόσμημα απόξεσης ιστού που ονομάζεται Nokogiri. Μεταξύ άλλων λειτουργιών, σας επιτρέπει να αναζητήσετε έγγραφα HTML από επιλεγμένους CSS. Αυτό σημαίνει ότι αν γνωρίζουμε τα αναγνωριστικά, τις τάξεις ή ακόμη και τους τύπους στοιχείων όπου τα δεδομένα αποθηκεύονται στο DOM, μπορούμε να τα βγάλουμε έξω.

Η ξύστρα

Εάν ακολουθείτε μαζί με το repo GibHub, μπορείτε να βρείτε την ξύστρα μου στο bridges_scraper.rb

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

Το Open-uri μας επιτρέπει να ανοίξουμε το HTML σαν ένα αρχείο και να το μεταβιβάσουμε στο Nokogiri για βαριά ανύψωση.

Στον παρακάτω κώδικα, μεταφέρω τις πληροφορίες DOM από τη διεύθυνση URL με τα δεδομένα γέφυρας στο Nokogiri. Στη συνέχεια, βρίσκω το στοιχείο πίνακα που κρατά τα δεδομένα, ψάχνω για τις σειρές του και επαναλαμβάνω.

url = '//bridgereports.com/city/wichita-kansas/'html = 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.write(json) 

Το Nokogiri έχει πολλές μεθόδους (εδώ είναι ένα cheat sheet και ένας αρχικός οδηγός!). Χρησιμοποιούμε μόνο μερικά.

Ο πίνακας βρίσκεται με το .at ('table') , το οποίο επιστρέφει την πρώτη εμφάνιση ενός στοιχείου πίνακα στο DOM. Αυτό λειτουργεί καλά για αυτήν τη σχετικά απλή σελίδα.

Με τον πίνακα στο χέρι, το .search ('tr') παρέχει μια σειρά από στοιχεία γραμμής που επαναλαμβάνουμε με .each . Σε κάθε σειρά, τα δεδομένα καθαρίζονται και ωθούνται σε μία μόνο καταχώριση για τη σειρά γεφυρών.

Μετά τη συλλογή όλων των σειρών, τα δεδομένα μετατρέπονται σε 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 = "//bridgereports.com" + 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" ως απλό δυαδικό. Αυτό έχει οριστεί ως false από προεπιλογή και εναλλάσσεται όταν τα δεδομένα καταγράφονται Ή ​​απλά δεν είναι διαθέσιμα.
  • Το γεωγραφικό πλάτος και το μήκος βρίσκονται σε εκτάσεις με αντίστοιχες κλάσεις. Αυτό καθιστά την ασφάλιση του απλού δεδομένα: .css ( «span.latitude») Αυτό ακολουθείται από .text, .strip και .to_f οποία 1) παίρνει το κείμενο από το άνοιγμα, 2) λωρίδες οποιαδήποτε περίσσεια κενά, και 3) μετατρέπει τα συμβολοσειρά σε αριθμό float.

JSON → Χάρτης Google

Το νέο αντικείμενο JSON πρέπει να τροποποιηθεί με ένα άγγιγμα ώστε να ταιριάζει στο API Χαρτών Google. Το έκανα με JavaScript μέσα στο map.js

Τα δεδομένα JSON είναι προσβάσιμα στο map.js επειδή έχουν μετακινηθεί στο φάκελο JS, έχουν αντιστοιχιστεί σε μια μεταβλητή που ονομάζεται "bridge_data" και συμπεριλαμβάνονται σε μια ετικέτα στο index.html.

Εντάξει! Τώρα θα μετατρέψουμε το αρχείο JSON (εκχωρείται στη μεταβλητή Bridge_data) σε έναν νέο πίνακα που μπορεί να χρησιμοποιηθεί από τους Χάρτες Google.

const locations = bridge_data.map(function(b) { var mapEntry = []; var info = "Built In: " + b.year_build + "

" + "Span Length: " + b.span_length + " ft

" + "Total Length: " + b.total_length + " ft

" + "Condition: " + b.condition + "

" + "Design: " + b.design + "

"; mapEntry.push( info, b.latitude, b.longitude, b.id ) return mapEntry;});

Χρησιμοποιώ το .map για να δημιουργήσω έναν νέο πίνακα διαστάσεων που ονομάζεται "τοποθεσίες". Κάθε καταχώριση έχει πληροφορίες, οι οποίες θα εμφανίζονται στο αναδυόμενο παράθυρο των Χαρτών Google εάν ο χρήστης κάνει κλικ σε αυτήν την καρφίτσα στον χάρτη. Περιλαμβάνουμε επίσης το γεωγραφικό πλάτος, το γεωγραφικό μήκος και το μοναδικό αναγνωριστικό γέφυρας.

Το αποτέλεσμα είναι ένας χάρτης Google που απεικονίζει τη σειρά τοποθεσιών με αναδυόμενα παράθυρα πλούσια σε πληροφορίες για κάθε γέφυρα!

Σας βοήθησε αυτό; Δώστε του μερικά χειροκρότημα και ακολουθήστε!