"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > تحسين تجريف الويب: تجريف بيانات المصادقة باستخدام JSDOM

تحسين تجريف الويب: تجريف بيانات المصادقة باستخدام JSDOM

تم النشر بتاريخ 2024-11-08
تصفح:523

كمطورين متخصصين، نحتاج أحيانًا إلى استخراج بيانات المصادقة مثل المفاتيح المؤقتة لأداء مهامنا. ومع ذلك، فالأمر ليس بهذه البساطة. عادةً ما يكون ذلك في طلبات شبكة HTML أو XHR، ولكن في بعض الأحيان، يتم حساب بيانات المصادقة. في هذه الحالة، يمكننا إما إجراء هندسة عكسية للعملية الحسابية، الأمر الذي يستغرق الكثير من الوقت لإزالة تشويش البرامج النصية أو تشغيل JavaScript الذي يحسبها. عادةً، نستخدم المتصفح، ولكنه مكلف. يوفر Crawlee الدعم لتشغيل مكشطة المتصفح وCheerio Scraper بالتوازي، ولكن هذا أمر معقد للغاية ومكلف من حيث استخدام موارد الحساب. يساعدنا JSDOM في تشغيل JavaScript للصفحة بموارد أقل من المتصفح وأعلى قليلاً من Cheerio.

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

تحليل الموقع

عند زيارة عنوان URL هذا:

https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pc/en

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

Optimizing web scraping: Scraping auth data using JSDOM

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

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

لا يعد Cheerio هو الخيار الأفضل هنا نظرًا لأن Creative Center هو تطبيق ويب، ومصدر البيانات هو واجهة برمجة التطبيقات (API)، لذلك يمكننا فقط الحصول على علامات التصنيف الموجودة في البداية في بنية HTML ولكن ليس كل علامة من الـ 100 كما نطلب.

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

الآن يأتي النهج الجديد الذي قمنا بتطويره لجعل هذه العملية أفضل بكثير من المعتمدة على المتصفح وقريبة جدًا من الزحف المعتمد على CheerioCrawler.

نهج JSDOM

قبل التعمق في هذا النهج، أود أن أشيد بـ Alexey Udovydchenko، مهندس أتمتة الويب في Apify، لتطوير هذا النهج. مجد له!

في هذا النهج، سنقوم بإجراء استدعاءات واجهة برمجة التطبيقات إلى https://ads.tiktok.com/creative_radar_api/v1/popular_trend/hashtag/list للحصول على البيانات المطلوبة.

قبل إجراء استدعاءات لواجهة برمجة التطبيقات هذه، سنحتاج إلى عدد قليل من الرؤوس المطلوبة (بيانات المصادقة)، لذا سنقوم أولاً بإجراء الاتصال على https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pad /ar.

سنبدأ هذا النهج من خلال إنشاء وظيفة من شأنها إنشاء عنوان URL لاستدعاء واجهة برمجة التطبيقات (API) لنا وإجراء الاتصال والحصول على البيانات.

export const createStartUrls = (input) => {
    const {
        days = '7',
        country = '',
        resultsLimit = 100,
        industry = '',
        isNewToTop100,
    } = input;

    const filterBy = isNewToTop100 ? 'new_on_board' : '';
    return [
        {
            url: `https://ads.tiktok.com/creative_radar_api/v1/popular_trend/hashtag/list?page=1&limit=50&period=${days}&country_code=${country}&filter_by=${filterBy}&sort_by=popular&industry_id=${industry}`,
            headers: {
                // required headers
            },
            userData: { resultsLimit },
        },
    ];
};

في الوظيفة أعلاه، نقوم بإنشاء عنوان URL للبدء لاستدعاء واجهة برمجة التطبيقات (API) الذي يتضمن معلمات مختلفة كما تحدثنا سابقًا. بعد إنشاء عنوان URL وفقًا للمعلمات، سيتم استدعاء Creative_radar_api وجلب جميع النتائج.

لكن الأمر لن ينجح حتى نحصل على الرؤوس. لذا، فلنقم بإنشاء دالة تقوم أولاً بإنشاء جلسة باستخدام sessionPool وproxyConfiguration.

export const createSessionFunction = async (
    sessionPool,
    proxyConfiguration,
) => {
    const proxyUrl = await proxyConfiguration.newUrl(Math.random().toString());
    const url =
        'https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pad/en';
    // need url with data to generate token
    const response = await gotScraping({ url, proxyUrl });
    const headers = await getApiUrlWithVerificationToken(
        response.body.toString(),
        url,
    );
    if (!headers) {
        throw new Error(`Token generation blocked`);
    }
    log.info(`Generated API verification headers`, Object.values(headers));
    return new Session({
        userData: {
            headers,
        },
        sessionPool,
    });
};

في هذه الوظيفة، الهدف الرئيسي هو الاتصال بـ https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pad/en والحصول على رؤوس في المقابل. للحصول على الرؤوس نستخدم وظيفة getApiUrlWithVerificationToken.

قبل المضي قدمًا، أود أن أذكر أن Crawlee يدعم أصلاً JSDOM باستخدام JSDOM Crawler. إنه يوفر إطارًا للزحف المتوازي لصفحات الويب باستخدام طلبات HTTP البسيطة وتنفيذ jsdom DOM. ويستخدم طلبات HTTP الأولية لتنزيل صفحات الويب، وهو سريع جدًا وفعال في عرض النطاق الترددي للبيانات.

دعونا نرى كيف سنقوم بإنشاء وظيفة getApiUrlWithVerificationToken:

