การขูดเว็บด้วยเบราว์เซอร์หัวขาด: บทช่วยสอนหุ่นกระบอก

เผยแพร่แล้ว: 2022-03-11

ในบทความนี้ เราจะมาดูกันว่าการขูดเว็บ (เว็บอัตโนมัติ) นั้นง่ายเพียงใดด้วยการใช้ เบราว์เซอร์หัวขาด

เบราว์เซอร์หัวขาดคืออะไรและเหตุใดจึงจำเป็น

ในช่วงไม่กี่ปีที่ผ่านมาพบว่าเว็บมีวิวัฒนาการมาจากเว็บไซต์ที่เรียบง่ายซึ่งสร้างด้วย HTML และ CSS เปล่า ขณะนี้มีเว็บแอปแบบโต้ตอบที่มี UI ที่สวยงามมากขึ้น ซึ่งมักจะสร้างด้วยเฟรมเวิร์ก เช่น Angular หรือ React กล่าวอีกนัยหนึ่ง ทุกวันนี้ JavaScript ควบคุมเว็บ รวมถึงเกือบทุกอย่างที่คุณโต้ตอบด้วยบนเว็บไซต์

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

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

หัวขาด? ขอโทษ? ใช่ นี่หมายความว่าไม่มีอินเทอร์เฟซผู้ใช้แบบกราฟิก (GUI) แทนที่จะโต้ตอบกับองค์ประกอบภาพแบบที่คุณทำตามปกติ—เช่น ด้วยเมาส์หรืออุปกรณ์สัมผัส—คุณทำให้กรณีการใช้งานอัตโนมัติด้วยอินเทอร์เฟซบรรทัดคำสั่ง (CLI)

หัวขาด Chrome และ Puppeteer

มีเครื่องมือขูดเว็บมากมายที่สามารถใช้ในการเรียกดูแบบไม่มีหัว เช่น Zombie.js หรือ Firefox แบบไม่มีหัวโดยใช้ Selenium แต่วันนี้เราจะมาสำรวจ Chrome หัวขาดผ่าน Puppeteer เนื่องจากเป็นผู้เล่นที่ค่อนข้างใหม่กว่า ซึ่งเปิดตัวเมื่อต้นปี 2018 หมายเหตุบรรณาธิการ: ควรพูดถึง Intoli's Remote Browser ผู้เล่นใหม่อีกคน แต่นั่นจะต้องเป็นเรื่องสำหรับอีกคนหนึ่ง บทความ.

Puppeteer คืออะไรกันแน่? เป็นไลบรารี Node.js ที่มี API ระดับสูงเพื่อควบคุม Chrome หรือ Chromium ที่ไม่มีส่วนหัว หรือเพื่อโต้ตอบกับโปรโตคอล DevTools มีการดูแลโดยทีม Chrome DevTools และชุมชนโอเพนซอร์สที่ยอดเยี่ยม

พูดมากแล้ว— ไปที่โค้ดแล้วสำรวจโลกของวิธีการขูดเว็บแบบอัตโนมัติโดยใช้การท่องเว็บแบบไม่มีหัวของ Puppeteer!

การเตรียมสิ่งแวดล้อม

ก่อนอื่น คุณจะต้องติดตั้ง Node.js 8+ บนเครื่องของคุณเสียก่อน คุณสามารถติดตั้งได้ที่นี่ หรือหากคุณเป็นคนรัก CLI อย่างฉันและชอบทำงานบน Ubuntu ให้ทำตามคำสั่งเหล่านี้:

 curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs

คุณจะต้องมีแพ็คเกจบางอย่างที่อาจหรือไม่มีอยู่ในระบบของคุณ เพื่อความปลอดภัย ลองติดตั้งสิ่งต่อไปนี้:

 sudo apt-get install -yq --no-install-recommends libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 libnss3

ตั้งค่า Headless Chrome และ Puppeteer

ฉันขอแนะนำให้ติดตั้ง Puppeteer ด้วย npm เนื่องจากจะรวม Chromium เวอร์ชันล่าสุดที่เสถียรซึ่งรับประกันว่าจะทำงานกับไลบรารี่ได้

รันคำสั่งนี้ในไดเร็กทอรีรากของโปรเจ็กต์ของคุณ:

 npm i puppeteer --save

หมายเหตุ: อาจใช้เวลาสักครู่เนื่องจาก Puppeteer จะต้องดาวน์โหลดและติดตั้ง Chromium ในพื้นหลัง

