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

عندما قررت استخدام scraping_imdb.R للزحف إلى 1000 صفحة
رمز التحسين. استخدام واحد لوظيفة read_html
في هذه المقالة ، سيتم استخدام 100 رابط إلى صفحات مكتبة Labyrinth للتحقق من تشغيل وسرعة الكود.
التغيير الصريح الذي يمكن أن يسرع العملية هو الاستخدام لمرة واحدة لوظيفة الكود "الأبطأ" - read_html
. دعني أذكرك بأنها "تقرأ" صفحة HTML. في الإصدار الأول من الكود الخاص بمواقع الأفلام ، قمت بتشغيل read_html
كل مرة أحتاج فيها للحصول على قيمة (اسم الفيلم ، والسنة ، والنوع ، والتصنيف). الآن تم مسح آثار هذا "العار" من جيثوبا ، لكنها كذلك. لا يوجد أي معنى في هذا ، لأن المتغير الذي تم إنشاؤه باستخدام read_html
يحتوي على معلومات حول الصفحة بأكملها read_html
على بيانات مختلفة عنها ، يكفي html_nodes
هذا المتغير جدًا لوظيفة html_nodes
وعدم البدء في قراءة HTML في كل مرة. بحيث يمكنك توفير الوقت بما يتناسب مع عدد القيم التي تريد الحصول عليها. من Labyrinth ، أحصل على سبع قيم ، على التوالي ، الشفرة التي تستخدم قراءة واحدة فقط لصفحة HTML ستعمل بشكل أسرع سبع مرات. ليس سيئا! ولكن قبل أن "أسرع" مرة أخرى ، سأحاول ونتحدث عن نقاط مثيرة للاهتمام تنشأ عند السحب من موقع Labyrinth.
ميزات تجريف الصفحة في المتاهة
في هذا الجزء ، لن أتطرق إلى إجراءات الحصول على البيانات التي تم ذكرها في المقالة السابقة ومسحها. سوف أذكر فقط تلك اللحظات التي واجهتها لأول مرة عند كتابة رمز لسكرابوكينغ لبيع الكتب.
أولاً ، تجدر الإشارة إلى الهيكل. انها ليست مريحة جدا. على النقيض من ذلك ، على سبيل المثال ، من موقع Read-Cities ، تقدم أقسام من هذا النوع بها "عوامل تصفية فارغة" 17 صفحة فقط. بطبيعة الحال ، فإن جميع الكتب 8011 في هذا النوع "المعاصرة الأجنبية النثر" لا تناسبها.
لذلك ، لم أتوصل إلى أي شيء أفضل من الالتفاف على روابط https://www.labirint.ru/books/ **** مع تمثال نصفي بسيط. بصراحة ، ليست الطريقة هي الأفضل (فقط لأن معظم الكتب "القديمة" ليس لها معلومات باستثناء الاسم وبالتالي فهي غير مجدية عملياً) ، لذلك إذا كان أي شخص يقدم حلاً أكثر أناقة ، فسوف أكون سعيدًا. لكنني اكتشفت أنه تحت الرقم الأول الفخور على موقع Labyrinth ، يوجد كتاب بعنوان "كيفية تكوين لغو" . للأسف ، من المستحيل بالفعل شراء مخزن المعرفة هذا.
يمكن تقسيم جميع العناوين أثناء التعداد إلى نوعين:
- الصفحات الموجودة
- الصفحات غير الموجودة
يمكن تقسيم الصفحات الحالية ، بدورها ، إلى قسمين:
- الصفحات التي تحتوي على جميع المعلومات اللازمة
- الصفحات التي لا تحتوي على جميع المعلومات اللازمة
انتهى بي جدول بيانات يحتوي على سبعة أعمدة:
- ISBN - رقم كتاب ISBN
- السعر - سعر الكتاب
- اسم - عنوان الكتاب
- مؤلف - مؤلف الكتاب
- الناشر - دار النشر
- سنة - سنة النشر
- الصفحة - عدد الصفحات
كل شيء واضح مع الصفحات التي تحتوي على معلومات كاملة ، فهي لا تتطلب أي تغييرات بالمقارنة مع الكود الخاص بمواقع الأفلام.
أما بالنسبة للصفحات التي لا تتوفر فيها بعض البيانات ، فهي ليست بهذه البساطة. البحث في الصفحة سوف يعرض فقط تلك القيم التي يعثر عليها وسوف ينخفض طول المخرجات بعدد العناصر التي لن يجدها. هذا سوف كسر الهيكل كله. لتجنب ذلك ، تمت إضافة بنية if ... else إلى كل وسيطة ، والتي تقدر طول المتجه الذي تم الحصول عليه بعد استخدام دالة html_nodes
وإذا كانت html_nodes
صفرًا ، html_nodes
NA
لتجنب قيم الانحياز.
PUBLISHER <- unlist(lapply(list_html, function(n){ publishing <- if(n != "NA") { publishing_html <- html_nodes(n, ".publisher a") publishing <- if(length(publishing_html) == 0){ NA } else { publishing <- html_text(publishing_html) } } else { NA } }))
ولكن كما يمكنك أن تلاحظ هنا ما يصل إلى اثنين من ifs وكذلك بقدر اثنين آخرين. فقط "الداخلية" إذا..يسلي هي ذات الصلة إلى حل المشكلة المذكورة أعلاه. الخارجي يحل المشكلة مع صفحات غير موجودة.
الصفحات التي لا تحتوي ببساطة على أكثر المشاكل. إذا تم نقل القيم على الصفحات التي تحتوي على بيانات مفقودة ، فعند إرسال إدخال read_html
غير موجود ، ستلقي الدالة خطأ read_html
تنفيذ التعليمات البرمجية. لأن بطريقة ما لا يمكن اكتشاف مثل هذه الصفحات مقدمًا ، فمن الضروري التأكد من أن الخطأ لا يوقف العملية بأكملها.
وظيفة possibly
الحزمة possibly
سوف تساعدنا في هذا. معنى وظائف possibly
(إلى جانب possibly
quietly
safely
) هو استبدال المخرجات المطبوعة للآثار الجانبية (على سبيل المثال ، الأخطاء) بقيمة تناسبنا. possibly
يحتوي على بنية possibly(.f, otherwise)
وإذا حدث خطأ في التعليمات البرمجية ، فبدلاً من إيقاف تنفيذه ، يستخدم القيمة الافتراضية (وإلا). في حالتنا ، يبدو كما يلي:
book_html <- possibly(read_html, "NA")(n)
n هي قائمة بعناوين صفحات الموقع التي قمنا بجمعها. في المخرجات ، نحصل على قائمة بالطول n ، تكون فيه العناصر من الصفحات الموجودة في النموذج "العادي" لوظيفة read_html
، read_html
العناصر من الصفحات غير الموجودة من متجه الأحرف "NA". يرجى ملاحظة أن القيمة الافتراضية يجب أن تكون متجهًا للأحرف ، لأننا سنشير إليها في المستقبل. إذا NA
فقط NA
، كما هو الحال في جزء كود PUBLISHER ، فلن يكون ذلك ممكنًا. لتجنب الالتباس ، يمكنك تغيير القيمة خلاف ذلك من NA إلى أي دولة أخرى.
والآن عد إلى رمز الحصول على اسم الناشر. خارجي إذا ... آخر مطلوب لنفس الأغراض الداخلية ، ولكن فيما يتعلق بالصفحات غير الموجودة. إذا كان المتغير book_html
هو "NA" ، فإن كل من القيم " book_html
" تساوي أيضًا NA
(هنا يمكنك بالفعل استخدام NA
"الحقيقي" بدلاً من المحتال الرمزي). في النهاية ، نحصل على جدول بالشكل التالي:
عاد الآن مع تسريع عملية التجريف.
الحوسبة المتوازية في مقارنة السرعة R. والمخاطر عند استخدام وظيفة read_html
بشكل افتراضي ، يتم تنفيذ جميع العمليات الحسابية في R على نفس المعالج الأساسي. وعلى الرغم من أن هذا النواة المؤسفة يتعرق ، "يتم إلغاء" البيانات من آلاف الصفحات بالنسبة لنا ، فإن بقية رفاقنا "يبردون" عن طريق أداء بعض المهام الأخرى. يساعد استخدام الحوسبة المتوازية على جذب جميع مراكز المعالج لمعالجة / تلقي البيانات ، مما يسرع العملية.
لن أتعمق في تصميم الحوسبة المتوازية على R ، يمكنك قراءة المزيد عنها ، على سبيل المثال ، هنا . الطريقة التي فهمت بها التوازي على R هي إنشاء نسخ من R في مجموعات منفصلة وفقًا لعدد من النواة المشار إليها التي تتفاعل مع بعضها البعض عبر مآخذ .
سوف أخبرك عن الخطأ الذي ارتكبته عند استخدام الحوسبة المتوازية. في البداية ، كانت خطتي هي: استخدام الحوسبة المتوازية ، أحصل على قائمة من 100 "read" read_html
صفحات ، ثم في الوضع العادي ، أحصل فقط على البيانات التي أحتاج إليها. في البداية سارت الأمور على ما يرام: حصلت على قائمة أقضي فيها وقتًا أقل بكثير مما كنت عليه في الوضع العادي R. لكن فقط عندما حاولت التفاعل مع هذه القائمة ، تلقيت خطأ:
Error: external pointer is not valid
ونتيجة لذلك ، أدركت ما هي المشكلة ، بالنظر إلى الأمثلة على الإنترنت ، وبعد ذلك ، وفقًا لقانون المعنى ، وجدت تفسير هنريك بنجتسون في المقالة القصيرة لحزمة المستقبل . الحقيقة هي أن وظائف XML لحزمة xml2
هي كائنات غير قابلة للتصدير.
). هذه الأشياء "مرتبطة" بجلسة R هذه ولا يمكن نقلها إلى عملية أخرى ، حاولت القيام بها. لذلك ، يجب أن تحتوي الوظيفة التي يتم إطلاقها في الحوسبة المتوازية على "دورة كاملة" من العمليات: قراءة صفحة HTML ، وتلقي وتنظيف البيانات اللازمة.
لا يتطلب إنشاء الحوسبة المتوازية نفسها الكثير من الوقت وخطوط التعليمات البرمجية. أول ما تحتاجه هو تنزيل المكتبات. يشير مستودع تخزين Github إلى الحزم اللازمة لأي الطرق. parLapply
هنا الحوسبة المتوازية باستخدام وظيفة parLapply
للحزمة parallel
. للقيام بذلك ، ما doParallel
سوى تشغيل doParallel
( doParallel
parallel
تلقائيًا في هذه الحالة). إذا كنت لا تعرف أو تنسى فجأة عدد النوى في المعالج الخاص بك ، detectCores
عددًا من detectCores
# detectCores - , number_cl <- detectCores()
بعد ذلك ، قم بإنشاء نسخ متوازية من R:
# makePSOCKcluster - R, cluster <- makePSOCKcluster(number_cl) registerDoParallel(cluster)
نكتب الآن وظيفة ستقوم بكل الإجراءات التي نحتاجها. ألاحظ ذلك منذ ذلك الحين يتم إنشاء جلسات جديدة ، ويجب كتابة حزم R التي تستخدم وظائفها في وظيفتنا في نص الوظيفة. في spider_parallel.R ، يؤدي هذا stringr
تشغيل الحزمة stringr
مرتين: أولاً للحصول على عناوين الصفحة ، ثم لمسح البيانات.
ثم لا يختلف الإجراء تقريبًا عن استخدام وظيفة lapply
المعتادة. في parLapply
نقدم قائمة بالعناوين ، parLapply
، والإضافة الوحيدة ، وهي متغير مع المجموعات التي أنشأناها.
# parLapply - lapply big_list <- parLapply(cluster, list_url, scraping_parellel_func) # stopCluster(cluster)
هذا كل شيء ، والآن يبقى مقارنة الوقت الذي تقضيه.
مقارنة بين سرعة الحساب التسلسلية والمتوازية
ستكون هذه هي أقصر نقطة. كانت الحوسبة المتوازية أسرع 5 مرات من المعتاد:
تجريف السرعة دون استخدام الحوسبة المتوازية
تجريف السرعة باستخدام الحوسبة المتوازية
ماذا أقول؟ الحوسبة المتوازية يمكن أن توفر الكثير من وقتك دون خلق أي صعوبات في إنشاء الشفرة. مع زيادة عدد النواة ، ستزداد السرعة بما يتناسب تقريبًا مع عددها. لذلك ، مع بعض التغييرات ، قمنا بتسريع الكود 7 مرات أولاً (توقف عن حساب read_html
في كل خطوة) ، ثم 5 أخرى ، باستخدام حسابات متوازية. توجد مخطوطات العنكبوت بدون الحوسبة المتوازية ، باستخدام الحزم parallel
و foreach
، في المستودع على جيثب.
نظرة عامة صغيرة على حزمة Rcrawler
. مقارنة السرعة.
هناك عدة طرق أخرى لتخليص صفحات HTML في R ، لكنني سأركز على حزمة Rcrawler . الميزة المميزة لها من الأدوات الأخرى في لغة البحث هي القدرة على الزحف إلى المواقع. يمكنك ضبط وظيفة Rcrawler
تحمل الاسم نفسه على عنوان Rcrawler
وستتجاوز الموقع بأكمله بشكل منهجي. يحتوي Rcrawler
على العديد من الحجج لإعداد البحث (على سبيل المثال ، يمكنك البحث عن طريق الكلمات الرئيسية وقطاعات الموقع (مفيدة عندما يتكون الموقع من عدد كبير من الصفحات) وعمق البحث وتجاهل معلمات URL التي تنشئ صفحات مكررة وأكثر من ذلك بكثير. تم بالفعل وضع الدالتين على حسابات متوازية ، يتم تحديدها بواسطة الوسيطتين no_cores
(عدد مراكز المعالج المعنية) و no_conn
(عدد الطلبات المتوازية).
لحالتنا ، التجريد من العناوين المحددة ، هناك وظيفة ContentScraper
. لا يستخدم الحوسبة المتوازية افتراضيًا ، لذلك ستحتاج إلى تكرار جميع عمليات التلاعب التي وصفتها أعلاه. أعجبتني الوظيفة نفسها - فهي توفر العديد من الخيارات لإعداد التجريف وفهمها جيدًا على مستوى حدسي. هنا أيضًا لا يمكنك استخدام if..else للصفحات المفقودة أو القيم المفقودة ، مثل تنفيذ وظيفة لا يتوقف.
# ContentScraper: # CssPatterns - CSS . # ExcludeCSSPat - CSS , . # , CSS CSS , . # ManyPerPattern - FALSE, , # . TRUE, , . # PatternsName - . # c , t_func <- function(n){ library(Rcrawler) t <- ContentScraper(n, CssPatterns = c("#product-title", ".authors", ".buying-price-val-number", ".buying-pricenew-val-number", ".publisher", ".isbn", ".pages2"), ExcludeCSSPat = c(".prodtitle-availibility", ".js-open-block-page_count"), ManyPerPattern = FALSE, PatternsName = c("title", "author", "price1", "price2", "publisher", "isbn", "page")) return(t) }
"، # ContentScraper: # CssPatterns - CSS . # ExcludeCSSPat - CSS , . # , CSS CSS , . # ManyPerPattern - FALSE, , # . TRUE, , . # PatternsName - . # c , t_func <- function(n){ library(Rcrawler) t <- ContentScraper(n, CssPatterns = c("#product-title", ".authors", ".buying-price-val-number", ".buying-pricenew-val-number", ".publisher", ".isbn", ".pages2"), ExcludeCSSPat = c(".prodtitle-availibility", ".js-open-block-page_count"), ManyPerPattern = FALSE, PatternsName = c("title", "author", "price1", "price2", "publisher", "isbn", "page")) return(t) }
"، # ContentScraper: # CssPatterns - CSS . # ExcludeCSSPat - CSS , . # , CSS CSS , . # ManyPerPattern - FALSE, , # . TRUE, , . # PatternsName - . # c , t_func <- function(n){ library(Rcrawler) t <- ContentScraper(n, CssPatterns = c("#product-title", ".authors", ".buying-price-val-number", ".buying-pricenew-val-number", ".publisher", ".isbn", ".pages2"), ExcludeCSSPat = c(".prodtitle-availibility", ".js-open-block-page_count"), ManyPerPattern = FALSE, PatternsName = c("title", "author", "price1", "price2", "publisher", "isbn", "page")) return(t) }
")، # ContentScraper: # CssPatterns - CSS . # ExcludeCSSPat - CSS , . # , CSS CSS , . # ManyPerPattern - FALSE, , # . TRUE, , . # PatternsName - . # c , t_func <- function(n){ library(Rcrawler) t <- ContentScraper(n, CssPatterns = c("#product-title", ".authors", ".buying-price-val-number", ".buying-pricenew-val-number", ".publisher", ".isbn", ".pages2"), ExcludeCSSPat = c(".prodtitle-availibility", ".js-open-block-page_count"), ManyPerPattern = FALSE, PatternsName = c("title", "author", "price1", "price2", "publisher", "isbn", "page")) return(t) }
ولكن مع كل الصفات الإيجابية ، فإن وظيفة ContentScraper
لها ناقص واحد شديد الخطورة - سرعة العمل.
Rcrawler ContentScraper ContentScraper
Rcrawler
دون الحوسبة المتوازية
Rcrawler ContentScraper ContentScraper
Rcrawler
باستخدام الحوسبة المتوازية
لذلك يجب استخدام Rcrawler إذا كنت بحاجة إلى تجاوز الموقع دون تحديد عناوين url أولاً ، وكذلك مع عدد صغير من الصفحات. في حالات أخرى ، تفوق السرعة البطيئة جميع المزايا المحتملة لاستخدام هذه الحزمة.
سأكون ممتنا لأية تعليقات أو اقتراحات أو شكاوى
جيثب مستودع الارتباط
ملفي الشخصي الدائرة