Node.js ، Tor ، Puppeteer و Cheerio: تجريف ويب مجهول

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

  • Puppeteer - للوصول إلى صفحات الويب.
  • Cheerio - لتحليل كود HTML.
  • Tor - لتنفيذ كل طلب من عنوان IP مختلف.

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



تركيب Tor


لنبدأ من البداية - وبالتالي ، أولاً وقبل كل شيء ، قم بتثبيت عميل Tor باستخدام الأمر التالي:

sudo apt-get install tor

إعداد Tor


الآن قم بتكوين عميل Tor. يستخدم التكوين الافتراضي لـ Tor منفذ SOCKS ، الذي يعطينا مسارًا واحدًا لعقدة إخراج واحدة (أي عنوان IP واحد). للاستخدام اليومي لـ Tor ، مثل مجرد تصفح الويب ، هذا مناسب تمامًا. لكننا بحاجة إلى بعض عناوين IP. سيسمح لك ذلك بالتبديل بينهما أثناء عملية إلغاء الويب.

من أجل تكوين Tor كما نحتاج ، نحن ببساطة نفتح منافذ إضافية للاستماع إلى اتصالات SOCKS. يتم ذلك عن طريق إضافة عدة إدخالات SocksPortإلى ملف التكوين الرئيسي للبرنامج ، والذي يمكن العثور عليه في /etc/tor.

افتح الملف /etc/tor/torrcباستخدام بعض محرر النصوص وأضف الإدخالات التالية إلى نهاية الملف:

#  4 SOCKS-,       Tor-.

SocksPort 9050
SocksPort 9052
SocksPort 9053
SocksPort 9054

هنا يجدر الانتباه إلى ما يلي:

  • SocksPort . — , , SOCKS, .
  • SocksPort , , , - .
  • 9050 — , Tor- .
  • 9051. Tor , , , Tor.
  • 9051, , 1.

لتطبيق التغييرات التي تم إجراؤها على ملف التكوين ، أعد تشغيل عميل Tor:

sudo /etc/init.d/tor restart

إنشاء مشروع Node.js جديد


إنشاء دليل جديد للمشروع. دعنا ندعوها superWebScraping:

mkdir superWebScraping

دعنا نذهب إلى هذا الدليل ونهيئ مشروع عقدة فارغ:

cd superWebScraping && npm init -y

قم بتعيين التبعيات اللازمة:

npm i --save puppeteer cheerio

العمل مع مواقع الويب باستخدام Puppeteer


Puppeteer هو متصفح بدون واجهة مستخدم يستخدم بروتوكول DevTools للتفاعل مع Chrome أو Chromium . سبب عدم استخدامنا للمكتبة هنا للتعامل مع الطلبات ، مثل طلب Tor ، هو أن هذه المكتبة لن تكون قادرة على معالجة المواقع التي تم إنشاؤها كتطبيقات ويب من صفحة واحدة يتم تحميل محتوياتها ديناميكيًا.

قم بإنشاء ملف index.jsووضع التعليمات البرمجية التالية فيه. يتم وصف الميزات الرئيسية لهذا الرمز في التعليقات.

/**
 *   puppeteer.
 */
const puppeteer = require('puppeteer');

/**
 *   main  , 
 *     -.
 * ,      ,
 *   ,     
 *  puppeteer.
 */
async function main() {
  /**
   *  Chromium.   `headless`   false,
   *     .
   */
  const browser = await puppeteer.launch({
    headless: false
  });

  /**
   *   .
   */
  const page = await browser.newPage();

  /**
   *   ,   https://api.ipify.org.
   */
  await page.goto('https://api.ipify.org');

  /**
   *  3     .
   */
  setTimeout(() => {
    browser.close();
  }, 3000);
}

/**
 *  ,  main().
 */
main();

قم بتشغيل البرنامج النصي باستخدام الأمر التالي:

node index.js

بعد ذلك ، يجب أن تظهر نافذة متصفح Chromium على الشاشة ، حيث يكون العنوان مفتوحًا https://api.ipify.org.


نافذة المتصفح ، لم يتم استخدام اتصال Tor.

فتحته في نافذة المتصفح على وجه التحديدhttps://api.ipify.orgلأن هذه الصفحة يمكن أن تعرض عنوان IP العام الذي يتم الوصول إليه منه. هذا هو العنوان المرئي للمواقع التي أزورها إذا قمت بزيارتها دون استخدام Tor.

قم بتغيير التعليمات البرمجية أعلاه بإضافة المفتاح التالي إلى الكائن مع المعلمات التي تم تمريرهاpuppeteer.launch:

  /**
   *  Chromium.   `headless`  false,
   *     .
   */
  const browser = await puppeteer.launch({
  headless: false,
  
  //   .
  args: ['--proxy-server=socks5://127.0.0.1:9050']
});

مررنا حجة للمتصفح --proxy-server. تخبر قيمة هذه الوسيطة المستعرض أنه يجب أن يستخدم خادم وكيل socks5 يعمل على جهاز الكمبيوتر الخاص بنا ويمكن الوصول إليه على المنفذ 9050. رقم المنفذ هو أحد تلك الأرقام التي أدخلناها مسبقًا في الملف torrc.

قم بتشغيل البرنامج النصي مرة أخرى:

node index.js

هذه المرة ، في الصفحة المفتوحة ، يمكنك رؤية عنوان IP مختلف. هذا هو العنوان المستخدم لعرض الموقع من خلال شبكة Tor.


