كيف تتخلص من روبي ونوكوجيري وتعيين البيانات

روبي ، JSON ، و Nokogiri

أحيانًا تريد الحصول على البيانات من موقع ويب لمشروعك الخاص. وذلك ما تستخدمه؟ روبي ، نوكوجيري ، وجسون لإنقاذ!

في الآونة الأخيرة ، كنت أعمل في مشروع لتعيين بيانات حول الجسور. باستخدام Nokogiri ، تمكنت من التقاط بيانات جسر المدينة من جدول. بعد ذلك استخدمت الروابط الموجودة في نفس الجدول لكشط الصفحات المرتبطة. أخيرًا ، قمت بتحويل البيانات المحشورة إلى JSON واستخدمتها لملء خريطة Google.

ترشدك هذه المقالة إلى الأدوات التي استخدمتها وكيف تعمل الشفرة!

انظر الكود الكامل على بلدي GitHub repo.

عرض خريطة حية هنا.

المشروع

كان هدفي هو أخذ جدول من موقع ويب بيانات الجسر وتحويله إلى خريطة Google مع دبابيس تحديد الموقع الجغرافي من شأنها أن تنتج النوافذ المنبثقة المعلوماتية لكل جسر.

الفكرة: HTML الجدول إلى الخريطة

لتحقيق ذلك ، سأحتاج إلى:

  1. كشط البيانات من الموقع الأصلي.
  2. تحويل تلك البيانات إلى كائن JSON.
  3. طبّق تلك البيانات لإنشاء خريطة تفاعلية جديدة.

سوف يختلف مشروعك ، بالتأكيد - كم من الأشخاص يحاولون تعيين الجسور العتيقة؟ - ولكني آمل أن تكون هذه العملية مفيدة لسياقك.

Nokogiri

روبي لديه جوهرة مذهلة تجريد الويب تسمى Nokogiri. من بين الميزات الأخرى ، يسمح لك بالبحث في مستندات HTML عن طريق محددات CSS. هذا يعني أننا إذا عرفنا المعرفات أو الفئات أو حتى أنواع العناصر التي يتم تخزين البيانات فيها في DOM ، فيمكننا انتزاعها.

المكشطة

إذا كنت تتابع جنبا إلى جنب مع GibHub repo ، فيمكنك العثور على مكشطة في bridges_scraper.rb

تتطلب "فتح uri"
تتطلب "nokogiri"
تتطلب "json"

يتيح لنا Open-uri فتح HTML مثل الملف ونقله إلى Nokogiri للرفع الثقيل.

في الرمز أدناه ، أقوم بتمرير معلومات DOM من عنوان URL مع نقل بيانات الجسر إلى Nokogiri. ثم أجد عنصر الجدول يحتفظ بالبيانات ، وابحث عن صفوفه ، ويتكرر من خلالها.

url = 'https://bridgereports.com/city/wichita-kansas/'
html = open (url)
doc = Nokogiri :: HTML (html)
الجسور = []
الجدول = doc.at ('الجدول')
table.search ('tr'). كل القيام | tr |
  bridges.push (
    يحمل: خلايا [1].
    الصلبان: الخلايا [2].
    الموقع: الخلايا [3].
    تصميم: خلايا [4].
    الحالة: خلايا [5].
    year_build: خلايا [6] .text.to_i ،
    year_recon: cells [7] .text ،
    span_length: cells [8] .text.to_f ،
    total_length: cells [9] .text.to_f ،
    الحالة: الخلايا [10].
    suff_rating: خلايا [11] .text.to_f ،
    id: خلايا [12] .text.to_i
  )
النهاية
json = JSON.pretty_generate (الجسور)
File.open ("data.json"، 'w') {| file | file.write (json)}

Nokogiri لديه الكثير من الأساليب (إليك ورقة الغش ودليل بدء التشغيل!). نحن نستخدم القليل فقط.

تم العثور على الجدول باستخدام .at ("الجدول") ، والذي يُرجع التكرار الأول لعنصر الجدول في DOM. هذا يعمل بشكل جيد لهذه الصفحة بسيطة نسبيا.

مع وجود الجدول في متناول اليد ، يوفر .search ('tr') مجموعة من عناصر الصف التي نكررها مع .each. في كل صف ، يتم تنظيف البيانات ودفعها في إدخال واحد لصفيف الجسور.

بعد جمع كل الصفوف ، يتم تحويل البيانات إلى JSON وحفظها في ملف جديد يسمى "data.json".

الجمع بين البيانات من صفحات متعددة

في هذه الحالة ، كنت بحاجة إلى معلومات من صفحات أخرى مرتبطة. على وجه التحديد ، كنت بحاجة إلى خطوط الطول والعرض لكل جسر ، والتي لم تكن واردة على الطاولة. ومع ذلك ، فقد وجدت أن الرابط في الخلية الأولى من كل صف أدى إلى صفحة توفر هذه التفاصيل.

كنت بحاجة إلى كتابة التعليمات البرمجية التي فعلت بعض الأشياء:

  • الروابط المجمعة من الخلية الأولى في الجدول.
  • إنشاء كائن Nokogiri جديد من HTML في تلك الصفحة.
  • نتف من خطوط الطول والعرض.
  • نوم البرنامج حتى اكتمال هذه العملية.
خلايا = tr.search ('th، td')
  الروابط = {}
  خلايا [0] .css ('a'). كل منها تفعل | a |
    الروابط [a.text] = a ['href']
  النهاية
  
  got_coords = خطأ
  
  إذا كانت الروابط ['تقرير NBI']
    nbi = الروابط ['تقرير NBI']
    تقرير = "https://bridgereports.com" + nbi
    report_html = open (تقرير)
    النوم 1 حتى 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 = صحيح
  آخر
    got_coords = صحيح
  النهاية
  
  النوم 1 حتى حصلت على __ords == صحيح
  bridges.push (
    الروابط: الروابط ،
    خط العرض: خط الطول ،
    خط الطول: طويل ،
    يحمل: خلايا [1].
    ... ، # جميع أزواج المفتاح / القيمة الأخرى السابقة
  )
النهاية

بعض الأشياء الإضافية تستحق الإشارة هنا:

  • أنا أستخدم "get_coords" كثنائي بسيط. يتم ضبط هذا على "خطأ" افتراضيًا ويتم تبديله عند التقاط البيانات أو ببساطة غير متوفر.
  • توجد خطوط الطول والعرض في مسافات مع فئات المقابلة. وهذا يجعل تأمين البيانات بسيطًا: .css ('span.latitude') ويتبع ذلك النص. و strip و. to_f أيهما 1) يحصل على النص من الامتداد ، 2) يجرد أي مسافة زائدة بيضاء ، و 3) يحول سلسلة إلى عدد تعويم.

JSON → خريطة جوجل

يجب تعديل كائن JSON المكون حديثًا لمسة لتناسب واجهة برمجة تطبيقات خرائط Google. فعلت هذا مع JavaScript داخل map.js

يمكن الوصول إلى بيانات JSON داخل map.js لأنه تم نقلها إلى مجلد JS ، وتم تعيينها لمتغير يسمى "bridge_data" ، وتم تضمينه في علامة