دليل got-scraping في Node.js: كشط الويب بالبروكسي السكني على نطاق الإنتاج

دليل تقني شامل لمكتبة got-scraping من Apify في Node.js — كيف تولّد رؤوس متصفح متماسكة، وتربط بروكسيات سكنية عبر ProxyHat، وتبني طبقات إعادة محاولة وتزامن محدود لإنتاج موثوق.

got-scraping in Node.js: A Developer's Guide with Residential Proxies
En este artículo

ملاحظة قانونية: هذا الدليل يغطي كشط البيانات العامة المتاحة على الويب فقط. تأكد من الالتزام بـ قانون الاحتيال وإساءة استخدام الحاسوب (CFAA) ولوائح GDPR، واحترم ملف robots.txt وشروط الخدمة لأي موقع، وفضّل الواجهات البرمجية الرسمية عند توفرها.

إذا كنت تطور كاشط ويب في Node.js، فمن المرجّح أنك جربت got أو axios وواجهت حظر IP أو تحديات CAPTCHA بعد بضع مئات من الطلبات. المشكلة ليست في سرعة مكتبتك — بل في بصمة المتصفح. got-scraping في Node.js هي مكتبة من Apify مبنية على got وتعالج هذه المشكلة من الجذور: توليد رؤوس HTTP متماسكة، دعم HTTP/2، وتكامل بروكسي مباشر. في هذا الدليل سننظر كيف تدمجها مع بروكسيات سكنية من ProxyHat لإنتاج كشط موثوق على نطاق واسع.

لماذا تُحظر الطلبات الخام؟ فهم بصمة المتصفح

أنظمة مكافحة البوت الحديثة لا تعتمد فقط على عنوان IP. تتحقق من ترتيب رؤوس HTTP، قيم sec-ch-ua، accept-language، بصمة TLS (JA3/JA4)، وبروتوكول الاتصال. طلب got أو axios العادي يكشف نفسه فوراً لأن:

  • ترتيب الرؤوس لا يتطابق مع أي متصفح حقيقي.
  • قيم مثل user-agent قد تكون صحيحة لكنها غير مصحوبة برؤوس sec-ch-ua المقابلة.
  • accept-language يفتقر إلى الترتيب المتوقع (مثل en-US,en;q=0.9).
  • الاتصال عبر HTTP/1.1 بينما المتصفح الحقيقي يستخدم HTTP/2 مع ALPN negotiation.

هذه الفجوات تجعل حتى الطلبات البطيئة قابلة للكشف. مستودع got-scraping على GitHub يوضح كيف تعالج المكتبة هذه المشكلة عبر header-generator الذي يصدر مجموعات رؤوس متماسكة من بيانات حقيقية لآلاف المتصفحات والأجهزة وأنظمة التشغيل.

مكتبة got-scraping في Node.js: السطح البرمجي المتماسك

got-scraping تمدّد got بدلاً من إعادة اختراعه. هذا يعني أن كل ميزات got متاحة: hooks، retry، timeout، pagination، وغيرها. الإضافة الأساسية هي:

  • got.extend() — لإنشاء نسخة مخصصة بخيارات افتراضية.
  • useHeaderGenerator: true — تفعيل توليد الرؤوس تلقائياً.
  • headerGeneratorOptions — تحديد المتصفح والجهاز ونظام التشغيل المستهدف.
  • proxyUrl — تمرير بروكسي HTTP/1.1 أو HTTP/2 أو SOCKS5.

هذا التصميم متماسك مع فلسفة got في استخدام hooks وextensions بدلاً من patching مخصصة. الـ header-generator نفسه يعمل كـ hook داخلي يضيف الرؤوس قبل إرسال الطلب، مما يعني أنك تستطيع تجاوز أي رأس يدوياً عند الحاجة.

خيارات headerGeneratorOptions

يمكنك تضييق نطاق الرؤوس المولّدة لتبدو كأنها من متصفح وجهاز محددين:

import { gotScraping } from 'got-scraping';

const client = gotScraping.extend({
  useHeaderGenerator: true,
  headerGeneratorOptions: {
    browsers: ['chrome'],
    devices: ['desktop'],
    operatingSystems: ['linux', 'windows'],
    locales: ['en-US', 'en'],
  },
  http2: true,
});

const res = await client('https://httpbin.org/headers');
console.log(JSON.parse(res.body).headers);

