โหมดไม่มีส่วนหัวของ Chrome มีการอัปเกรด: ขอแนะนำ --headless=new

โหมดไม่มีส่วนหัวของ Chrome ดีขึ้นกว่าเดิมมาก

Peter Kvitek
Peter Kvitek

โหมดไม่มีส่วนหัวของ Chrome ดีขึ้นกว่าเดิมมาก บทความนี้นำเสนอภาพรวมของความพยายามด้านวิศวกรรมล่าสุดเพื่อทำให้ Headless มีประโยชน์มากขึ้นสำหรับนักพัฒนาแอป โดยการนำ Headless เข้าใกล้โหมด "headful" ปกติของ Chrome มากขึ้น

ที่มา

ย้อนกลับไปในปี 2017 Chrome 59 ได้เปิดตัวโหมดที่ไม่มีส่วนหัว ซึ่งจะช่วยให้คุณเรียกใช้เบราว์เซอร์ในสภาพแวดล้อมที่ไม่ต้องดำเนินการใดๆ โดยไม่มี UI ที่มองเห็นได้ พูดง่ายๆ ก็คือเรียกใช้ Chrome โดยไม่ใช้ Chrome!

โหมด Headless เป็นตัวเลือกยอดนิยมสำหรับการทำงานอัตโนมัติของเบราว์เซอร์ผ่านโปรเจ็กต์ต่างๆ เช่น Puppeteer หรือ ChromeDriver ต่อไปนี้เป็นตัวอย่างบรรทัดคำสั่งสั้นๆ ของการใช้โหมดไม่มีส่วนหัวเพื่อสร้างไฟล์ PDF ของ URL ที่ระบุ

chrome --headless --print-to-pdf https://developer.chrome.com/

มีอะไรใหม่ใน Headless

ก่อนที่เราจะเจาะลึกเกี่ยวกับการปรับปรุง Headless ล่าสุด คุณต้องเข้าใจว่า Headless ระดับ "แบบเก่า" ทำงานอย่างไร ข้อมูลโค้ดบรรทัดคำสั่งที่เราแสดงก่อนหน้านี้ใช้แฟล็กบรรทัดคำสั่ง --headless ซึ่งบ่งบอกว่า Headless เป็นเพียงโหมดการทำงานของเบราว์เซอร์ Chrome ทั่วไป บางทีก็น่าประหลาดใจที่ นี่ไม่เป็นความจริงเลย โดยในทางเทคนิคแล้ว Headless เดิมเป็นการใช้งานเบราว์เซอร์สำรองแยกต่างหากที่เกิดขึ้นโดยมีการจัดส่งเป็นส่วนหนึ่งของไบนารี Chrome เดียวกัน และจะไม่แชร์โค้ดของเบราว์เซอร์ Chrome ใน //chrome

คุณคงพอจะจินตนาการได้ว่า การใช้และดูแลรักษาเบราว์เซอร์ Headless ที่แยกต่างหากนี้มีค่าใช้จ่ายทางวิศวกรรมจำนวนมาก แต่นั่นไม่ใช่ปัญหาเดียว เนื่องจาก Headless เป็นระบบการทำงานที่แยกต่างหาก จึงมีข้อบกพร่องและฟีเจอร์ของตัวเองซึ่งไม่มีอยู่ใน Chrome ที่ซ้ำซ้อน ซึ่งก่อให้เกิดสถานการณ์ที่สับสน โดยการทดสอบเบราว์เซอร์อัตโนมัติอาจผ่านในโหมด Headless แต่ล้มเหลวในโหมด Headless หรือกลับกัน ถือเป็นปัญหาหลักสำหรับวิศวกรระบบอัตโนมัติ นอกจากนี้ยังไม่รวมการทดสอบอัตโนมัติที่อาศัยการติดตั้งส่วนขยายของเบราว์เซอร์ เป็นต้น การทำงานระดับเบราว์เซอร์ก็เช่นเดียวกัน กล่าวคือ ไม่รองรับฟังก์ชันดังกล่าว เว้นแต่ Headless จะมีการใช้งานแยกต่างหาก

ในปี 2021 ทีม Chrome ได้เริ่มแก้ปัญหานี้และรวมโหมดไม่มีส่วนหัวและโหมด Headless เข้าด้วยกันในทุกกรณี

Chrome Headless ใหม่ไม่ใช่เบราว์เซอร์ที่แยกต่างหากอีกต่อไป และจะแชร์โค้ดกับ Chrome แทน

เรายินดีที่จะประกาศว่าโหมดไม่มีส่วนหัวใหม่พร้อมให้บริการใน Chrome 112 แล้ว ในโหมดนี้ Chrome จะสร้างแต่ไม่แสดงหน้าต่างแพลตฟอร์ม ส่วนฟังก์ชันอื่นๆ ทั้งหมดที่มีอยู่และในอนาคตจะใช้งานได้โดยไม่มีข้อจำกัด