const getApiUrlWithVerificationToken = async (body, url) => {
    log.info(`Getting API session`);
    const virtualConsole = new VirtualConsole();
    const { window } = new JSDOM(body, {
        url,
        contentType: 'text/html',
        runScripts: 'dangerously',
        resources: 'usable' || new CustomResourceLoader(),
        // ^ 'usable' faster than custom and works without canvas
        pretendToBeVisual: false,
        virtualConsole,
    });
    virtualConsole.on('error', () => {
        // ignore errors cause by fake XMLHttpRequest
    });

    const apiHeaderKeys = ['anonymous-user-id', 'timestamp', 'user-sign'];
    const apiValues = {};
    let retries = 10;
    // api calls made outside of fetch, hack below is to get URL without actual call
    window.XMLHttpRequest.prototype.setRequestHeader = (name, value) => {
        if (apiHeaderKeys.includes(name)) {
            apiValues[name] = value;
        }
        if (Object.values(apiValues).length === apiHeaderKeys.length) {
            retries = 0;
        }
    };
    window.XMLHttpRequest.prototype.open = (method, urlToOpen) => {
        if (
            ['static', 'scontent'].find((x) =>
                urlToOpen.startsWith(`https://${x}`),
            )
        )
        log.debug('urlToOpen', urlToOpen);
    };
    do {
        await sleep(4000);
        retries--;
    } while (retries > 0);

    await window.close();
    return apiValues;
};

في هذه الوظيفة، نقوم بإنشاء وحدة تحكم افتراضية تستخدم CustomResourceLoader لتشغيل عملية الخلفية واستبدال المتصفح بـ JSDOM.

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

باستخدام XMLHttpRequest.prototype.setRequestHeader، نقوم بالتحقق مما إذا كانت الرؤوس المذكورة موجودة في الاستجابة أم لا، إذا كانت الإجابة بنعم، فإننا نأخذ قيمة تلك الرؤوس، ونكرر المحاولات حتى نحصل على جميع الرؤوس.

الجزء الأكثر أهمية هو أننا نستخدم XMLHttpRequest.prototype.open لاستخراج بيانات المصادقة وإجراء المكالمات دون استخدام المتصفحات فعليًا أو الكشف عن نشاط الروبوت.

في نهاية createSessionFunction، تقوم بإرجاع جلسة بالرؤوس المطلوبة.

الآن نأتي إلى الكود الرئيسي الخاص بنا، سوف نستخدم CheerioCrawler وسنستخدم خطافات prenavigationHooks لإدخال الرؤوس التي حصلنا عليها من الوظيفة السابقة في requestHandler.

const crawler = new CheerioCrawler({
    sessionPoolOptions: {
        maxPoolSize: 1,
        createSessionFunction: async (sessionPool) =>
            createSessionFunction(sessionPool, proxyConfiguration),
    },
    preNavigationHooks: [
        (crawlingContext) => {
            const { request, session } = crawlingContext;
            request.headers = {
                ...request.headers,
                ...session.userData?.headers,
            };
        },
    ],
    proxyConfiguration,
});

أخيرًا، في معالج الطلب، نقوم بإجراء الاتصال باستخدام الرؤوس والتأكد من عدد المكالمات اللازمة لجلب جميع صفحات معالجة البيانات.

async requestHandler(context) {
    const { log, request, json } = context;
    const { userData } = request;
    const { itemsCounter = 0, resultsLimit = 0 } = userData;
    if (!json.data) {
        throw new Error('BLOCKED');
    }
    const { data } = json;
    const items = data.list;
    const counter = itemsCounter   items.length;
    const dataItems = items.slice(
        0,
        resultsLimit && counter > resultsLimit
            ? resultsLimit - itemsCounter
            : undefined,
    );
    await context.pushData(dataItems);
    const {
        pagination: { page, total },
    } = data;
    log.info(
        `Scraped ${dataItems.length} results out of ${total} from search page ${page}`,
    );
    const isResultsLimitNotReached =
        counter 



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

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

لتوضيح الأمور أكثر، إليك كيفية ظهور تدفق التعليمات البرمجية:

Optimizing web scraping: Scraping auth data using JSDOM

خاتمة

يساعدنا هذا الأسلوب في الحصول على طريقة ثالثة لاستخراج بيانات المصادقة دون استخدام المتصفح فعليًا وتمرير البيانات إلى CheerioCrawler. يؤدي هذا إلى تحسين الأداء بشكل كبير وتقليل متطلبات ذاكرة الوصول العشوائي بنسبة 50%، وبينما يكون أداء التجريد المستند إلى المتصفح أبطأ بعشر مرات من Cheerio النقي، فإن JSDOM يفعل ذلك أبطأ بمقدار 3-4 مرات فقط، مما يجعله أسرع 2-3 مرات من المتصفح- القشط القائم.

تم بالفعل تحميل قاعدة التعليمات البرمجية للمشروع هنا. تتم كتابة الكود كممثل Apify؛ يمكنك العثور على المزيد حول هذا الموضوع هنا، ولكن يمكنك أيضًا تشغيله دون استخدام Apify SDK.

إذا كانت لديك أي شكوك أو أسئلة حول هذا الأسلوب، تواصل معنا على خادم Discord الخاص بنا.

بيان الافراج تم إعادة نشر هذه المقالة على: https://dev.to/crawlee/optimizing-web-scraping-scraping-auth-data-using-jsdom-3cji?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] للحذف هو - هي
أحدث البرنامج التعليمي أكثر>

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

Copyright© 2022 湘ICP备2022001581号-3