เอาล่ะ เมื่อทุกอย่างพร้อมและกำหนดค่าแล้ว มาเริ่มความสนุกกันเลย!

การใช้ Puppeteer API สำหรับการขูดเว็บอัตโนมัติ

มาเริ่มบทแนะนำ Puppeteer ด้วยตัวอย่างพื้นฐานกัน เราจะเขียนสคริปต์ที่จะทำให้เบราว์เซอร์หัวขาดของเราจับภาพหน้าจอของเว็บไซต์ที่เราเลือก

สร้างไฟล์ใหม่ในไดเร็กทอรีโครงการของคุณที่ชื่อ screenshot.js และเปิดในโปรแกรมแก้ไขโค้ดที่คุณชื่นชอบ

ขั้นแรก ให้นำเข้าไลบรารี Puppeteer ในสคริปต์ของคุณ:

 const puppeteer = require('puppeteer');

ถัดไป ลองใช้ URL จากอาร์กิวเมนต์บรรทัดคำสั่ง:

 const url = process.argv[2]; if (!url) { throw "Please provide a URL as the first argument"; }

ตอนนี้ เราต้องจำไว้ว่า Puppeteer เป็นไลบรารีที่อิงตามสัญญา: มันทำการเรียกแบบอะซิงโครนัสไปยังอินสแตนซ์ Chrome ที่ไม่มีส่วนหัวภายใต้ประทุน รักษาโค้ดให้สะอาดโดยใช้ async/await สำหรับสิ่งนั้น เราจำเป็นต้องกำหนดฟังก์ชัน async ก่อน และใส่รหัส Puppeteer ทั้งหมดลงไป:

 async function run () { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url); await page.screenshot({path: 'screenshot.png'}); browser.close(); } run();

โดยรวมแล้วรหัสสุดท้ายมีลักษณะดังนี้:

 const puppeteer = require('puppeteer'); const url = process.argv[2]; if (!url) { throw "Please provide URL as a first argument"; } async function run () { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url); await page.screenshot({path: 'screenshot.png'}); browser.close(); } run();

คุณสามารถเรียกใช้ได้โดยดำเนินการคำสั่งต่อไปนี้ในไดเร็กทอรีรากของโครงการของคุณ:

 node screenshot.js https://github.com

รอสักครู่แล้วบูม! เบราว์เซอร์หัวขาดของเราเพิ่งสร้างไฟล์ชื่อ screenshot.png และคุณสามารถดูหน้าแรกของ GitHub ที่แสดงผลได้ เยี่ยมมาก เรามีเครื่องขูดเว็บ Chrome ที่ใช้งานได้!

หยุดสักครู่แล้วสำรวจสิ่งที่เกิดขึ้นในฟังก์ชัน run() ด้านบนของเรา

ขั้นแรก เราเปิดอินสแตนซ์เบราว์เซอร์หัวขาดใหม่ จากนั้นเปิดหน้าใหม่ (แท็บ) และไปที่ URL ที่ให้ไว้ในอาร์กิวเมนต์บรรทัดคำสั่ง สุดท้ายนี้ เราใช้วิธีการในตัวของ Puppeteer ในการจับภาพหน้าจอ และเราเพียงแค่ระบุเส้นทางที่จะบันทึกเท่านั้น นอกจากนี้เรายังต้องแน่ใจว่าได้ปิดเบราว์เซอร์หัวขาดหลังจากที่เราดำเนินการอัตโนมัติเสร็จแล้ว

ตอนนี้เราได้ครอบคลุมพื้นฐานแล้ว มาต่อกันที่บางสิ่งที่ซับซ้อนกว่านี้หน่อย

ตัวอย่างการขูดรีดหุ่นตัวที่สอง

สำหรับส่วนต่อไปของบทแนะนำ Puppeteer ของเรา สมมติว่าเราต้องการลบบทความใหม่ล่าสุดจาก Hacker News

สร้างไฟล์ใหม่ชื่อ ycombinator-scraper.js และวางในข้อมูลโค้ดต่อไปนี้:

 const puppeteer = require('puppeteer'); function run () { return new Promise(async (resolve, reject) => { try { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto("https://news.ycombinator.com/"); let urls = await page.evaluate(() => { let results = []; let items = document.querySelectorAll('a.storylink'); items.forEach((item) => { results.push({ url: item.getAttribute('href'), text: item.innerText, }); }); return results; }) browser.close(); return resolve(urls); } catch (e) { return reject(e); } }) } run().then(console.log).catch(console.error);

