คู่มือการคัดลอกเว็บไซต์แบบไดนามิกอย่างมีจริยธรรมด้วย Node.js และ Puppeteer

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างรวดเร็ว ↬ สำหรับงานขูดเว็บจำนวนมาก ไคลเอนต์ HTTP ก็เพียงพอที่จะดึงข้อมูลของหน้า อย่างไรก็ตาม เมื่อพูดถึงเว็บไซต์ไดนามิก เบราว์เซอร์หัวขาดในบางครั้งอาจเป็นสิ่งที่ขาดไม่ได้ ในบทช่วยสอนนี้ เราจะสร้างเว็บสแครปเปอร์ที่สามารถขูดเว็บไซต์ไดนามิกตาม Node.js และ Puppeteer

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

เมื่อใช้คำนี้ในอุตสาหกรรมซอฟต์แวร์ เรามักจะอ้างถึงการ ทำงานอัตโนมัติของงานที่ทำด้วยตนเองนี้ โดยใช้ซอฟต์แวร์ชิ้นหนึ่ง ยึดตามตัวอย่าง “จานก๋วยเตี๋ยว” ก่อนหน้าของเรา กระบวนการนี้มักประกอบด้วยสองขั้นตอน:

  • กำลังดึงหน้า
    ก่อนอื่นเราต้องดาวน์โหลดทั้งหน้า ขั้นตอนนี้เหมือนกับการเปิดหน้าในเว็บเบราว์เซอร์ของคุณเมื่อทำการขูดด้วยตนเอง
  • การแยกวิเคราะห์ข้อมูล
    ตอนนี้ เราต้องแยกสูตรใน HTML ของเว็บไซต์และแปลงเป็นรูปแบบที่เครื่องอ่านได้ เช่น JSON หรือ XML

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

ในช่วงเวลานี้ ฉันเห็นบริษัทต่างๆ ใช้การขูดเว็บสำหรับกรณีการใช้งานทุกประเภท บริษัทด้านการลงทุนมุ่งเน้นไปที่การรวบรวมข้อมูลทางเลือกเป็นหลัก เช่น บทวิจารณ์ผลิตภัณฑ์ ข้อมูลราคา หรือโพสต์บนโซเชียลมีเดียเพื่อสนับสนุนการลงทุนทางการเงินของพวกเขา

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

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

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ยึดตามกฎ

โดยทั่วไป การดึงข้อมูลเว็บที่เปิดเผยต่อสาธารณะนั้นถูกกฎหมาย ตามที่ได้รับการยืนยันโดยเขตอำนาจศาลของคดี Linkedin กับ HiQ อย่างไรก็ตาม ฉันได้ตั้งกฎเกณฑ์ทางจริยธรรมให้กับตัวเองที่ฉันชอบยึดถือเมื่อเริ่มโครงการขูดเว็บใหม่ ซึ่งรวมถึง:

  • กำลังตรวจสอบไฟล์ robots.txt
    โดยปกติจะมีข้อมูลที่ชัดเจนเกี่ยวกับส่วนใดของไซต์ที่เจ้าของเพจสามารถเข้าถึงได้โดยโรบ็อตและแครปเปอร์ และเน้นส่วนที่ไม่ควรเข้าถึง
  • การอ่านข้อกำหนดและเงื่อนไข
    เมื่อเทียบกับ robots.txt ข้อมูลชิ้นนี้ไม่ได้มีให้บ่อยนัก แต่มักจะระบุวิธีจัดการกับข้อมูลแครปเปอร์
  • ขูดด้วยความเร็วปานกลาง
    การขูดจะสร้างภาระงานของเซิร์ฟเวอร์บนโครงสร้างพื้นฐานของไซต์เป้าหมาย ขึ้นอยู่กับสิ่งที่คุณขูดและระดับการทำงานพร้อมกันที่มีดโกนของคุณทำงาน การรับส่งข้อมูลอาจทำให้เกิดปัญหาสำหรับโครงสร้างพื้นฐานเซิร์ฟเวอร์ของไซต์เป้าหมาย แน่นอนว่าความจุของเซิร์ฟเวอร์มีบทบาทสำคัญในสมการนี้ ดังนั้น ความเร็วของมีดโกนของฉันจึงเป็น ความสมดุลระหว่างปริมาณข้อมูลที่ฉันตั้งใจจะขูดและความนิยมของไซต์เป้าหมายเสมอ การหาจุดสมดุลนี้สามารถทำได้โดยการตอบคำถามเดียว: "ความเร็วที่วางแผนไว้จะเปลี่ยนการเข้าชมที่เกิดขึ้นเองของไซต์อย่างมากหรือไม่" ในกรณีที่ฉันไม่แน่ใจเกี่ยวกับปริมาณการเข้าชมเว็บไซต์ตามธรรมชาติ ฉันใช้เครื่องมือเช่น ahrefs เพื่อทำความเข้าใจคร่าวๆ

