|
// 📌 Description: Crawl lịch cúp điện từ trang web lichcupdien và gửi email thông báo |
|
// ⚠️ Lưu ý: Script này chỉ có thể lấy dữ liệu từ trang web lichcupdien.org, không thể hoạt động với các trang web khác |
|
|
|
// Các URL cần lấy dữ liệu |
|
// Mỗi url (tương ứng với tỉnh/thành phố) có thể lọc ra các khu vực cần thiết để nhận thông báo, cách nhau bởi dấu phẩy |
|
// Nếu muốn lấy thông báo cúp điện từ tất cả các khu vực của một tỉnh/thành phố, điền <ALL> |
|
// Điền theo mẫu như ví dụ bên dưới, mỗi url (tỉnh/thành phố) cách nhau bởi dấu xuống dòng |
|
// Ví dụ: Muốn lấy thông báo cúp điện từ Phú Quới (Vĩnh Long), Tắc Vân và Định Bình (Cà Mau), tất cả khu vực ở An Giang |
|
const urlString = ` |
|
https://lichcupdien.org/lich-cup-dien-vinh-long: Phú Quới |
|
https://lichcupdien.org/lich-cup-dien-ca-mau: Tắc Vân, Định Bình |
|
https://lichcupdien.org/lich-cup-dien-an-giang: <ALL> |
|
`; |
|
// Hãy thay đổi các giá trị ở trên để lấy thông báo cúp điện từ các tỉnh/thành phố mà bạn quan tâm |
|
|
|
// Có thể gửi thông báo đến nhiều email, mỗi email cách nhau bởi dấu phẩy |
|
const recipients = "[email protected]"; |
|
|
|
function main() { |
|
crawlAndSendMail(); |
|
} |
|
|
|
function crawlAndSendMail() { |
|
let htmlBody = ""; |
|
|
|
const urls = {}; |
|
urlString.split("\n").forEach((line) => { |
|
if (!line.trim()) { |
|
return; |
|
} |
|
const parts = line.split(":"); |
|
const url = parts.slice(0, -1).join(":").trim(); |
|
const areas = parts[parts.length - 1].trim(); |
|
urls[url] = areas; |
|
}); |
|
|
|
for (const [url, areas] of Object.entries(urls)) { |
|
const items = crawlData(url, areas); |
|
htmlBody += `<h2 style="color: #4CAF50;">Lịch Cúp Điện Tại ${toUpperCaseEachWord((url.split("lich-cup-dien-")[1] || "").replace(/-/g, " "))} (${areas})</h2>`; |
|
htmlBody += `<div style="font-family: Arial, sans-serif; color: #333;">`; |
|
|
|
if (!items.length) { |
|
htmlBody += `<p>Không có thông báo cúp điện nào.</p>`; |
|
} else { |
|
items.forEach((item) => { |
|
const highlightedArea = item.khuVuc.replace( |
|
new RegExp(item.areaDetected, "gi"), |
|
'<strong style="color: red;">' + |
|
toUpperCaseEachWord(item.areaDetected) + |
|
"</strong>" |
|
); |
|
|
|
htmlBody += ` |
|
<div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 5px;"> |
|
<p><strong>Điện lực:</strong> ${item.dienLuc}</p> |
|
<p><strong>Ngày:</strong> ${item.ngay}</p> |
|
<p><strong>Thời Gian Cúp:</strong> Từ <strong>${item.thoiGian.from}</strong> đến <strong>${item.thoiGian.to}</strong></p> |
|
<p><strong>Khu Vực:</strong> ${highlightedArea}</p> |
|
<p><strong>Lý Do:</strong> ${item.lyDo}</p> |
|
<p><strong>Trạng Thái:</strong> ${item.trangThai}</p> |
|
</div> |
|
`; |
|
}); |
|
} |
|
htmlBody += `</div>`; |
|
} |
|
|
|
htmlBody += `<p style="font-size: 12px; color: #888;">Đây là email tự động, vui lòng không trả lời.</p>`; |
|
|
|
// Sử dụng GmailApp để gửi email |
|
const recipientsArray = recipients.split(",").map((email) => email.trim()); |
|
for (const recipient of recipientsArray) { |
|
GmailApp.sendEmail(recipient, "Lịch Cúp Điện", "", { |
|
htmlBody |
|
}); |
|
} |
|
} |
|
|
|
/** |
|
* Crawls and filters data from a specified URL based on given areas |
|
* @param {string} url - The URL to fetch data from |
|
* @param {string} areasString - Comma-separated string of area names to filter by |
|
* @returns {Array<Object>} Array of filtered data items where each item's khuVuc property includes one of the specified areas. |
|
* Each matching item will have an additional 'areaDetected' property added. |
|
* @throws {Error} May throw errors related to URL fetching or HTML parsing |
|
*/ |
|
function crawlData(url, areasString = "") { |
|
const areas = areasString.split(",").map((area) => area.trim().toLowerCase()); |
|
const response = UrlFetchApp.fetch(url); |
|
const html = response.getContentText(); |
|
const data = parseData(html); |
|
|
|
if (areasString.toLocaleLowerCase() === "<all>") { |
|
return data; |
|
} |
|
|
|
return data.filter((item) => |
|
areas.some((area) => { |
|
const isMatch = (item.khuVuc || "").toLowerCase().includes(area); |
|
if (isMatch) { |
|
item.areaDetected = area; |
|
} |
|
return isMatch; |
|
}) |
|
); |
|
} |
|
|
|
function parseData(html) { |
|
const result = []; |
|
|
|
// Tách các phần lịch cúp điện |
|
const parts = html.split('<div class="lcd_detail_wrapper">').slice(1); |
|
|
|
parts.forEach((part) => { |
|
const item = {}; |
|
|
|
// Điện lực |
|
const dienLucMatch = part.match( |
|
/<span class="content_item_content_lcd_wrapper item_txt_bold">([^<]+)<\/span>/ |
|
); |
|
if (dienLucMatch) { |
|
item.dienLuc = dienLucMatch[1]; |
|
} |
|
|
|
// Ngày |
|
const ngayMatch = part.match( |
|
/<span class="content_item_content_lcd_wrapper item_txt_bold item_txt_red">([^<]+)<\/span>/ |
|
); |
|
if (ngayMatch) { |
|
item.ngay = ngayMatch[1]; |
|
} |
|
|
|
// Thời gian |
|
const thoiGianMatch = part.match( |
|
/Từ <span class="item_lcd_time">([^<]+)<\/span> đến <span class="item_lcd_time">([^<]+)<\/span>/ |
|
); |
|
if (thoiGianMatch) { |
|
item.thoiGian = { |
|
from: thoiGianMatch[1], |
|
to: thoiGianMatch[2] |
|
}; |
|
} |
|
|
|
// Khu vực |
|
const khuVucMatch = part.match( |
|
/<span class="content_item_content_lcd_wrapper">([^<]+)<\/span>/ |
|
); |
|
if (khuVucMatch) { |
|
item.khuVuc = khuVucMatch[1]; |
|
} |
|
|
|
// Lý do |
|
const lyDoMatch = part.match( |
|
/<span class="content_item_content_lcd_wrapper">([^<]+)<\/span>/ |
|
); |
|
if (lyDoMatch) { |
|
item.lyDo = lyDoMatch[1]; |
|
} |
|
|
|
// Trạng thái |
|
const trangThaiMatch = part.match( |
|
/<span class="content_item_content_lcd_wrapper lcd_check_trang_thai">([^<]+)<\/span>/ |
|
); |
|
if (trangThaiMatch) { |
|
item.trangThai = trangThaiMatch[1]; |
|
} |
|
|
|
result.push(item); |
|
}); |
|
|
|
return result; |
|
} |
|
|
|
function toUpperCaseEachWord(str) { |
|
const words = str.split(" "); |
|
return words |
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) |
|
.join(" "); |
|
} |