Advertisement
  1. Code
  2. Ruby
Code

بناء اول web scraper خاص بك، الجزء 3

by
Length:LongLanguages:

Arabic (العربية/عربي) translation by Ayman Amar (you can also view the original English article)

مرحبا بك مرة أخرى في هذه السلسلة لإنشاء مستخرج الويب "web scraper". في هذا البرنامج التعليمي، سأبدأ من مثال على استخراج البيانات من موقع التدوين الخاص بي. سوف أشمل بالتفصيل كيف استخرجت البيانات، وكيفية المساعد والوسائل المساعدة على إنجاز وظائفهم، وكيفية تجميع كل قطع اللغز معا.

المواضيع

  • استخراج التدوينة الخاصة بي
  • النقب
  • المستخرج
  • طرق مساعدة
  • كتابة المشاركات

استخراج التدوينة الخاصة بي

دعونا نضع ما تعلمناه حتى الآن في الممارسة العملية. لأسباب مختلفة، إعادة تصميم التدوينة الخاصة بي بين | شاشات كانت بالغة التأخير. كانت هناك مشاكل جعلتني أصرخ عندما استيقظت في الصباح. لذلك قررت إنشاء موقع ثابت جديد كليا، بواسطة Middleman واستضافة صفحات GitHub.

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

القيام بذلك يدويا في schmuck fashion لم يكن على الطاولة - ولا حتى سؤال - لأنني بإمكاني الإعتماد على أصدقائي نوكوجيري و مشانيز للقيام بهذه المهمة لأجلي. ما أمامك هو وظيفة استخراج صغيرة إلى حد معقول ليست معقدة جدا ولكن تقدم بعض التقلبات المثيرة للاهتمام التي ينبغي أن تكون تعليمية لمستجدين مستخرج الويب.

فيما يلي لقطتين من التدوينة الخاصة بي.

لقطة شاشة للتدوينة القديمة

A screenshot of an old podcast

لقطة شاشة للتدوينة الجديدة

A screenshot of a new podcast

دعونا نقوم بما نريد تحقيقه. نريد استخراج البيانات التالية من 139 حلقة موزعة على 21 موقع فهرس صفحات:

  • العنوان
  • الضيف
  • الرؤوس الفرعية مع قائمة الموضوعات
  • رقم مقطوعة SoundCloud لكل حلقة
  • تاريخ
  • الحلقة رقم
  • النص من ملاحظات العرض
  • الروابط من ملاحظات العرض

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

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

def compose_markdown

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

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

على طول الطريق، أنا أشجعك بشدة لبدء التفكير في كيف يمكنك تحسين التعليمات البرمجية أمامك. ستكون هذه مهمتك النهائية في نهاية هذه المقالة. تلميح صغير مني: كسر طرق كبيرة في أصغر منها هو دائما نقطة انطلاق جيدة. بمجرد أن تفهم كيف يعمل رمز، سوف يكون لديك وقت ممتع لصقل اعادة بناء التعليمات البرمجية هذه.

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

الرمز كامل

لماذا لم نحتج إلى "Nokogiri"؟ Mechanize يوفر لنا مع كل احتياجاتنا للإستخراج. كما ناقشنا في المقالة السابقة، Mechanize يبني فوق Nokogiri ويسمح لنا لاستخراج المحتوى كذلك. ومع ذلك، كان من المهم تغطية هذا الجوهر في المقالة الأولى منذ أن كنا بحاجة إلى بناء فوقها.

النقب

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

إذا قمت بوضع Pry.start (ملزمة) في أي مكان في الرمز الخاص بك، يمكنك فحص التطبيق الخاص بك في هذه النقطة بالضبط. يمكنك النقب في الأشياء في نقاط محددة في التطبيق. هذا مفيد حقا لاتخاذ التطبيق الخاص بك خطوة بخطوة دون التعثر. على سبيل المثال، دعنا نضعها مباشرة بعد وظيفة write_page، ونعرف ما إذا كان الرابط هو ما نتوقعه أم لا.

النقب

إذا قمت بتشغيل البرمجة، سوف تحصل على شيء من هذا القبيل.

الإخراج

بعد ذالك عندما نطلب كائن الرابط، يمكننا التحقق مما إذا كنا على الطريق الصحيح قبل أن ننتقل إلى تفاصيل التنفيذ الأخرى.

طرفية

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

المستخرج

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

podcast_scraper.rb

ماذا يحدث في طريقة الاستخراج؟ أولا وقبل كل شيء، عقدت كل صفحة فهرس في المدونة القديمة. أنا أستخدم عنوان URL القديم من تطبيق Heroku بما أن الموقع الجديد هو بالفعل على الانترنت في betweenscreens.fm. كان لدي 20 صفحة من الحلقات التي كنت بحاجة إلى عقدها.