هذا ينتج رؤوساً مثل sec-ch-ua و sec-fetch-site و accept-language بترتيب مطابق لمتصفح Chrome حقيقي على Linux. الفرق بين هذا وطلب axios عادي هو فرق بين طلب يمرّ صامتاً وطلب يُكتشف في الثانية الأولى.

التوجيه عبر بروكسيات سكنية: لماذا IP هو الحلقة الأخيرة

حتى مع رؤوس متصفح مثالية وبصمة TLS نظيفة، يبقى عنوان IP هو العامل الحاسم. خوادم Cloud وdatacenter معروفة بنطاقاتها (AWS، GCP، Azure)، وأنظمة مكافحة البوت تضعها في قوائم مشبوهة افتراضياً. البروكسي السكني يحلّ هذا لأنه يستخدم عناوين IP مخصصة لمزودي إنترنت منزليين حقيقيين.

مع ProxyHat، تمرر البروكسي عبر خيار proxyUrl في got-scraping:

import { gotScraping } from 'got-scraping';

const res = await gotScraping({
  url: 'https://httpbin.org/ip',
  useHeaderGenerator: true,
  http2: true,
  proxyUrl: 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080',
});

console.log(JSON.parse(res.body).origin);
// { origin: "192.x.x.x" } — IP سكني أمريكي

لاحظ كيف نمرر معلمات الاستهداف الجغرافي والجلسة في اسم المستخدم. هذا نمط متماسك مع got-scraping لأن proxyUrl يقبل أي صيغة بروكسي يدعمها got، بما في ذلك HTTP/2 proxies و SOCKS5.

متى تستخدم SOCKS5 بدلاً من HTTP؟

البروكسي SOCKS5 يعمل على مستوى TCP ويستخدم المنفذ 1080 مع ProxyHat. يكون مفيداً عندما تحتاج إلى نفق شفاف لا يفسّر رؤوس HTTP، أو عند التعامل مع مواقع تستخدم WebSocket أو اتصالات طويلة الأمد:

const res = await gotScraping({
  url: 'https://httpbin.org/ip',
  useHeaderGenerator: true,
  proxyUrl: 'socks5://user-country-DE-session-xyz789:pass@gate.proxyhat.com:1080',
});

مثال عملي: تدوير بروكسيات سكنية مع إعادة محاولة

في الإنتاج، تحتاج إلى تدوير الجلسات لكل طلب (أو لكل مجموعة طلبات)، مع إعادة محاولة ذكية عند الفشل. إليك نمط كامل يستخدم hooks في got-scraping لتوليد معرفات جلسة فريدة لكل طلب:

import { gotScraping } from 'got-scraping';
import crypto from 'crypto';

const PROXYHAT_GATE = 'gate.proxyhat.com';
const PROXYHAT_PORT = 8080;
const PROXYHAT_USER = 'user';
const PROXYHAT_PASS = 'pass';

function buildProxyUrl(country = 'US') {
  const session = crypto.randomUUID().split('-')[0];
  return `http://${PROXYHAT_USER}-country-${country}-session-${session}:${PROXYHAT_PASS}@${PROXYHAT_GATE}:${PROXYHAT_PORT}`;
}

const scraper = gotScraping.extend({
  useHeaderGenerator: true,
  headerGeneratorOptions: {
    browsers: ['chrome'],
    devices: ['desktop'],
    operatingSystems: ['windows', 'macos'],
  },
  http2: true,
  timeout: { request: 30000 },
  retry: {
    limit: 3,
    statusCodes: [403, 429, 500, 502, 503],
    calculateDelay: ({ computedValue }) => computedValue + 1000,
  },
  hooks: {
    beforeRequest: [
      (options) => {
        // تدوير البروكسي لكل طلب
        options.proxyUrl = buildProxyUrl('US');
      },
    ],
    afterResponse: [
      (response, retryWithMergedOptions) => {
        if (response.statusCode === 403) {
          // IP محظور — جرّب جلسة جديدة
          return retryWithMergedOptions({
            proxyUrl: buildProxyUrl('US'),
          });
        }
        return response;
      },
    ],
  },
});

// استخدام
const urls = [
  'https://httpbin.org/ip',
  'https://httpbin.org/headers',
  'https://httpbin.org/user-agent',
];

for (const url of urls) {
  const res = await scraper(url);
  console.log(url, '→', res.statusCode);
}

هذا النمط متماسك مع بنية got: beforeRequest hook يضخ البروكسي قبل الإرسال، و afterResponse hook يعالج الحظر بإعادة محاولة بجلسة جديدة. لا حاجة لـ patching أو workaround.