ลองใช้ Headless ใหม่

หากต้องการลองใช้โหมดไม่มีส่วนหัวใหม่ ให้ส่งแฟล็กบรรทัดคำสั่ง --headless=new ดังนี้

chrome --headless=new

สำหรับตอนนี้ โหมดไม่มีส่วนหัวแบบเก่ายังคงใช้งานได้ผ่านช่องทางต่อไปนี้

chrome --headless=old

ปัจจุบันการส่งแฟล็กบรรทัดคำสั่ง --headless โดยไม่มีค่าที่ชัดเจนจะยังเปิดใช้งานโหมดไม่มีส่วนหัวแบบเก่า แต่เราวางแผนที่จะเปลี่ยนค่าเริ่มต้นนี้เป็นแบบไม่มีส่วนหัวใหม่ในอนาคต

เราวางแผนที่จะนำ Headless เวอร์ชันเก่าออกจากไบนารี Chrome โดยสมบูรณ์ และหยุดรองรับโหมดนี้ใน Puppeteer ภายในปีนี้ ในการนําออกครั้งนี้ เราจะทําให้ Headless เดิมพร้อมใช้งานเป็นไบนารีแบบสแตนด์อโลนแยกต่างหากสําหรับผู้ใช้ที่ยังอัปเกรดไม่ได้

เกม Headless แบบใหม่ใน Puppeteer

วิธีเลือกใช้โหมดไม่มีส่วนหัวใน Puppeteer

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: 'new',
  // `headless: true` (default) enables old Headless;
  // `headless: 'new'` enables new Headless;
  // `headless: false` enables "headful" mode.
});

const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');

// …

await browser.close();

ใหม่ Headless ใน Selenium-WebDriver

วิธีใช้โหมด Headless ใหม่ใน Selenium-WebDriver

const driver = await env
  .builder()
  .setChromeOptions(options.addArguments('--headless=new'))
  .build();

await driver.get('https://developer.chrome.com/');

// …

await driver.quit();

ดูข้อมูลเพิ่มเติมได้ในบล็อกโพสต์ของทีม Selenium และตัวอย่างที่ใช้การเชื่อมโยงภาษาอื่น

แฟล็กบรรทัดคำสั่งที่เฉพาะเจาะจงแบบไม่มีส่วนหัว

แฟล็กบรรทัดคำสั่งต่อไปนี้พร้อมใช้งานสำหรับโหมดไม่มีส่วนหัวใหม่

--dump-dom

แฟล็ก --dump-dom จะพิมพ์ DOM ที่ทำให้เป็นอนุกรมของหน้าเป้าหมายไปยัง Stdout ตัวอย่าง

chrome --headless=new --dump-dom https://developer.chrome.com/

โปรดทราบว่าวิธีนี้แตกต่างจากการพิมพ์ซอร์สโค้ด HTML (ซึ่งคุณอาจทำกับ curl) เพื่อนำเอาต์พุตของ --dump-dom มาให้คุณ Chrome จะแยกวิเคราะห์โค้ด HTML เป็น DOM ก่อน แล้วเรียกใช้ <script> ใดๆ ที่อาจดัดแปลง DOM จากนั้นเปลี่ยน DOM นั้นกลับมาเป็นสตริง HTML ที่ต่อเนื่องกัน

--screenshot

แฟล็ก --screenshot จะถ่ายภาพหน้าจอของหน้าเว็บเป้าหมายและบันทึกเป็น screenshot.png ในไดเรกทอรีที่ใช้งานอยู่ปัจจุบัน ซึ่งจะมีประโยชน์อย่างยิ่งเมื่อใช้ร่วมกับการแจ้ง --window-size ตัวอย่าง

chrome --headless=new --screenshot --window-size=412,892 https://developer.chrome.com/

--print-to-pdf

ธง --print-to-pdf บันทึกหน้าเป้าหมายเป็น PDF ชื่อ output.pdf ในไดเรกทอรีการทำงานปัจจุบัน ตัวอย่าง

chrome --headless=new --print-to-pdf https://developer.chrome.com/

นอกจากนี้ คุณยังเพิ่มแฟล็ก --no-pdf-header-footer เพื่อละเว้นส่วนหัวที่พิมพ์ (ที่มีวันที่และเวลาปัจจุบัน) และส่วนท้าย (ที่มี URL และหมายเลขหน้า) ได้อีกด้วย

chrome --headless=new --print-to-pdf --no-pdf-header-footer https://developer.chrome.com/

--timeout

แฟล็ก --timeout จะกำหนดเวลารอสูงสุด (เป็นมิลลิวินาที) หลังจากที่ --dump-dom, --screenshot และ --print-to-pdf บันทึกเนื้อหาของหน้าเว็บแล้ว แม้ว่าหน้าเว็บจะยังคงโหลดอยู่ก็ตาม