การเลือกเทคโนโลยีที่เหมาะสม

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

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

สถานการณ์

  • คุณต้องการขูด 20,000 URLs
  • เวลาตอบสนองเฉลี่ยจากไซต์เป้าหมายคือ 6 วินาที
  • เซิร์ฟเวอร์ของคุณมีซีพียู 2 คอร์

โครงการจะใช้เวลา 16 ชั่วโมง จึงจะแล้วเสร็จ

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

ต่อไปนี้คือรายการตรวจสอบเล็กๆ น้อยๆ ที่ฉันต้องทำเสมอ:

  • ฉันสามารถบังคับสถานะของหน้าที่ต้องการผ่านพารามิเตอร์ GET ใน URL ได้หรือไม่ ถ้าใช่ เราสามารถเรียกใช้คำขอ HTTP ด้วยพารามิเตอร์ที่ต่อท้ายได้
  • ข้อมูลแบบไดนามิกเป็นส่วนหนึ่งของแหล่งที่มาของหน้าและพร้อมใช้งานผ่านวัตถุ JavaScript ที่ใดที่หนึ่งใน DOM ถ้าใช่ เราสามารถใช้คำขอ HTTP ปกติได้อีกครั้งและแยกวิเคราะห์ข้อมูลจากวัตถุที่ทำให้เป็นสตริง
  • ข้อมูลถูกดึงผ่านคำขอ XHR หรือไม่ ถ้าใช่ ฉันสามารถเข้าถึงปลายทางโดยตรงด้วยไคลเอนต์ HTTP ได้หรือไม่ ถ้าใช่ เราสามารถส่งคำขอ HTTP ไปยังปลายทางได้โดยตรง หลายครั้ง การตอบสนองยังอยู่ในรูปแบบ JSON ซึ่งทำให้ชีวิตของเราง่ายขึ้นมาก

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

หากคุณสามารถเข้าถึงได้ด้วยเบราว์เซอร์ คุณสามารถขูดได้

ลองใช้ไซต์ต่อไปนี้เป็นตัวอย่างสำหรับมีดโกนของเรา: https://quotes.toscrape.com/search.aspx มันมีคำพูดจากรายชื่อผู้เขียนที่กำหนดสำหรับรายการหัวข้อ ข้อมูลทั้งหมดถูกดึงผ่าน XHR

เว็บไซต์ที่มีการแสดงข้อมูลแบบไดนามิก
ตัวอย่างเว็บไซต์ที่มีข้อมูลที่แสดงผลแบบไดนามิก (ตัวอย่างขนาดใหญ่)

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

การติดตั้งข้อกำหนดเบื้องต้น

เนื่องจากเราจะสร้างทุกอย่างโดยใช้ Node.js ก่อนอื่นให้สร้างและเปิดโฟลเดอร์ใหม่ และสร้างโปรเจ็กต์ Node ใหม่ภายใน โดยใช้คำสั่งต่อไปนี้:

 mkdir js-webscraper cd js-webscraper npm init

โปรดตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง npm แล้ว โปรแกรมติดตั้งจะถามคำถามสองสามข้อเกี่ยวกับข้อมูลเมตาเกี่ยวกับโครงการนี้ ซึ่งเราทุกคนสามารถข้ามได้โดยกด Enter

การติดตั้ง Puppeteer

เราเคยพูดถึงการขูดด้วยเบราว์เซอร์มาก่อน Puppeteer เป็น Node.js API ที่ช่วยให้เราสามารถพูดคุยกับ อินสแตนซ์ Chrome ที่ไม่มีส่วนหัว โดยทางโปรแกรม

มาติดตั้งโดยใช้ npm:

 npm install puppeteer