โอเค มีอะไรเกิดขึ้นมากกว่านี้เล็กน้อยเมื่อเทียบกับตัวอย่างก่อนหน้านี้

สิ่งแรกที่คุณอาจสังเกตเห็นคือตอนนี้ฟังก์ชัน run() ส่งกลับคำสัญญา ดังนั้นคำนำหน้า async จึงย้ายไปยังคำจำกัดความของฟังก์ชันคำสัญญา

เรายังรวมโค้ดทั้งหมดของเราไว้ในบล็อก try-catch เพื่อให้เราสามารถจัดการกับข้อผิดพลาดใดๆ ที่ทำให้คำสัญญาของเราถูกปฏิเสธ

และสุดท้าย เรากำลังใช้เมธอดในตัวของ Puppeteer ที่ชื่อว่า evaluate() วิธีนี้ช่วยให้เราเรียกใช้โค้ด JavaScript ที่กำหนดเองได้เหมือนกับว่าเราดำเนินการโค้ดดังกล่าวในคอนโซล DevTools ทุกอย่างที่ส่งคืนจากฟังก์ชันนั้นได้รับการแก้ไขโดยสัญญา วิธีนี้มีประโยชน์มากในการดึงข้อมูลหรือดำเนินการที่กำหนดเอง

รหัสที่ส่งไปยังเมธอดการ evaluate() เป็นจาวาสคริปต์พื้นฐานที่สร้างอาร์เรย์ของอ็อบเจ็กต์ โดยแต่ละโค้ดมี url และฟิลด์ text ที่แสดงถึง URL เรื่องราวที่เราเห็นใน https://news.ycombinator.com/