chrome --headless=new --print-to-pdf --timeout=5000 https://developer.chrome.com/

ธง --timeout=5000 จะบอกให้ Chrome รอถึง 5 วินาทีก่อนพิมพ์ PDF ดังนั้น กระบวนการนี้จะใช้เวลาไม่เกิน 5 วินาทีในการเรียกใช้

--virtual-time-budget

--virtual-time-budget เปิดใช้การเดินทางข้ามเวลา ก็ไม่เชิงนะ เวลาเสมือนจะทำหน้าที่เป็น "กรอไปข้างหน้า" สำหรับโค้ดที่ขึ้นอยู่กับเวลา (ตัวอย่างเช่น setTimeout/setInterval) จะบังคับให้เบราว์เซอร์เรียกใช้โค้ดใดๆ ของหน้าเว็บโดยเร็วที่สุดเท่าที่จะเป็นไปได้ ขณะที่หน้าเว็บเชื่อว่าเวลาได้ผ่านไปแล้วจริงๆ

เพื่อเห็นภาพการใช้งาน ให้ลองพิจารณาหน้าสาธิตนี้ซึ่งจะเพิ่ม บันทึก และแสดงตัวนับทุกวินาทีโดยใช้ setTimeout(fn, 1000) นี่คือโค้ดที่เกี่ยวข้อง

<output>0</output>
<script>
  const element = document.querySelector('output');
  let counter = 0;
  setInterval(() => {
    counter++;
    console.log(counter);
    element.textContent = counter;
  }, 1_000);
</script>

หลังจากผ่านไป 1 วินาที หน้าเว็บจะมี "1" หลังจาก 2 วินาที มี "2" ต่อไปเรื่อยๆ ต่อไปนี้คือวิธีที่คุณสามารถบันทึกสถานะของหน้าเว็บหลังจากผ่านไป 42 วินาที แล้วบันทึกเป็น PDF

chrome --headless=new --print-to-pdf --virtual-time-budget=42000 https://mathiasbynens.be/demo/time

--allow-chrome-scheme-url

ต้องใช้แฟล็ก --allow-chrome-scheme-url เพื่อเข้าถึง URL chrome:// รายการ แฟล็กนี้พร้อมให้ใช้งานตั้งแต่ Chrome 123 เป็นต้นไป ตัวอย่าง

chrome --headless=new --print-to-pdf --allow-chrome-scheme-url chrome://gpu

การแก้ไขข้อบกพร่อง

เนื่องจาก Chrome ซ่อนตัวได้อย่างมีประสิทธิภาพในโหมดไม่มีส่วนหัว การค้นหาสิ่งที่เกิดขึ้นในกรณีที่เกิดปัญหาจึงอาจเป็นเรื่องยาก โชคดีที่คุณสามารถแก้ไขข้อบกพร่องของ Chrome แบบไม่มีส่วนหัวในลักษณะที่คล้ายกับ Chrome แบบ Headless มาก เคล็ดลับคือการเปิด Chrome ในโหมดไม่มีส่วนหัวด้วยแฟล็กบรรทัดคำสั่ง --remote-debugging-port

chrome --headless=new --remote-debugging-port=0 https://developer.chrome.com/

การดำเนินการนี้จะพิมพ์ URL ของ WebSocket ที่ไม่ซ้ำกันไปยัง stdout เช่น

DevTools listening on ws://127.0.0.1:60926/devtools/browser/b4bd6eaa-b7c8-4319-8212-225097472fd9

ในอินสแตนซ์ Chrome ที่มีการดำเนินการล่วงหน้าตามปกติ เราสามารถใช้การแก้ไขข้อบกพร่องระยะไกลของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เพื่อเชื่อมต่อกับเป้าหมายแบบไม่มีส่วนหัวและตรวจสอบได้ โดยไปที่ chrome://inspect คลิกปุ่ม Configure... แล้วป้อนที่อยู่ IP และหมายเลขพอร์ตจาก WebSocket URL ในตัวอย่างด้านบน ฉันป้อน 127.0.0.1:60926 คลิกเสร็จสิ้น แล้วคุณจะเห็นเป้าหมายระยะไกลปรากฏขึ้นพร้อมกับแท็บทั้งหมดและเป้าหมายอื่นๆ ที่แสดงด้านล่าง คลิกinspect แล้วคุณก็มีสิทธิ์เข้าถึงเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เพื่อตรวจสอบเป้าหมายแบบไม่มีส่วนหัวระยะไกล inspect

เครื่องมือสำหรับนักพัฒนาเว็บใน Chrome สามารถตรวจสอบหน้าเป้าหมายแบบไม่มีส่วนหัวระยะไกลได้

ความคิดเห็น

เราหวังว่าจะได้รับความคิดเห็นของคุณเกี่ยวกับโหมดไม่มีส่วนหัวใหม่ หากพบปัญหา โปรดรายงานปัญหาดังกล่าว