أنماط الإنتاج: التزامن المحدود وملفات تعريف الارتباط

تقييد التزامن مع p-limit

إطلاق آلاف الطلبات المتزامنة سيؤدي إلى استنزاف الموارد وحظر IP حتى مع البروكسي. استخدم p-limit لتحديد عدد الطلبات المتزامنة:

import pLimit from 'p-limit';

const limit = pLimit(50); // 50 طلب متزامن كحد أقصى

const results = await Promise.all(
  urls.map((url) => limit(() => scraper(url)))
);

قيمة 50 متزامن توازن بين السرعة ومعدل النجاح. مع بروكسيات سكنية، يمكنك رفعها إلى 100 متزامن إذا كانت المواقع المستهدفة تتحمل ذلك، لكن راقب معدل 429 و 403.

بعض المواقع تتطلب جلسة ملفات تعريف ارتباط متسقة. got-scraping يدعم tough-cookie عبر خيار cookieJar:

import { CookieJar } from 'tough-cookie';

const jar = new CookieJar();

const sessionClient = scraper.extend({
  cookieJar: jar,
  hooks: {
    beforeRequest: [
      (options) => {
        // نفس الجلسة لكل الطلبات في هذه الدفعة
        options.proxyUrl = buildProxyUrl('US');
      },
    ],
  },
});

// الطلب الأول يضبط الكوكيز
await sessionClient('https://example.com/login');
// الطلبات اللاحقة تحملها تلقائياً
await sessionClient('https://example.com/dashboard');

الترقية إلى Crawlee و CheerioCrawler

عندما يزداد التعقيد — pagination، قوائم انتظار طلبات، تصدير بيانات منظم — فإن الانتقال إلى Crawlee من Apify هو الخطوة الطبيعية. Crawlee يستخدم got-scraping داخلياً، و CheerioCrawler يتيح كشط HTML بسرعة مع دعم مدمج للبروكسي وإعادة المحاولة:

import { CheerioCrawler } from 'crawlee';

const crawler = new CheerioCrawler({
  useHeaderGenerator: true,
  proxyConfiguration: {
    proxyUrls: [
      'http://user-country-US-session-s1:pass@gate.proxyhat.com:8080',
      'http://user-country-US-session-s2:pass@gate.proxyhat.com:8080',
      'http://user-country-US-session-s3:pass@gate.proxyhat.com:8080',
    ],
  },
  maxConcurrency: 50,
  requestHandler: async ({ $, request }) => {
    const title = $('title').text();
    console.log(request.url, '→', title);
  },
});

await crawler.run(['https://example.com/page1', 'https://example.com/page2']);

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

مقارنة: got-scraping مقابل got العادي مقابل axios مع بروكسي

الميزة got-scraping got العادي axios + proxy
توليد رؤوس متصفح متماسكة ✓ مدمج ✗ يدوي ✗ يدوي
دعم HTTP/2 ✓ افتراضي ✓ لكن بدون ALPN matching ✗ محدود
proxyUrl كخيار أولي ✓ عبر httpsAgent
إعادة محاولة مدمجة ✓ مع hooks ✗ يتطلب axios-retry
بصمة TLS مطابقة للمتصفح ✓ أفضل تطابق ~ جزئي ✗ ضعيف
ملفات تعريف ارتباط ✓ tough-cookie ✓ يدوي

متى يكون المتصفح الـ headless لا مفر منه؟

got-scraping يعالج 80-90% من حالات كشط الويب. لكن بعض المواقع تتطلب تنفيذ JavaScript فعلياً — تطبيقات SPA، مواقع تستخدم Cloudflare Turnstile، أو مواقع تتحقق من بصمة Canvas وWebGL. في هذه الحالات، الانتقال إلى PlaywrightCrawler في Crawlee هو الخيار الصحيح. يمكنك أيضاً الاطلاع على تتبع نتائج محركات البحث لفهم متى تكون هذه الحدود حرجة.

القاعدة العملية: ابدأ بـ got-scraping + بروكسي سكني. إذا واجهت CAPTCHA أو صفحات فارغة بعد 5-10 طلبات تجريبية، انتقل إلى متصفح headless مع نفس البنية البرمجية للبروكسي.