نافذة المتصفح ، يتم استخدام اتصال Tor.

في حالتي ، ظهر عنوان في هذه النافذة144.217.7.33. قد يكون لديك عنوان آخر. يرجى ملاحظة أنه إذا قمت بتشغيل البرنامج النصي مرة أخرى واستخدمت نفس رقم المنفذ (9050) ، فستتلقى نفس عنوان IP الذي تلقيته من قبل.


إعادة تشغيل نافذة المتصفح ، يتم استخدام اتصال Tor ،

ولهذا السبب في إعدادات Tor قمنا بفتح العديد من المنافذ. حاول توصيل متصفحك بمنفذ مختلف. سيؤدي ذلك إلى تغيير عنوان IP.

جمع البيانات مع Cheerio


الآن بعد أن أصبح لدينا آلية ملائمة لتحميل الصفحات ، فقد حان الوقت للقيام بتخريد الويب. لهذا ، سنستخدم مكتبة cheerio . هذا محلل HTML الذي تم إنشاء API الخاص به بنفس طريقة jQuery API . هدفنا هو الحصول على 5 من أحدث المنشورات من صفحة أخبار Hacker.

انتقل إلى موقع Hacker News .


موقع Hacker News

نريد أن نأخذ 5 عناوين جديدة من الصفحة المفتوحة (الآن أصبح HAKMEM (1972) ، ومات Larry Roberts ، وآخرون). عند فحص عنوان المقالة باستخدام أدوات مطور المتصفح ، لاحظت أن كل عنوان يتم وضعه في عنصر HTML<a>مع فصل دراسيstorylink.


دراسة هيكل الوثيقة

لاستخراج ما نحتاجه من كود HTML للصفحة ، نحتاج إلى تنفيذ التسلسل التالي من الإجراءات:

  • بدء نسخة متصفح جديدة بدون واجهة مستخدم متصلة بوكيل Tor.
  • قم بإنشاء صفحة جديدة.
  • انتقل إلى العنوان https://news.ycombinator.com/.
  • استرجاع محتوى HTML للصفحة.
  • تحميل محتوى HTML للصفحة cheerio.
  • إنشاء مصفوفة لحفظ عناوين المقالات.
  • الوصول إلى العناصر مع الفصل storylink.
  • الحصول على أول 5 عناصر باستخدام طريقة cheerio slice () .
  • اجتياز العناصر الناتجة باستخدام طريقة cheerio كل () .
  • اكتب كل رأس موجود في مصفوفة.

إليك الشفرة التي تنفذ هذه الإجراءات:

const puppeteer = require('puppeteer');

/**
 *   cheerio.
 */
const cheerio = require('cheerio');

async function main() {
  const browser = await puppeteer.launch({
    /**
     *       (   ).
     */
    headless: true,
    args: ['--proxy-server=socks5://127.0.0.1:9050']
  });

  const page = await browser.newPage();

  await page.goto('https://news.ycombinator.com/');

  /**
   *      HTML-.
   */
  const content = await page.content();

  /**
   *    cheerio.
   */
  const $ = cheerio.load(content);


  /**
   *      .
   */
  const titles = [];

  /**
   *   ,   `storylink`.
   *  slice()      5   .
   *      each().
   */
  $('.storylink').slice(0, 5).each((idx, elem) => {
    /**
     *   HTML-,   .
     */
    const title = $(elem).text();
  
    /**
     *    .
     */
    titles.push(title);
  })

  browser.close();
  
  /**
   *     .
   */
  console.log(titles);
}

main();

إليك ما يحدث بعد تشغيل هذا البرنامج النصي.


تم استخراج أول 5 عناوين إخبارية من الهاكر بنجاح من شفرة الصفحة

الكشط المستمر باستخدام عناوين IP مختلفة


الآن دعونا نتحدث عن كيفية استخدام منافذ SOCKS المختلفة التي حددناها في الملف torrc. إنه بسيط للغاية. سنعلن عن مصفوفة ، يحتوي كل منها على رقم منفذ. ثم أعد تسمية الوظيفة main()إلى وظيفة scrape()وأعلن عن وظيفة جديدة main()تستدعي الوظيفة scrape()، وتمريرها برقم منفذ جديد مع كل مكالمة.

هنا هو الرمز النهائي:

const puppeteer = require('puppeteer');
const cheerio = require('cheerio');

async function scrape(port) {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=socks5://127.0.0.1:' + port]
  });

  const page = await browser.newPage();
  await page.goto('https://news.ycombinator.com/');
  const content = await page.content();

  const $ = cheerio.load(content);

  const titles = [];

  $('.storylink').slice(0, 5).each((idx, elem) => {
    const title = $(elem).text();
    titles.push(title);
  });

  browser.close();
  return titles;
}

async function main() {
  /**
   *  SOCKS- Tor,    torrc. 
   */
  const ports = [
    '9050',
    '9052',
    '9053',
    '9054'
  ];
  
  /**
   *  -...
   */
  while (true) {
    for (const port of ports) {
      /**
       * ...  -    .
       */
      console.log(await scrape(port));
    }
  }
}

main();

ملخص


الآن لديك أدوات تحت تصرفك تسمح لك بالقيام بعمل مسح مجهول للويب.

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

Source: https://habr.com/ru/post/undefined/


All Articles