ผลลัพธ์ของสคริปต์มีลักษณะดังนี้ (แต่เดิมมี 30 รายการ):

 [ { url: 'https://www.nature.com/articles/d41586-018-05469-3', text: 'Bias detectives: the researchers striving to make algorithms fair' }, { url: 'https://mino-games.workable.com/jobs/415887', text: 'Mino Games Is Hiring Programmers in Montreal' }, { url: 'http://srobb.net/pf.html', text: 'A Beginner\'s Guide to Firewalling with pf' }, // ... { url: 'https://tools.ietf.org/html/rfc8439', text: 'ChaCha20 and Poly1305 for IETF Protocols' } ]

ค่อนข้างเรียบร้อยฉันจะพูด!

โอเค ไปกันต่อเลย เรามีการส่งคืนสินค้าเพียง 30 รายการ ในขณะที่ยังมีสินค้าอีกมากมาย—ซึ่งอยู่ในหน้าอื่นๆ เราต้องคลิกที่ปุ่ม "เพิ่มเติม" เพื่อโหลดหน้าถัดไปของผลลัพธ์

มาแก้ไขสคริปต์ของเราเล็กน้อยเพื่อเพิ่มการรองรับการแบ่งหน้า:

 const puppeteer = require('puppeteer'); function run (pagesToScrape) { return new Promise(async (resolve, reject) => { try { if (!pagesToScrape) { pagesToScrape = 1; } const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto("https://news.ycombinator.com/"); let currentPage = 1; let urls = []; while (currentPage <= pagesToScrape) { let newUrls = await page.evaluate(() => { let results = []; let items = document.querySelectorAll('a.storylink'); items.forEach((item) => { results.push({ url: item.getAttribute('href'), text: item.innerText, }); }); return results; }); urls = urls.concat(newUrls); if (currentPage < pagesToScrape) { await Promise.all([ await page.click('a.morelink'), await page.waitForSelector('a.storylink') ]) } currentPage++; } browser.close(); return resolve(urls); } catch (e) { return reject(e); } }) } run(5).then(console.log).catch(console.error);

มาทบทวนสิ่งที่เราทำกันที่นี่:

  1. เราได้เพิ่มอาร์กิวเมนต์เดียวที่เรียกว่า pagesToScrape ให้กับฟังก์ชัน main run() ของเรา เราจะใช้สิ่งนี้เพื่อจำกัดจำนวนหน้าที่สคริปต์ของเราจะขูด
  2. มีตัวแปรใหม่อีกหนึ่งตัวชื่อ currentPage ซึ่งแสดงถึงจำนวนหน้าของผลลัพธ์ที่เรากำลังดูอยู่ มันถูกตั้งค่าเป็น 1 ในตอนแรก เรายังรวมฟังก์ชันการ evaluate() ของเราไว้ใน while วนรอบเพื่อให้ทำงานต่อไปได้ตราบเท่าที่ currentPage น้อยกว่าหรือเท่ากับ pagesToScrape
  3. เราได้เพิ่มการบล็อกสำหรับการย้ายไปยังหน้าใหม่และรอให้หน้าโหลดก่อนที่จะเริ่มการวนรอบ while ใหม่

คุณจะสังเกตเห็นว่าเราใช้วิธี page.click() เพื่อให้เบราว์เซอร์หัวขาดคลิกที่ปุ่ม "เพิ่มเติม" เรายังใช้ waitForSelector() เพื่อให้แน่ใจว่าตรรกะของเราถูกหยุดชั่วคราวจนกว่าจะโหลดเนื้อหาของหน้า

ทั้งสองวิธีนี้เป็นวิธี Puppeteer API ระดับสูงที่พร้อมใช้งานทันที

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

ทั้งหมดนี้ค่อนข้างเจ๋ง แต่บทแนะนำ Puppeteer ของเรายังไม่ครอบคลุมถึงการเพิ่มประสิทธิภาพ มาดูกันว่าเราจะทำให้ Puppeteer วิ่งเร็วขึ้นได้อย่างไร

การเพิ่มประสิทธิภาพสคริปต์ Puppeteer ของเรา

แนวคิดทั่วไปคืออย่าให้เบราว์เซอร์หัวขาดทำงานพิเศษใดๆ ซึ่งอาจรวมถึงการโหลดรูปภาพ การใช้กฎ CSS การส่งคำขอ XHR เป็นต้น

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

อย่างไรก็ตาม การเพิ่มประสิทธิภาพเหล่านี้สามารถทำได้โดยการแคชเนื้อหาในคำขอแรก หรือยกเลิกคำขอ HTTP ทันทีที่เริ่มต้นโดยเว็บไซต์

เรามาดูกันว่าการแคชทำงานอย่างไรก่อน

คุณควรทราบว่าเมื่อคุณเปิดอินสแตนซ์เบราว์เซอร์ที่ไม่มีส่วนหัวใหม่ Puppeteer จะสร้างไดเร็กทอรีชั่วคราวสำหรับโปรไฟล์ จะถูกลบออกเมื่อปิดเบราว์เซอร์และไม่พร้อมใช้งานเมื่อคุณเปิดอินสแตนซ์ใหม่ ดังนั้นรูปภาพ, CSS, คุกกี้ และอ็อบเจ็กต์อื่นๆ ทั้งหมดที่จัดเก็บไว้จะไม่สามารถเข้าถึงได้อีกต่อไป

เราสามารถบังคับให้ Puppeteer ใช้เส้นทางที่กำหนดเองสำหรับการจัดเก็บข้อมูล เช่น คุกกี้และแคช ซึ่งจะถูกนำกลับมาใช้ใหม่ทุกครั้งที่เราเรียกใช้อีกครั้ง จนกว่าจะหมดอายุหรือถูกลบด้วยตนเอง

 const browser = await puppeteer.launch({ userDataDir: './data', });

สิ่งนี้น่าจะช่วยให้เรามีประสิทธิภาพเพิ่มขึ้น เนื่องจาก CSS และรูปภาพจำนวนมากจะถูกแคชในไดเร็กทอรีข้อมูลเมื่อมีการร้องขอครั้งแรก และ Chrome จะไม่จำเป็นต้องดาวน์โหลดซ้ำแล้วซ้ำอีก

อย่างไรก็ตาม เนื้อหาเหล่านั้นจะยังคงถูกใช้เมื่อแสดงผลหน้า ในความต้องการในการขูดบทความข่าว Y Combinator เราไม่จำเป็นต้องกังวลเกี่ยวกับภาพใด ๆ รวมถึงรูปภาพ เราสนใจเฉพาะเอาต์พุต HTML เปลือย ดังนั้นเรามาลองบล็อกทุกคำขอกัน

โชคดีที่ Puppeteer ใช้งานได้ดีมาก ในกรณีนี้ เพราะมันมาพร้อมกับการรองรับตะขอแบบกำหนดเอง เราสามารถจัดหาเครื่องสกัดกั้นในทุกคำขอและยกเลิกคำขอที่เราไม่ต้องการจริงๆ

Interceptor สามารถกำหนดได้ดังนี้:

 await page.setRequestInterception(true); page.on('request', (request) => { if (request.resourceType() === 'document') { request.continue(); } else { request.abort(); } });

อย่างที่คุณเห็น เรามีสิทธิ์ควบคุมคำขอที่เริ่มต้นได้อย่างสมบูรณ์ เราสามารถเขียนตรรกะที่กำหนดเองเพื่ออนุญาตหรือยกเลิกคำขอเฉพาะตามประเภท resourceType นอกจากนี้เรายังมีสิทธิ์เข้าถึงข้อมูลอื่นๆ มากมาย เช่น request.url เพื่อให้เราสามารถบล็อกเฉพาะ URL ที่ต้องการได้

ในตัวอย่างข้างต้น เราอนุญาตเฉพาะคำขอที่มีประเภททรัพยากรเป็น "document" เพื่อผ่านตัวกรองของเรา ซึ่งหมายความว่าเราจะบล็อกรูปภาพ, CSS และทุกอย่างอื่นนอกเหนือจากการตอบกลับ HTML ดั้งเดิม

นี่คือรหัสสุดท้ายของเรา:

 const puppeteer = require('puppeteer'); function run (pagesToScrape) { return new Promise(async (resolve, reject) => { try { if (!pagesToScrape) { pagesToScrape = 1; } const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setRequestInterception(true); page.on('request', (request) => { if (request.resourceType() === 'document') { request.continue(); } else { request.abort(); } }); await page.goto("https://news.ycombinator.com/"); let currentPage = 1; let urls = []; while (currentPage <= pagesToScrape) { await page.waitForSelector('a.storylink'); let newUrls = await page.evaluate(() => { let results = []; let items = document.querySelectorAll('a.storylink'); items.forEach((item) => { results.push({ url: item.getAttribute('href'), text: item.innerText, }); }); return results; }); urls = urls.concat(newUrls); if (currentPage < pagesToScrape) { await Promise.all([ await page.waitForSelector('a.morelink'), await page.click('a.morelink'), await page.waitForSelector('a.storylink') ]) } currentPage++; } browser.close(); return resolve(urls); } catch (e) { return reject(e); } }) } run(5).then(console.log).catch(console.error);

อยู่อย่างปลอดภัยด้วยการจำกัดอัตรา

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

เนื่องจากแง่มุมนี้เกี่ยวข้องกับสถาปัตยกรรมมากกว่า ฉันจะไม่กล่าวถึงเรื่องนี้ในเชิงลึกในบทแนะนำ Puppeteer นี้ ที่กล่าวว่าวิธีพื้นฐานที่สุดในการทำให้สคริปต์ Puppeteer ช้าลงคือการเพิ่มคำสั่ง sleep ลงไป:

js await page.waitFor(5000);

คำสั่งนี้จะบังคับให้สคริปต์ของคุณเข้าสู่โหมดสลีปเป็นเวลาห้าวินาที (5,000 มิลลิวินาที) คุณสามารถวางไว้ที่ใดก็ได้ก่อน browser.close()

เช่นเดียวกับการจำกัดการใช้บริการของบุคคลที่สาม มีวิธีอื่นๆ ที่มีประสิทธิภาพมากขึ้นในการควบคุมการใช้งาน Puppeteer ของคุณ ตัวอย่างหนึ่งคือการสร้างระบบคิวที่มีจำนวนผู้ปฏิบัติงานจำกัด ทุกครั้งที่คุณต้องการใช้ Puppeteer คุณจะต้องพุชงานใหม่เข้าไปในคิว แต่จะมีพนักงานจำนวนจำกัดเท่านั้นที่สามารถทำงานได้ในนั้น นี่เป็นวิธีปฏิบัติทั่วไปเมื่อต้องรับมือกับขีดจำกัดอัตรา API ของบุคคลที่สาม และสามารถนำไปใช้กับการดึงข้อมูลเว็บ Puppeteer ได้เช่นกัน

Puppeteer's Place ในเว็บที่เคลื่อนไหวเร็ว

ในบทช่วยสอน Puppeteer นี้ ฉันได้สาธิตการทำงานพื้นฐานเป็นเครื่องมือในการขูดเว็บ อย่างไรก็ตาม มันมีกรณีการใช้งานที่กว้างขึ้นมาก รวมถึงการทดสอบเบราว์เซอร์ที่ไม่มีส่วนหัว การสร้าง PDF และการตรวจสอบประสิทธิภาพ และอื่นๆ อีกมากมาย

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