حددت العقدة عبر المتغير link_range، الذي قمت بتحديثه مع كل عقدة. كانت عملية ترقيم الصفحات بسيطة مثل استخدام هذا المتغير في عنوان URL لكل صفحة. بسيطة وفعالة.

def scrape

ثم، كلما حصلت على صفحة جديدة مع ثماني حلقات أخرى للإستخراج، استخدم page.links لتحديد الروابط التي نريد النقر عليها والمتابعة إلى صفحة التفاصيل لكل حلقة. قررت أن أستعمل مجموعة من الروابط (الروابط [2..8]) لأنها كانت متسقة في كل صفحة. وكانت أيضا أسهل طريقة لاستهداف الروابط التي أحتاج إليها من كل صفحة فهرس. لا حاجة للخطأ حولها مع محددات CSS هنا.

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

def write_page

def extract_data

كما ترون أعلاه، نأخذdetails_page وتطبيق مجموعة من أساليب الاستخراج على ذلك. نستخرج intervieweetitlesc_idtextepisode_title و episode_number. لقد قمت بإعادة بناء التعليمات البرمجية مجموعة من الأساليب التي تركز على المساعد والمسؤولة عن الاستخراج. دعونا نلقي نظرة سريعة عليها:

أساليب المساعد

أساليب الاستخراج

لقد استخرجت هذه المساعدات لأنها مكنتني من الحصول على أساليب أصغر عموما. كما أن إحتواء سلوكهم كان مهم أيضا. الرمز يقرأ أفضل كذلك. معظمهم يأخذ detail_page كحجة ويستخرج بعض البيانات المحددة التي نحتاجها لمنشورات Middleman الخاصة بنا.

نحن نبحث في الصفحة على محدد خاص وللحصول على النص دون مساحة بيضاء لا حاجة لها.

نأخذ العنوان ونزيله ؟ و # هذه لا تشتغل بشكل جيد مع المسألة الأمامية في المشاركات لحلقاتنا. المزيد من المعلومات حول المسألة الأمامية أدناه.

هنا نحن بحاجة إلى العمل أصعب قليلا لاستخراج معرف SoundCloud للمقطوعات المستضافة الخاصة بنا. أولا نحن بحاجة إلى جعل iframes ألية مع href  من soundcloud.com وجعلها سلسلة للمسح ...

ثم تطابق تعبيرا عاديا للأرقام من معرف القطعة الخاصة بنا soundcloud_id "221003494".

استخراج ملاحظات العرض مرة أخرى واضح تماما. نحن بحاجة فقط للبحث عن فقرات ملاحذات العرض في صفحة التفاصيل. لا مفاجآت هنا.

وينطبق الشيء نفسه على العنوان الفرعي، إلا أنه مجرد إعداد لاستخراج نظيف لرقم الحلقة منه.

هنا نحن بحاجة لجولة أخرى من التعبير العادي. دعونا نلقي نظرة قبل وبعد تطبيقنا للتعبير العادي.

episode_subtitle

العدد

خطوة واحدة أخرى حتى يصبح لدينا رقم نظيف.

نحن نأخذ هذا الرقم مع تجزئة # ونزيلها. فوالا، لدينا أول رقم حلقة 139 مستخرجة كذلك. أقترح أن علينا أن ننظر إلى الوسائل المساعدة الأخرى قبل أن نجمع كل ذلك معا.

الوسائل المساعدة

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

def clean_date

نشغل تعبير عادي آخر يبحث عن مواعيد مثل هذا: "26 أغسطس 2015". كما ترون، هذا ليس مفيدا جدا بعد. عن طريق string_date نخرج من العنوان الفرعي، نحتاج إلى إنشاء كائن تاريخ حقيقي. وإلا فإنه سيكون عديم الفائدة لإنشاء منشورات Middleman .

string_date

لذلك نأخذ هذه السلسلة للقيام ب Date.parse. النتيجة تبدو واعدة أكثر.

التاريخ

def build_tags

هذه تأخد العنوان والمقابلة التي تراكمت لدينا داخل أسلوب extract_data وتزيل كل الأحرف الأنابيب والخردة. نحن نستبدل أحرف الأنابيب بفاصلة، @،؟، #، و & بسلسلة فارغة، وأخيرا نهتم بالاختصارات ل with.

def strip_pipes

وفي النهاية، ندرج اسم الضيف في قائمة العلامات أيضا، والفصل بين العلامات بفاصلة.

قبل

بعد

ستؤدي كل واحدة من هذه العلامات إلى رابط لمجموعة من المشاركات لهذا الموضوع. يحدث كل هذا ضمن أسلوب extract_data. دعونا نلقي نظرة أخرى أين نحن:

def extract_data

