إذا كنت تقوم بتشغيل سكريبتات التفسير أو الحسابات المتعددة على Playwright وتقوم بفتح مثيل متصفح منفصل لكل بروكسي - فأنت تضيع الذاكرة وCPU بلا فائدة. يمكن لـ Playwright تعيين البروكسي على مستوى BrowserContext، وليس على المتصفح بالكامل، وهذا يغير بنية السكريبتات بشكل جذري: عملية متصفح واحدة، وعشرات من السياقات المعزولة مع IPs مختلفة، وملفات تعريف الارتباط، وبصمة الإصبع. في هذه المقالة - كيف يعمل ذلك، كود بلغة بايثون وNode.js، ولماذا يكون هذا مهمًا بشكل خاص عند العمل مع بروكسيات سكنية ومحمولة.
المشكلة: البروكسي على browser.launch() - مكلف وغير مريح
النهج الكلاسيكي للعديد من السكريبتات على Playwright يبدو كالتالي: يتم استدعاء chromium.launch({ proxy: {...} }) لكل بروكسي، ويتم إنشاء عملية متصفح منفصلة، تعمل ثم تغلق، ثم يتم تشغيل التالي مع بروكسي جديد. إذا كنت بحاجة إلى معالجة 50 عنوان IP في وقت واحد لتفسير Wildberries أو Ozon، فهذا يعني 50 عملية Chromium كاملة في نفس الوقت - كل منها تستهلك من 150 إلى 300 ميغابايت من الذاكرة فقط عند البدء، دون احتساب علامات التبويب والرندر.
في الممارسة العملية، تصل هذه المشكلة إلى الحد الأقصى بالفعل عند 15-20 متصفحًا متوازيًا على VPS عادي بسعة 8 غيغابايت من الذاكرة. يبدأ الخادم في التبديل، وتسقط السكريبتات مع انتهاء الوقت، ولا تتمكن بعض البروكسيات من العمل في الوقت المحدد. المشكلة ليست في البروكسيات ولا في Playwright - المشكلة في البنية المعمارية: كل تشغيل للمتصفح يسحب معه محرك الرندر بالكامل، ومعالجة GPU، والشبكة، وعشرات من الخيوط المساعدة، على الرغم من أنك تحتاج فقط إلى IP جديد وجلسة نظيفة.
تحل Playwright هذه المشكلة بشكل أنيق: يمكن تعيين البروكسي ليس عند تشغيل المتصفح، ولكن عند إنشاء BrowserContext - "صندوق الرمل" المعزول الخفيف داخل نفس عملية المتصفح. يمكن لعملية Chromium واحدة الاحتفاظ بعشرات السياقات، كل منها مع بروكسي خاص به، وملفات تعريف الارتباط الخاصة به، وlocalStorage، دون أن تتداخل مع بعضها البعض.
المتصفح مقابل BrowserContext: ما الفرق
Browser - هو عملية المحرك نفسها (Chromium، Firefox أو WebKit)، والتي يتم تشغيلها مرة واحدة وتعيش لفترة طويلة. BrowserContext - هو بيئة معزولة داخل هذه العملية، مشابهة لنافذة خاصة (incognito)، مع ملفات تعريف الارتباط الخاصة بها، وذاكرة التخزين المؤقت، والأذونات، وما هو مهم بالنسبة لنا، إعدادات الشبكة الخاصة بها، بما في ذلك البروكسي.
إذا قارننا مع متصفحات مكافحة الكشف مثل Dolphin Anty أو AdsPower - كل "ملف تعريف" هناك هو أيضًا في الأساس حاوية معزولة منفصلة مع ملفات تعريف الارتباط وبصمة الإصبع. يسمح Playwright ببناء منطق مشابه برمجيًا: متصفح واحد - العديد من السياقات، كل منها كـ "ملف تعريف" منفصل مع IP خاص به.
| المعلمة | بروكسي على المتصفح | بروكسي على BrowserContext |
|---|---|---|
| الذاكرة لكل IP | 150-300 ميغابايت (عملية جديدة) | 15-40 ميغابايت (سياق جديد) |
| سرعة تغيير IP | 2-5 ثوانٍ (إعادة تشغيل المتصفح) | 0.1-0.3 ثوانٍ (سياق جديد) |
| عزل ملفات تعريف الارتباط | كامل (عمليات مختلفة) | كامل (السياقات لا تتشارك ملفات تعريف الارتباط) |
| الحد الأقصى للجلسات المتوازية على 8 غيغابايت RAM | ~20-25 | ~150-200 |
بروكسي على السياق: كود بلغة بايثون
أدناه هو نمط أساسي: يتم تشغيل متصفح واحد مرة واحدة، ثم يتم إنشاء سياق منفصل لكل بروكسي. هذه واجهة برمجة التطبيقات المتزامنة لـ Playwright، لكن المنطق هو نفسه للإصدار غير المتزامن.
from playwright.sync_api import sync_playwright
proxies = [
{"server": "http://proxy1.example.com:8000", "username": "user1", "password": "pass1"},
{"server": "http://proxy2.example.com:8000", "username": "user2", "password": "pass2"},
{"server": "http://proxy3.example.com:8000", "username": "user3", "password": "pass3"},
]
with sync_playwright() as p:
# يتم تشغيل المتصفح مرة واحدة، بدون بروكسي
browser = p.chromium.launch(headless=True)
for proxy in proxies:
# يتم تعيين البروكسي للسياق، وليس للمتصفح
context = browser.new_context(
proxy={
"server": proxy["server"],
"username": proxy["username"],
"password": proxy["password"],
},
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
)
page = context.new_page()
page.goto("https://httpbin.org/ip", timeout=30000)
print(page.content())
page.close()
context.close() # نغلق فقط السياق، بينما يستمر المتصفح في العمل
browser.close()
النقطة الرئيسية - browser.launch() يتم استدعاؤه مرة واحدة خارج الحلقة، بينما browser.new_context() - داخل حلقة البروكسي. بالنسبة للبروكسي مع المصادقة باستخدام اسم المستخدم وكلمة المرور، يقوم Playwright تلقائيًا بإضافة رؤوس Basic Auth على مستوى الشبكة، ولا تحتاج إلى إعداد أي شيء إضافي.
بروكسي على السياق: كود بلغة Node.js
نفس المنطق بلغة JavaScript باستخدام async/await - غالبًا ما يتم استخدامه مع أطر عمل التفسير على Node.js:
const { chromium } = require('playwright');
const proxies = [
{ server: 'http://proxy1.example.com:8000', username: 'user1', password: 'pass1' },
{ server: 'http://proxy2.example.com:8000', username: 'user2', password: 'pass2' },
];
(async () => {
const browser = await chromium.launch({ headless: true });
for (const proxy of proxies) {
const context = await browser.newContext({
proxy: {
server: proxy.server,
username: proxy.username,
password: proxy.password,
},
});
const page = await context.newPage();
await page.goto('https://httpbin.org/ip', { timeout: 30000 });
console.log(await page.content());
await page.close();
await context.close();
}
await browser.close();
})();
لمعالجة عشرات البروكسيات بشكل متوازي، يمكن إنشاء السياقات عبر Promise.all، دون انتظار إغلاق السابق - وهذا هو الميزة الرئيسية لنهج "متصفح واحد، العديد من السياقات" مقارنة بتشغيل عمليات منفصلة.
دوران البروكسي النظيف بدون إعادة تشغيل المتصفح
"الدوران النظيف" يعني أنه عند تغيير IP لا تبقى آثار من الجلسة السابقة - لا ملفات تعريف الارتباط، ولا ذاكرة التخزين المؤقت، ولا عمال الخدمة. عند إعادة تشغيل المتصفح بالكامل، يتم ضمان ذلك تلقائيًا، لكنه مكلف من حيث الموارد. عند العمل مع السياقات، يتم تحقيق نفس الشيء من خلال إغلاق السياق القديم وإنشاء سياق جديد - العملية تستغرق أجزاء من الثانية.
async function rotateProxy(browser, proxyList, index) {
const proxy = proxyList[index % proxyList.length];
const context = await browser.newContext({ proxy });
const page = await context.newPage();
return { context, page };
}
// نستخدمها هكذا: في كل N-iteration نغير IP
for (let i = 0; i < 100; i++) {
if (i % 10 === 0) {
const { context, page } = await rotateProxy(browser, proxies, i);
// نعمل مع جلسة جديدة لـ 10 طلبات
}
}
هذا النمط مفيد بشكل خاص عند تفسير الأسواق: على سبيل المثال، عند جمع الأسعار من Wildberries أو Ozon، حيث تتعقب حماية البوتات عدد الطلبات من IP واحد خلال فترة زمنية. يسمح الدوران على مستوى السياق بتغيير IP كل 5-10 طلبات، دون فقدان الأداء بسبب إعادة تشغيل المتصفح.
لمثل هذه السيناريوهات، تعتبر البروكسيات السكنية خيارًا جيدًا - حيث تقدم IP لمستخدمين حقيقيين، مما يجعل الأسواق أقل احتمالًا لوضع علامة عليها كمشبوهة، مقارنة بالنطاقات الواضحة الخاصة بالخوادم.
مقارنة من حيث الذاكرة والسرعة
تم إجراء اختبار على VPS تجريبي بسعة 8 غيغابايت من الذاكرة و4 vCPU على طريقتين للتعامل مع 100 صفحة باستخدام IPs مختلفة. في الحالة الأولى، تم تشغيل chromium.launch() لكل IP بشكل منفصل، وفي الحالة الثانية - متصفح واحد مع إنشاء 100 سياق بشكل متتابع.
| المقياس | 100 تشغيل لـ browser.launch() | 100 سياق في 1 متصفح |
|---|---|---|
| الذاكرة القصوى | ~6.8 غيغابايت | ~1.9 غيغابايت |
| إجمالي وقت التنفيذ | 182 ثانية | 97 ثانية |
| عدد الجلسات التي سقطت بسبب انتهاء الوقت | 7 | 0 |
كانت وفورات الذاكرة في هذا الاختبار حوالي 70%، بينما انخفض إجمالي وقت التنفيذ تقريبًا إلى النصف بسبب عدم وجود نفقات عامة على بدء وإنهاء عملية Chromium في كل مرة. مع كميات كبيرة - آلاف IPs يوميًا - تصبح الفجوة أكثر وضوحًا، وهذا يؤثر مباشرة على عدد البروكسيات التي يمكنك استخدامها على خادم واحد دون ترقية الأجهزة.
حالات عملية: التفسير والحسابات المتعددة
تفسير الأسواق. عند جمع الأسعار من Wildberries، Ozon أو Avito، يحتفظ نفس المتصفح بعشرات السياقات مفتوحة، كل منها مع IP فريد وملف تعريف الارتباط الخاص به. يقلل هذا من خطر الحظر بسبب نمط الطلبات ويسمح بجمع البيانات بشكل أسرع، دون انتظار إعادة تشغيل العملية بين IPs.
الحسابات المتعددة وزراعة الحسابات. لاختبار الحملات الإعلانية على Facebook Ads أو TikTok Ads من خلال سكريبتات Playwright، من المنطقي الاحتفاظ بكل حساب في سياق منفصل مع بروكسي وuser-agent خاص به - هذا يحاكي سلوك متصفحات مكافحة الكشف مثل Multilogin أو GoLogin، ولكن بدون ترخيص لمكافحة الكشف نفسها، بالكامل برمجيًا.
اختبار الإعلانات الجغرافية. يحتاج المسوقون الذين يريدون التحقق من كيفية عرض الإبداع في دول مختلفة، إلى السياقات مع بروكسيات مختلفة للسماح لهم "بزيارة" المناطق المطلوبة في جلسة متصفح واحدة، دون فتح عشرات النوافذ المنفصلة يدويًا.
للسيناريوهات التي يكون فيها من المهم محاكاة حركة المرور المحمولة - على سبيل المثال، التحقق من النسخة المحمولة من الموقع أو الإعلانات في TikTok Ads - يجب النظر في البروكسيات المحمولة، التي تقدم IP من مشغلين حقيقيين للهواتف المحمولة وتثير الشك أقل لدى أنظمة مكافحة الاحتيال.
إذا كانت المهمة هي تفسير سريع ومستقر دون الحاجة إلى مستوى عالٍ من الخصوصية (على سبيل المثال، جمع البيانات العامة من المواقع دون حماية صارمة ضد البوتات)، فإن بروكسيات مراكز البيانات تقدم أفضل توازن بين السرعة والتكلفة في كميات كبيرة من الطلبات.
الأخطاء الشائعة وكيفية تجنبها
1. يتم تعيين البروكسي في launch()، وليس في new_context(). هذه هي الخطأ الأكثر شيوعًا بين المبتدئين - البروكسي المحدد عند تشغيل المتصفح يتم تطبيقه على جميع السياقات مرة واحدة ولا يمكن إعادة تعيينه بشكل فردي. دائمًا قم بتمرير البروكسي في new_context() إذا كنت بحاجة إلى المرونة في IP.
2. لا يتم إغلاق السياقات القديمة. إذا كنت تقوم بإنشاء مئات السياقات ولا تستدعي context.close()، ستزداد ذاكرة المتصفح بشكل خطي حتى تسقط العملية بسبب OOM. دائمًا أغلق السياق بعد الانتهاء من المهمة لهذا IP.
3. نفس user-agent لجميع السياقات. إذا تغير البروكسي، بينما تظل بصمة المتصفح كما هي (user-agent، اللغة، المنطقة الزمنية)، يمكن أن ترتبط أنظمة مكافحة البوتات في الأسواق ووسائل التواصل الاجتماعي بين الجلسات. قم بتغيير user-agent وviewport مع البروكسي لكل سياق.
4. تجاهل أوقات انتهاء البروكسي. البروكسيات السكنية والمحمولة أحيانًا تستجيب ببطء أكثر من بروكسيات مراكز البيانات بسبب البنية التحتية الشبكية الحقيقية. قم بتعيين وقت انتهاء معقول (20-40 ثانية) عند استدعاء page.goto()، وإلا سيعتبر السكريبت البروكسي العامل "ميتًا".
5. الكثير من السياقات في متصفح واحد في نفس الوقت. على الرغم من توفير الذاكرة، فإن إنشاء 500+ سياق نشط في نفس الوقت سيصل إلى حدود العملية. التوازن المعقول هو 30-80 سياق نشط في نفس الوقت لكل عملية متصفح، اعتمادًا على سعة RAM للخادم.
الخاتمة
تعيين البروكسي على مستوى BrowserContext، وليس على المتصفح بالكامل - هو حل معماري يوفر حتى 70% من الذاكرة، ويزيد من سرعة دوران IP عشرات المرات، ويعطي عزلًا نظيفًا لملفات تعريف الارتباط بين الجلسات دون الحاجة إلى إعادة تشغيل Chromium باستمرار. لتفسير الأسواق، واختبار الإعلانات في مناطق مختلفة، والحسابات المتعددة، هذه هي الطريقة المباشرة لزيادة عدد الجلسات المتوازية على نفس الخادم دون ترقية الأجهزة.
إذا كنت تبني سكريبتًا على Playwright لجمع البيانات من Wildberries، Ozon أو للعمل مع حسابات إعلانات Facebook Ads وTikTok Ads، فإن جودة مجموعة البروكسي نفسها ليست أقل أهمية من بنية الكود. للمهام التي تكون فيها موثوقية IP والمقاومة لأنظمة مكافحة البوتات أمرًا حاسمًا، يجب أن تبدأ بـ البروكسيات السكنية - فهي تتناسب جيدًا مع النهج "متصفح واحد، العديد من السياقات" الموضح أعلاه.