أخطاء شائعة وحالات حدية

  • استخدام نفس الجلسة طويلاً: الجلسة اللاصقة (sticky session) مفيدة للتماسك، لكنها تُحمّل IP واحد بكل الطلبات. حدّد عمر الجلسة إلى 50-100 طلب ثم جدّدها.
  • تجاهل accept-language: إذا كان البروكسي في دولة معينة لكن accept-language يقول en-US فقط، فقد يثير شكوكاً. استخدم locales في headerGeneratorOptions لتتناسب مع جغرافيا البروكسي.
  • عدم التعامل مع 429: أضف 429 إلى retry.statusCodes وزد تأخيراً أُسّياً. بعض المواقع تفرض حدوداً مثل طلب واحد كل 2 ثانية لكل IP.
  • نسيان timeout: بروكسيات سكنية قد تكون أبطأ من datacenter بـ 200-500ms. اضبط timeout.request إلى 30 ثانية على الأقل.

النقاط الرئيسية

الخلاصة: got-scraping يحل مشكلة بصمة المتصفح على مستوى الرؤوس وHTTP/2، بينما يحل البروكسي السكني من ProxyHat مشكلة عنوان IP. الجمع بينهما مع hooks إعادة محاولة وتزامن محدود ينتج كشطاً موثوقاً على نطاق الإنتاج.

  • استخدم useHeaderGenerator: true و headerGeneratorOptions دائماً — الرؤوس المتماسكة هي الخط الدفاعي الأول.
  • مرر البروكسي السكني عبر proxyUrl مع gate.proxyhat.com:8080 (HTTP) أو :1080 (SOCKS5).
  • دوّر الجلسات عبر beforeRequest hook، وعالج 403 عبر afterResponse hook.
  • قيّد التزامن إلى 50-100 طلب متزامن مع p-limit.
  • عند التعقيد المتزايد، انتقل إلى Crawlee و CheerioCrawler مع نفس البروكسي.
  • احترم robots.txt وشروط الخدمة، وفضّل الواجهات البرمجية الرسمية. راجع أسعار ProxyHat و مواقع البروكسي المتاحة للتخطيط.

للتفاصيل التقنية الكاملة حول معلمات البروكسي والاستهداف الجغرافي، راجع توثيق ProxyHat.

Preguntas frecuentes

ما هو got-scraping في Node.js؟

got-scraping هي مكتبة من Apify مبنية على got وتضيف توليد رؤوس متصفح متماسكة (user-agent، sec-ch-ua، accept-language بترتيب صحيح) ودعم HTTP/2 وخيار proxyUrl مدمج. الهدف هو جعل طلبات Node.js تبدو كأنها من متصفح حقيقي، مما يقلل من كشفها بواسطة أنظمة مكافحة البوت.

لماذا يهم got-scraping في Node.js مستخدمي البروكسي؟

لأن البروكسي وحده لا يكفي. حتى مع IP سكني نظيف، إذا كانت رؤوس HTTP وبصمة TLS لا تتطابق مع متصفح حقيقي، فسيتم كشف الطلب وحظره. got-scraping يعالج طبقة الرؤوس بينما يعالج البروكسي السكني طبقة IP، والجمع بينهما ضروري لكشط موثوق.

أي نوع بروكسي يعمل بشكل أفضل مع got-scraping في Node.js؟

البروكسي السكني (residential) هو الأفضل لأنه يستخدم عناوين IP من مزودي إنترنت منزليين حقيقيين، مما يجعل الطلبات تبدو كأنها من مستخدمين عاديين. مع ProxyHat، يمكنك تمرير البروكسي عبر proxyUrl باستخدام gate.proxyhat.com:8080 للـ HTTP أو :1080 للـ SOCKS5، مع استهداف جغرافي وجلسات لاصقة في اسم المستخدم.

كيف تتجنب الحظر عند تنفيذ got-scraping في Node.js؟

استخدم useHeaderGenerator مع headerGeneratorOptions لتناسب المتصفح والجغرافيا، دوّر الجلسات عبر beforeRequest hook لكل طلب، عالج 403 و 429 عبر afterResponse hook مع إعادة محاولة بجلسة جديدة، قيّد التزامن إلى 50-100 طلب متزامن مع p-limit، واحترم حدود المعدل و robots.txt. البروكسي السكني مع تدوير الجلسات يقلل الحظر بشكل كبير.

¿Listo para empezar?

Proxies residenciales, ISP y móviles en más de 148 países. Creá una cuenta gratis.

Crear cuenta gratis
← Volver al Blog