كل ما تبقى للقيام به هو العودة لتجزئة الخيارات مع البيانات التي استخرجناها. يمكننا تغذية هذه التجزئة في أسلوب compose_markdown، والذي يجعل بياناتنا جاهزة لكونها مكتوبة كملف الذي أحتاجه لموقعي الجديد.

كتابة المشاركات

def compose_markdown

لنشر حلقات مدونة على موقع Middleman الخاص بي، اخترت إعادة استخدام نظام التدوين. بدلا من إنشاء مشاركات "نقية" في المدونة، أنشئ ملاحظات عرض لحلقاتي التي تعرض بإستضافة SoundCloud  عبر iframes. على مواقع الفهرس، أعرض فقط iframe بالإضافة إلى العنوان والأدوات.

الصيغة التي أحتاجها لهذا العمل تتكون من شيء يسمى المادة الأمامية. هذا في الأساس مخزن ل مفتاح/قيمة لمواقعي الثابتة. هذا استبدال احتياجات قاعدة البيانات الخاصة بي من موقع Sinatra القديم الخاص بي.

البيانات مثل اسم الشخص الذي تمت مقابلته، والتاريخ،معرف SoundCloud للقصعة، ورقم الحلقة وما إلى ذالك يذهب بين ثلاث شرطات (---) على رأس ملفات الحلقة لدينا. في ما يلي محتوى كل حلقة - مثل الأسئلة والروابط والأدوات الراعية وما إلى ذلك.

المسألة الأمامية

في أسلوبcompose_markdown، يمكنني استخدام HEREDOC لإنشاء هذا الملف مع المسألة الأمامية لكل حلقة نلتف حولها. من تجزئة الخيارات سوف نقوم بتغذية هذا الأسلوب، سوف نستخراج كافة البيانات التي جمعناها في أسلوب المساعد extract_data.

def compose_markdown

هذا هو المخطط لحلقة التدوينة جديدة هناك. هذا هو ما جئنا لأجله. ربما تتساءل عن هذا التركيب الخاص: #{options[:interviewee]}. أنا أقتحم كالمعتاد مع السلاسل، ولكن بما أنني بالفعل بداخل <<-HEREDOC، يمكن أن أترك مزدوجة اللإقتباس مفتوحة.

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

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

def write_page

ثم نحن بحاجة فقط إلى أخد file_name و markdown_text وكتابة الملف.

def write_page

دعونا نكسر هذا أسفله أيضا. لكل مشاركة، أحتاج إلى تنسيق معين: شيء مثل 2016-10-25-Avdi-Grimm-120. أريد أن أكتب الملفات التي تبدأ مع التاريخ وتشمل اسم الضيف ورقم الحلقة.

لتتناسب مع صيغة Middleman المتوقع للحصول على مشاركات جديدة، أنا بحاجة إلى أخذ اسم الضيف ووضعه من خلال أسلوب المساعد الخاص بي لتضييق الاسم بالنسبة لي، من Avdi Grimm إلى Avdi-Grimm. لا شيء سحري، ولكن يستحق نظرة:

def dasherize

هذا يزيل المسافة البيضاء من النص المستخرج لاسم الضيف ويحل محل المسافة البيضاء بين Avdi وGrimm  مع تقطع. أما بقية اسم الملف فهي متقطعة معا في السلسلة نفسها: "date-interviewee-name-episodenumber".

def write_page

وبما أن المحتوى المستخرج يأتي مباشرة من موقع HTML، لا يمكنني ببساطة استخدام .md أو .markdown كملحق لاسم الملف. قررت أن أختار .html.erb.md. للحلقات المستقبلية التي أنشئ دون إستخراج، يمكنني ترك جزء .html.erb وأحتاج فقط ل .md.

بعد هذه الخطوة، تنتهي حلقة في وظيفة الإستخراج، ويجب أن يكون لدينا حلقة واحدة التي تبدو هكذا:

2014-12-01-Avdi-Grimm-1.html.erb.md

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

كل ذلك كان مقفل سابقا في قاعدة البيانات الخاصة بي ل تطبيق Sinatra حلقة عدد والتاريخ واسم الضيف، وما إلى ذالك. الآن لدينا هذه جاهزة لتكون جزءا من موقع Middleman الجديد الثابت الخاص بي. كل شيء تحت الشرطتين الثلاثية (---) هو النص من ملاحظات العرض: الأسئلة والروابط غالبا.

افكار اخيرة

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

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

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

ولكن كما هو الحال دائما، اتخدها خطوة واحدة في كل مرة، ولا تحبط إذا لم تقم بالأشياء على الفور. هذا فقط ليس طبيعيا بالنسبة لمعظم الناس لاكن متوقع. انها جزء من الرحلة. مستخرج سعيد!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.