برنامه نویسی

The Puppeteer Language Experiment – انجمن DEV

اگر از Puppeteer برای اتوماسیون، تست یا خراش وب استفاده می کنید، احتمالاً با این سوال مواجه شده اید که چگونه زبان مرورگر را تنظیم کنید. کنترل صریح زبان بسیار مهم است زیرا ممکن است زبان سیستم محلی شما با زبان سیستم راه دور دیگری که می‌خواهید Puppeteer را اجرا کنید، مانند CI (مثلاً GitHub Actions) یا یک محیط بدون سرور (مانند AWS Lambda یا CloudFlare Workers) متفاوت باشد. .

در کمال تعجب، نحوه انجام این کار به خوبی مستند نشده است. به نظر می رسد یک سری گزینه وجود دارد، و شما باید بفهمید که چه چیزی برای شما بهتر است. پس از صرف زمان قابل توجهی برای تحقیق، فهرستی از گزینه ها را تهیه کرده ام. من هر گزینه را در مقابل BrowserLeaks تأیید کرده‌ام، که تمام اطلاعات موجود در مرورگر شما و ویژگی‌های پشتیبانی‌شده آن، از جمله زبان محلی و زبان پذیرفته‌شده را به شما نشان می‌دهد، که در نهایت محتوایی را که قرار است ببینید تعیین می‌کند.

چه زبانی؟

دو راه برای تعیین زبان درخواست کننده وجود دارد: سمت مشتری و سمت سرور. در سمت کلاینت، با جاوا اسکریپت، شما این را دارید navigator.language و navigator.languages خواص، و Intl.DateTimeFormat().resolvedOptions() روش. مقادیر لزوماً با یکدیگر مطابقت ندارند زیرا navigator.language به نظر می رسد از زبان تنظیمات کروم استفاده می کند، در حالی که Intl.DateTimeFormat().resolvedOptions() منعکس کننده زبان سیستم عامل است. در سمت سرور، شما باید Accept-Language هدری که با هر درخواست HTTP از مرورگر ارسال می شود. مرورگر از navigator.languages ویژگی برای پر کردن مقادیر هدر.

نکته جانبی: من از این اصطلاح استفاده می کنم زبان برای مراجعه به قسمت اول de از یک محل پسندیدن de-DE.

