כיצד לגרד עם רובי ונוקוגירי ולמפות את הנתונים

לפעמים אתה רוצה לתפוס נתונים מאתר אינטרנט לפרויקט משלך. אז במה אתה משתמש? רובי, נוקוגירי וג'סון להצלה!

לאחרונה עבדתי על פרויקט למיפוי נתונים על גשרים. באמצעות Nokogiri הצלחתי ללכוד את נתוני הגשר של העיר משולחן. לאחר מכן השתמשתי בקישורים באותה טבלה כדי לגרד דפים משויכים. לבסוף, המיר את הנתונים הגרודים ל- JSON והשתמשתי בהם לאכלוס מפת גוגל.

מאמר זה מדריך את הכלים בהם השתמשתי וכיצד הקוד עובד!

ראה את הקוד המלא ברפי של GitHub שלי.

הדגמת מפה חיה כאן.

הפרויקט

המטרה שלי הייתה לקחת טבלה מאתר נתוני גשר ולהפוך אותה למפת גוגל עם סיכות ממוקמות גיאוגרפיות שיפיקו חלונות קופצים מידעיים לכל גשר.

כדי לגרום לזה לקרות, אצטרך:

  1. גרד נתונים מהאתר המקורי.
  2. המרת נתונים לאובייקט JSON.
  3. החל את הנתונים כדי ליצור מפה חדשה ואינטראקטיבית.

הפרויקט שלך ישתנה, בוודאי - כמה אנשים מנסים למפות גשרים עתיקים? - אבל אני מקווה שתהליך זה יתגלה כשימושי בהקשר שלך.

נוקוגירי

לרובי יש פנינת גירוד אינטרנטית מדהימה בשם Nokogiri. בין יתר התכונות, הוא מאפשר לך לחפש מסמכי HTML לפי בוחרי CSS. פירוש הדבר שאם אנו מכירים את המזהים, המחלקות או אפילו סוגי האלמנטים שבהם הנתונים מאוחסנים ב- DOM, אנו יכולים לשלוף אותם.

המגרד

אם אתה עוקב אחר ריפו GibHub, תוכל למצוא את המגרד שלי ב- bridges_scraper.rb

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

Open-uri מאפשר לנו לפתוח את ה- HTML כמו קובץ ולהעביר אותו ל- Nokogiri לצורך ההרמה הכבדה.

בקוד שלמטה, אני מעביר את מידע ה- DOM מכתובת האתר עם נתוני הגשר לידי נוקוגירי. לאחר מכן אני מוצא את אלמנט הטבלה המחזיק את הנתונים, מחפש את השורות שלו ומעבור דרכם.

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) 

לנוקוגירי יש המון שיטות (הנה גיליון בגידות ומדריך למתחילים!). אנו משתמשים רק בכמה.

הטבלה נמצאת עם .at ('טבלה') , המחזירה את המופע הראשון של אלמנט טבלה ב- 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) ממיר את מחרוזת למספר צף.

JSON → Google Map

יש לשנות את האובייקט JSON שנוגע כדי להתאים ל- API של מפות Google. עשיתי זאת עם JavaScript בתוך map.js

ניתן לגשת לנתוני JSON בתוך map.js מכיוון שהם הועברו לתיקיית JS, הוקצו למשתנה המכונה "bridge_data" ונכללו בתג ב- index.html.

בסדר! כעת נמיר את קובץ JSON (שהוקצה למשתנה bridge_data) למערך חדש שניתן להשתמש בו במפות גוגל.

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 אם המשתמש לוחץ על הסיכה הזו במפה. אנו כוללים גם את קו הרוחב, האורך ותעודת הגשר הייחודית.

התוצאה היא מפת גוגל המתווה את מגוון המיקומים עם חלונות קופצים עשירים במידע לכל גשר!

האם זה עזר לך? תנו לזה כמה מחיאות כפיים ובצעו!