การสร้างเครื่องขูดของเรา

ตอนนี้ มาเริ่มสร้างมีดโกนของเราโดยสร้างไฟล์ใหม่ที่เรียกว่า scraper.js

ขั้นแรก เรานำเข้าไลบรารีที่ติดตั้งไว้ก่อนหน้านี้ Puppeteer:

 const puppeteer = require('puppeteer');

ในขั้นตอนต่อไป เราบอกให้ Puppeteer เปิดอินสแตนซ์เบราว์เซอร์ใหม่ภายในฟังก์ชันแบบอะซิงโครนัสและดำเนินการเอง:

 (async function scrape() { const browser = await puppeteer.launch({ headless: false }); // scraping logic comes here… })();

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

ภายในเบราว์เซอร์ที่เปิดอยู่ ตอนนี้เราเปิดหน้าใหม่และตรงไปยัง URL เป้าหมายของเรา:

 const page = await browser.newPage(); await page.goto('https://quotes.toscrape.com/search.aspx');

ในส่วนหนึ่งของฟังก์ชันอะซิงโครนัส เราจะใช้คำสั่ง await เพื่อรอให้คำสั่งต่อไปนี้ทำงานก่อนที่จะดำเนินการกับโค้ดบรรทัดถัดไป

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

หัวข้อที่มีอยู่จะถูกสร้างขึ้นแบบไดนามิกสำหรับผู้เขียนที่เลือก ดังนั้น ก่อนอื่นเราจะเลือก 'Albert Einstein' และรอรายการหัวข้อที่สร้างขึ้น เมื่อรายการถูกสร้างขึ้นอย่างสมบูรณ์แล้ว เราเลือก 'การเรียนรู้' เป็นหัวข้อและเลือกเป็นพารามิเตอร์รูปแบบที่สอง จากนั้นเราคลิกที่ส่งและดึงใบเสนอราคาที่ดึงมาจากคอนเทนเนอร์ที่ถือผลลัพธ์

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

ฟิลด์เลือกผู้เขียน #author
แท็กเลือกช่อง #tag
ปุ่มส่ง input[type="submit"]
คอนเทนเนอร์ใบเสนอราคา .quote

ก่อนที่เราจะเริ่มโต้ตอบกับเพจ เราจะตรวจสอบให้แน่ใจว่าองค์ประกอบทั้งหมดที่เราจะเข้าถึงนั้นมองเห็นได้ โดยการเพิ่มบรรทัดต่อไปนี้ในสคริปต์ของเรา:

 await page.waitForSelector('#author'); await page.waitForSelector('#tag');

ต่อไป เราจะเลือกค่าสำหรับสองฟิลด์ที่เลือกของเรา:

 await page.select('select#author', 'Albert Einstein'); await page.select('select#tag', 'learning');

ตอนนี้เราพร้อมที่จะทำการค้นหาโดยกดปุ่ม "ค้นหา" บนหน้าและรอให้คำพูดปรากฏขึ้น:

 await page.click('.btn'); await page.waitForSelector('.quote');

เนื่องจากตอนนี้เรากำลังจะเข้าถึงโครงสร้าง HTML DOM ของหน้า เราจึงเรียกใช้ page.evaluate() ที่ให้มา โดยเลือกคอนเทนเนอร์ที่ถือเครื่องหมายคำพูด (ในกรณีนี้คืออันเดียวเท่านั้น) จากนั้นเราสร้างอ็อบเจ็กต์และกำหนด null เป็นค่าทางเลือกสำหรับพารามิเตอร์ object แต่ละตัว:

 let quotes = await page.evaluate(() => { let quotesElement = document.body.querySelectorAll('.quote'); let quotes = Object.values(quotesElement).map(x => { return { author: x.querySelector('.author').textContent ?? null, quote: x.querySelector('.content').textContent ?? null, tag: x.querySelector('.tag').textContent ?? null, }; }); return quotes; });

เราสามารถทำให้ผลลัพธ์ทั้งหมดปรากฏในคอนโซลของเราได้โดยการบันทึก:

 console.log(quotes);

สุดท้าย ให้ปิดเบราว์เซอร์ของเราและเพิ่มคำสั่ง catch:

 await browser.close();

มีดโกนที่สมบูรณ์มีลักษณะดังนี้:

 const puppeteer = require('puppeteer'); (async function scrape() { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://quotes.toscrape.com/search.aspx'); await page.waitForSelector('#author'); await page.select('#author', 'Albert Einstein'); await page.waitForSelector('#tag'); await page.select('#tag', 'learning'); await page.click('.btn'); await page.waitForSelector('.quote'); // extracting information from code let quotes = await page.evaluate(() => { let quotesElement = document.body.querySelectorAll('.quote'); let quotes = Object.values(quotesElement).map(x => { return { author: x.querySelector('.author').textContent ?? null, quote: x.querySelector('.content').textContent ?? null, tag: x.querySelector('.tag').textContent ?? null, } }); return quotes; }); // logging results console.log(quotes); await browser.close(); })();

ลองใช้มีดโกนของเราด้วย:

 node scraper.js

และเราไปกันเลย! มีดโกนส่งคืนอ็อบเจ็กต์ใบเสนอราคาของเราตามที่คาดไว้:

ผลลัพธ์ของมีดโกนเว็บของเรา
ผลลัพธ์ของมีดโกนเว็บของเรา (ตัวอย่างขนาดใหญ่)

การเพิ่มประสิทธิภาพขั้นสูง

เครื่องขูดพื้นฐานของเรากำลังทำงานอยู่ มาเพิ่มการปรับปรุงเพื่อเตรียมพร้อมสำหรับงานขูดที่จริงจังกว่านี้

การตั้งค่า User-Agent

ตามค่าเริ่มต้น Puppeteer จะใช้ user-agent ที่มีสตริง HeadlessChrome มีเว็บไซต์ไม่กี่แห่งที่มองหาลายเซ็นประเภทนี้และ บล็อกคำขอที่เข้ามา ด้วยลายเซ็นแบบนั้น เพื่อหลีกเลี่ยงไม่ให้เป็นสาเหตุที่เป็นไปได้สำหรับมีดโกนที่จะล้มเหลว ฉันมักจะตั้งค่า user-agent ที่กำหนดเอง โดยเพิ่มบรรทัดต่อไปนี้ในโค้ดของเรา:

 await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4298.0 Safari/537.36');

สิ่งนี้สามารถปรับปรุงให้ดียิ่งขึ้นไปอีกโดยการเลือก User-agent แบบสุ่มกับคำขอแต่ละรายการจากอาร์เรย์ของ user-agent ที่พบบ่อยที่สุด 5 อันดับแรก รายชื่อ User-agent ที่พบบ่อยที่สุดสามารถพบได้ใน Most Common User-Agents

การใช้พร็อกซี่

Puppeteer ทำให้การเชื่อมต่อกับพร็อกซีเป็นเรื่องง่ายมาก เนื่องจากที่อยู่พร็อกซีสามารถส่งไปยัง Puppeteer เมื่อเปิดใช้งานได้ เช่นนี้:

 const browser = await puppeteer.launch({ headless: false, args: [ '--proxy-server=<PROXY-ADDRESS>' ] });

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

ข้อผิดพลาดและการจัดการลองใหม่

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

นอกจากนี้ ก็ไม่มีประโยชน์ที่จะลองส่งคำขอด้วยที่อยู่ IP เดิมอีกครั้งหากล้มเหลวก่อนหน้านี้ ดังนั้น เราจะสร้าง ระบบหมุนเวียนพร็อกซี่ ขนาดเล็ก

ก่อนอื่น เราสร้างตัวแปรใหม่สองตัว:

 let retry = 0; let maxRetries = 5;

ทุกครั้งที่เราเรียกใช้ฟังก์ชัน scrape() เราจะเพิ่มตัวแปรการลองใหม่เป็น 1 จากนั้นเราจะรวมตรรกะการขูดทั้งหมดด้วยคำสั่ง try and catch เพื่อให้เราสามารถจัดการกับข้อผิดพลาดได้ การจัดการลองใหม่เกิดขึ้นภายในฟังก์ชัน catch ของเรา:

อินสแตนซ์ของเบราว์เซอร์ก่อนหน้าจะถูกปิด และหากตัวแปรการลองใหม่ของเราน้อยกว่าตัวแปร maxRetries ฟังก์ชันการขูดจะถูกเรียกซ้ำ

มีดโกนของเราจะมีลักษณะดังนี้:

 const browser = await puppeteer.launch({ headless: false, args: ['--proxy-server=' + proxy] }); try { const page = await browser.newPage(); … // our scraping logic } catch(e) { console.log(e); await browser.close(); if (retry < maxRetries) { scrape(); } };

ตอนนี้ ให้เราเพิ่มตัวหมุนพร็อกซีที่กล่าวถึงก่อนหน้านี้

ขั้นแรกให้สร้างอาร์เรย์ที่มีรายการพร็อกซี่:

 let proxyList = [ '202.131.234.142:39330', '45.235.216.112:8080', '129.146.249.135:80', '148.251.20.79' ];

ตอนนี้ เลือกค่าสุ่มจากอาร์เรย์:

 var proxy = proxyList[Math.floor(Math.random() * proxyList.length)];

ตอนนี้เราสามารถเรียกใช้พร็อกซีที่สร้างแบบไดนามิกร่วมกับอินสแตนซ์ Puppeteer ของเรา:

 const browser = await puppeteer.launch({ headless: false, args: ['--proxy-server=' + proxy] });

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

นี่คือรหัสของมีดโกนของเรา (รวมถึงการปรับปรุงทั้งหมด):

 const puppeteer = require('puppeteer'); // starting Puppeteer let retry = 0; let maxRetries = 5; (async function scrape() { retry++; let proxyList = [ '202.131.234.142:39330', '45.235.216.112:8080', '129.146.249.135:80', '148.251.20.79' ]; var proxy = proxyList[Math.floor(Math.random() * proxyList.length)]; console.log('proxy: ' + proxy); const browser = await puppeteer.launch({ headless: false, args: ['--proxy-server=' + proxy] }); try { const page = await browser.newPage(); await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4298.0 Safari/537.36'); await page.goto('https://quotes.toscrape.com/search.aspx'); await page.waitForSelector('select#author'); await page.select('select#author', 'Albert Einstein'); await page.waitForSelector('#tag'); await page.select('select#tag', 'learning'); await page.click('.btn'); await page.waitForSelector('.quote'); // extracting information from code let quotes = await page.evaluate(() => { let quotesElement = document.body.querySelectorAll('.quote'); let quotes = Object.values(quotesElement).map(x => { return { author: x.querySelector('.author').textContent ?? null, quote: x.querySelector('.content').textContent ?? null, tag: x.querySelector('.tag').textContent ?? null, } }); return quotes; }); console.log(quotes); await browser.close(); } catch (e) { await browser.close(); if (retry < maxRetries) { scrape(); } } })();

โว้ว! การเรียกใช้เครื่องขูดของเราภายในเทอร์มินัลจะส่งคืนราคา

นักเขียนบทละครทางเลือกแทนคนเชิดหุ่น

Puppeteer ได้รับการพัฒนาโดย Google เมื่อต้นปี 2563 Microsoft ได้เปิดตัวทางเลือกที่เรียกว่า Playwright Microsoft ได้ว่าจ้างวิศวกรจำนวนมากจากทีม Puppeteer-Team ดังนั้น นักเขียนบทละครจึงได้รับการพัฒนาโดยวิศวกรหลายคนที่ได้ลงมือทำ Puppeteer แล้ว นอกจากจะเป็นเด็กใหม่ในบล็อกแล้ว จุดแตกต่างที่ใหญ่ที่สุดของนักเขียนบทละครคือการสนับสนุนข้ามเบราว์เซอร์ เนื่องจากรองรับ Chromium, Firefox และ WebKit (Safari)

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

ความแตกต่างอื่นๆ เช่น ความจริงที่ว่าคุณสามารถเรียกใช้อุปกรณ์หลายเครื่องด้วยอินสแตนซ์เบราว์เซอร์เดียว ไม่ได้มีค่ามากสำหรับบริบทของการขูดเว็บ

แหล่งข้อมูลและลิงค์เพิ่มเติม

  • เอกสารเชิดหุ่น
  • การเรียนรู้หุ่นกระบอกและนักเขียนบทละคร
  • การขูดเว็บด้วย Javascript โดย Zenscrape
  • ตัวแทนผู้ใช้ทั่วไปส่วนใหญ่
  • Puppeteer vs. นักเขียนบทละคร