لازم به ذکر است که سرور می تواند تصمیم بگیرد که محتوای یک وب سایت را به زبان منعکس کننده HTTP بازگرداند Accept-Language مقادیر هدر، یا می تواند از جاوا اسکریپت برای شناسایی زبان و هدایت کاربر به یک URL محلی استفاده کند (به این فکر کنید example.com/de-DE/، یا می تواند به صورت پویا محتوای واقعی را از طریق جاوا اسکریپت بر اساس ویژگی ها از سرور بارگیری کند.

عروسک گردان را راه اندازی کنید

من از puppeteer بسته، که به طور خودکار نسخه اخیر Chrome را برای آزمایش دانلود می کند (فکر می کنم قبلاً Chromium بوده است). نیز وجود دارد puppeteer-core اگر می خواهید نصب مرورگر را خودتان مدیریت کنید یا اگر محیط از قبل یک مرورگر ارائه می دهد.

برای راه اندازی مرورگر، تنها کاری که باید انجام دهیم این است که با آن تماس بگیرید launch بدون نیاز به هیچ آرگومان دیگری عمل کنید. Puppeteer همه پیش فرض ها را فراهم می کند.

import puppeteer from "puppeteer";

const LANG = 'de-DE';

const browser = await puppeteer.launch();
const page = await browser.newPage();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من ثابت را تعریف کردم LANG به عنوان زبان مقصد برای مرورگر. در چند مرحله بعدی، نحوه اعمال این تنظیمات را به شما نشان خواهم داد.

آرگومان خط فرمان --lang

کروم (و کرومیوم) تعداد زیادی آرگومان خط فرمان را ارائه می دهد. بحث و جدل --lang می توان از آن برای تنظیم زبان هنگام راه اندازی استفاده کرد. به خاطر داشته باشید که باید با آرگ های پیش فرض Puppeteer ادغام شود.

console.log(`Using --lang=${LANG}`);

const args = [...puppeteer.defaultArgs(), `--lang=${LANG}`];
const browser = await puppeteer.launch({
  args,
});

const page = await browser.newPage();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

متغیر محیطی LANG

در حالی که متغیر محیطی به طور رسمی مستند نشده است، ارجاعاتی به آن در ردیاب اشکال Chromium و مخزن Puppeteer وجود دارد. با این حال، به نظر می رسد که این فقط در لینوکس کار می کند. حتی بدتر از آن، تنظیم این متغیر محیطی باعث می شود که مرورگر در سیستم عامل های خاصی راه اندازی نشود.

console.log(`Using env.LANG=${LANG}`);

const browser = await puppeteer.launch({
  env: {
    LANG,
  }
});

const page = await browser.newPage();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هدر HTTP Accept-Language

هدرهای HTTP اضافی مانند Accept-Language را می توان در هر درخواست صفحه تنظیم کرد. این روی زبان مرورگر تأثیری نمی‌گذارد، اما وب‌سایت درخواستی در صورت رعایت این سرصفحه ممکن است محتوا را به زبان درخواستی بازگرداند.

console.log(`Sending HTTP header Accept-Language: ${LANG}`);

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page.setExtraHTTPHeaders({
  'Accept-Language': LANG,
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

لغو navigator.language

نادیده گرفتن navigator.language ویژگی موجود در یک صفحه ممکن است مانند یک هک به نظر برسد، اما در واقع یک نمونه رسمی در اسناد Puppeteer است.

console.log(`Overriding navigator.language=${LANG}`);

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page.evaluateOnNewDocument((lang) => {
  Object.defineProperty(navigator, 'language', {
    get() {
      return lang;
    },
  });
  Object.defineProperty(navigator, 'languages', {
    get() {
      return [lang];
    },
  });
}, LANG);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پروتکل Chrome DevTools Network.setUserAgentOverride

Puppeteer از پروتکل Chrome DevTools Protocol (CDP) برای برقراری ارتباط با Chrome استفاده می کند. را Network.setUserAgentOverride روش اجازه تنظیم را می دهد acceptLanguage به عنوان زبان مرورگر برای تقلید. توجه داشته باشید که userAgent یک پارامتر ضروری است، اما مقدار پیش فرض را حفظ می کنیم.

console.log(`Using CDP Network.setUserAgentOverride(acceptLanguage: ${LANG})`);

const browser = await puppeteer.launch();

const page = await browser.newPage();

const cdpSession = await page.createCDPSession();
cdpSession.send('Network.setUserAgentOverride', {
  userAgent: await browser.userAgent(),
  acceptLanguage: LANG,
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتایج

همه گزینه ها را به صورت متوالی اجرا کردم و مقادیر آن را استخراج کردم navigator.language، navigator.languages، Intl.DateTimeFormat().resolvedOptions() از BrowserLeaks JS و Accept-Language هدر از IP BrowserLeaks. در اینجا نتایج برای هر گزینه آمده است:

System:  darwin/23.1.0, arm64
Browser: Chrome/125.0.6422.60

Using --lang=de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Using env.LANG=de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Sending HTTP header Accept-Language: de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: de-DE

Overriding navigator.language=de-DE
        Internationalization Locale: en-GB
        Navigator Language: de-DE
        HTTP Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Using CDP Network.setUserAgentOverride(acceptLanguage: de-DE)
        Internationalization Locale: en-GB
        Navigator Language: de-DE
        HTTP Accept-Language: de-DE
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که می بینید، نتایج به طور قابل توجهی متفاوت است. هیچ یک از گزینه‌ها روی منطقه بازگشتی از آن تأثیری نداشت Intl.DateTimeFormat().resolvedOptions(). با کمال تعجب، حتی --lang این گزینه بر زبان مرورگر تأثیری نمی‌گذارد navigator.language. این غیرمنتظره است، زیرا معتقدم در نسخه‌های قدیمی‌تر Chrome/Chromium یا در سیستم‌عامل‌های مختلف، این پرچم رعایت می‌شود. با استفاده از Network.setUserAgentOverride به نظر می رسد دستور از CDP مطمئن ترین راه برای کنترل زبان مرورگر باشد، علیرغم اینکه حداقل گزینه مستند است.

مشارکت

من این پروژه را به عنوان یک مجموعه آزمایشی تکرارپذیر اجرا کردم که می توان آن را به صورت محلی با حداقل تنظیمات اجرا کرد. اگر علاقه مند هستید، لطفاً مخزن را بررسی کنید و آزمایش ها را روی دستگاه محلی خود اجرا کنید. من کنجکاو هستم که ببینم آیا نتایج در سیستم عامل های مختلف یا نسخه های مرورگر متفاوت است یا خیر.

این پروژه نحوه تغییر زبان مرورگر را با Puppeteer آزمایش می کند. چندین گزینه را برای تنظیم زبان کروم پیاده‌سازی می‌کند و هر گزینه را در مقابل BrowserLeaks بررسی می‌کند تا ببیند چگونه بر ویژگی‌های جاوا اسکریپت و هدرهای HTTP موجود توسط مرورگر تأثیر می‌گذارد. برای اطلاعات بیشتر، به مقاله من The Puppeteer Language Experiment در DEV.to مراجعه کنید.

استفاده

این مخزن را در دستگاه محلی خود کلون کنید و وابستگی ها را با npm نصب کنید. را puppeteer بسته به طور خودکار Chrome را در یک پوشه موقت دانلود می کند.

npm install
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس تست را شروع کنید:

npm test
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تست هر گزینه را اجرا می کند و نتیجه آن را چاپ می کند:

System:   darwin/23.1.0, arm64
Language: en-US
Browser:  Chrome/125.0.6422.60
Using --lang=de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Using env.LANG=de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Sending HTTP header Accept-Language: de-DE
        Internationalization Locale: en-GB
        Navigator Language: en-GB
        HTTP Accept-Language: de-DE

Overriding navigator.language=de-DE
        Internationalization Locale: en-GB
        Navigator

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا