Skip to main content

วิธีทำ Web scraping ดูดข้อมูลจากเว็บอื่นมาใช้ประโยชน์ง่าย ๆ ด้วย Cheerio

· 7 min read

Intro​

สวัสดีครับ บทความนี้จะพาทำ Web scraping คือการดูดข้อมูลหรือดึงข้อมูลจาก URL หรือเว็บไชต์อื่น ๆ เพื่อเอาข้อมูลเหล่านั้นมาใช้ประโยชน์ โดยจะมี 2 ขั้นตอนคือ

  1. การดึงข้อมูลหน้าเว็บทั้งหมด
  2. การสกัดเอาเฉพาะข้อมูลที่ต้องการ

ก่อนเริ่ม​

คำเตือน

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

ในตัวอย่างการทำ Web scraping นี้จะใช้เครื่องมือหลัก ๆ 2 ตัวคือ

  • Cheerio สำหรับจัดการ Cheerio
  • Axios สำหรับการยิง Request

ภาษาที่จะใช้คือ Javascript รันบน NodeJS เนื่องจากมีความเร็วพวกสมควรและ Cheerio สามารถจัดการกับ Element ของ HTML ได้ง่ายมากเริ่มกันเลยครับ

โจทย์​

โจทย์ที่เราต้องการคือดึงข้อมูลที่อยู่ในตารางนี้

Weekend of July 9 - 11, 2021


TitleWeekendGrossWeeks
Black Widow

$80.4M

$80.4M1
F9

$11.4M

$141.9M3
The Boss Baby: Family Business

$8.9M

$34.9M2
The Forever Purge

$7.1M

$27.9M2
A Quiet Place Part II

$3.2M

$150.8M7
Cruella

$2.4M

$80.9M7
Hitman's Wife's Bodyguard

$1.6M

$35.0M4
Peter Rabbit 2: The Runaway

$1.3M

$37.7M5
The Conjuring: The Devil Made Me Do It

$655K

$63.8M6
Zola

$620K

$3.5M2

และต้องการข้อมูลที่อยู่ในรูปแบบ Objects ดังนี้

{
weekendOf: "Weekend of July 9 - 11, 2021",
movies: [
{
title: "Black Widow",
weekend: "$80.4M",
gross: "$80.4M",
weeks: "1",
}
...
]
}

วิเคราะห์ HTML Elements​

การสกัดข้อมูลจาก HTML นั้นให้กด F12 หรือ คลิกขวาที่หน้า Webpage ใน Web Browser จากนั้นเลือก Inspect Element

weekendOf​

img img

สำหรับลำดับ Selector ของ weekendOf นั้นเข้าถึงง่ายมากไม่มีปัญหาอะไร แถมมี div และ id = boxoffice มาครอบไว้ดังนั้นเราจะได้ Selector ดังนี้

#boxoffice > h4

Title​

img img

สำหรับลำดับ Selector ของ Title ในอยู่ใน table โชคดีที่แยกส่วนเป็น tbody แต่มีปัญหาอยู่ว่ามี Element span ครอบไว้ดังนั้นก่อนจะดึงข้อมูลใน td ได้ต้องเข้าถึง span ก่อน

สำหรับเข้าถึงเฉพาะข้อมูลตัวแรก

#boxoffice > table > tbody > tr:nth-child(1) > td.titleColumn > span

เมื่อเราจะเข้าถึงข้อมูลทุกตัวของ Selector ของ Title จะได้ดังนี้

#boxoffice > table > tbody > tr

จะได้

Title = td[0] > span

Weekend​

img img

สำหรับ Weekend นั้นอยู่ภายใต้ tr แต่อยู่ td ลำดับที่ 2 ดังนั้น Selector คือ

Weekend = td[1]

Gross​

img img

สำหรับ Gross นั้นอยู่ภายใต้ tr แต่อยู่ td ลำดับที่ 3 ดังนั้น Selector คือ

Gross = td[2] > span

Weeks​

img img

สำหรับ Weeks นั้นอยู่ภายใต้ tr แต่อยู่ td ลำดับที่ 4 ดังนั้น Selector คือ

Weekend = td[3]

ขั้นตอนการสกัดข้อมูล​

สร้างโปรเจคใหม่ และติดตั้ง Packages ที่ต้องใช้งาน
mkdir web-scraping-by-cheerio && cd ./web-scraping-by-cheerio
touch index.js
npm init -y
npm install cheerio axios
index.js
const axios = require("axios")
const cheerio = require("cheerio")

const app = async () => {
// ใช้ axios ส่ง request เพื่อร้องขอข้อมูลแล้วให้ response ข้อมูลกลับ
const html = await fetchData('https://blog.2my.xyz/2021/07/07/web-scraping-by-cheerio')
// เมื่อได้ HTML จาก axios แล้วก็ส่งไปสกัดเพื่อเอาเฉพาะข้อมูลที่ต้องการ
const result = extractData(html)

console.log(result)
}


const fetchData = (url) => {
// ส่ง request เพื่อร้องขอข้อมูลหน้าเว็บเพจทั้งหน้า
return axios.get(url).then(response => response.data)
}

const extractData = (html) => {
// ส่งข้อมูล HTML เข้า Method load ของ cheerio
// จากนั้นเราสามารถเข้าถึงข้อมูลทุก Element ผ่านตัวแปร $
const $ = cheerio.load(html);

// ดึงข้อมูล weekendOf จาก Selector ที่เราได้วิเคราะห์ไว้ แล้วสกัดข้อมูล Text ออกมา
const weekendOf = $('#boxoffice > h4').text()

// สำหรับข้อมูลในตารางมีหลายแถวดังนั้นเราจึงใช้ Loop แบบ Map มาช่วย
const movies = $('#boxoffice > table > tbody > tr').map((i, element) => {
// วน Loop ทีละ Element tr (แต่ละแถวของข้อมูล)
// เข้าถึง td และเก็บไว้ที่ตัวแปร
const td = $(element).find("td");

return {
// เข้าถึง Selector คอลั่มน์ที่ 1 แล้วเข้าไปที่ span จากนั้นสกัดข้อมูล Text ออกมา
title: $(td[0]).children('span').text(),
// เข้าถึง Selector คอลั่มน์ที่ 2 แล้วสกัดข้อมูล Text ออกมา
weekend: $(td[1]).text(),
// เข้าถึง Selector คอลั่มน์ที่ 3 แล้วเข้าไปที่ span จากนั้นสกัดข้อมูล Text ออกมา
gross: $(td[2]).children('span').text(),
// เข้าถึง Selector คอลั่มน์ที่ 2 แล้วสกัดข้อมูล Text ออกมา
weeks: $(td[3]).text(),
}
}).toArray()

return { weekendOf, movies }
}

app()
สั่งรัน
node index.js

ผลลัพธ์​

{
weekendOf: 'Weekend of July 9 - 11, 2021',
movies: [
{
title: 'Black Widow',
weekend: '$80.4M',
gross: '$80.4M',
weeks: '1'
},
{ title: 'F9', weekend: '$11.4M', gross: '$141.9M', weeks: '3' },
{
title: 'The Boss Baby: Family Business',
weekend: '$8.9M',
gross: '$34.9M',
weeks: '2'
},
{
title: 'The Forever Purge',
weekend: '$7.1M',
gross: '$27.9M',
weeks: '2'
},
{
title: 'A Quiet Place Part II',
weekend: '$3.2M',
gross: '$150.8M',
weeks: '7'
},
{ title: 'Cruella', weekend: '$2.4M', gross: '$80.9M', weeks: '7' },
{
title: "Hitman's Wife's Bodyguard",
weekend: '$1.6M',
gross: '$35.0M',
weeks: '4'
},
{
title: 'Peter Rabbit 2: The Runaway',
weekend: '$1.3M',
gross: '$37.7M',
weeks: '5'
},
{
title: 'The Conjuring: The Devil Made Me Do It',
weekend: '$655K',
gross: '$63.8M',
weeks: '6'
},
{ title: 'Zola', weekend: '$620K', gross: '$3.5M', weeks: '2' }
]
}

สรุป​

สำหรับการทำ Web Scraping ด้วย Cheerio นั้นสรุปหลักการดังนี้

  1. ใช้ axios หรือ fetch request สักตัวในการดึง HTML Content ทั้งหน้าที่ต้องการมา
  2. ใช้ Cheerio ในการสกัดข้อมูลใน HTML

ถ้าคุณมีพื้นฐานของ jQuery อยู่แล้วก็จะเข้าใจและใช้งาน Cheerio ได้เร็ว แต่ถ้าคุณไม่ได้มีความรู้ในการเข้าถึงข้อมูลใน Elements มากนักแนะนำให้ศึกษาเพิ่มเติมจากที่นี่ https://cheerio.js.org

อ้างอิง​

แชร์บทความ
☕

เนื้อหานี้มีประโยชน์ไหม? ช่วยสนับสนุนค่ากาแฟให้ผู้เขียนสักแก้ว

Buy Me a Coffee
Loading...