Add new JavaScript files for KM organization learning and recommended tourist attractions, along with JSON files for scraped data and HTML debug pages. Update package.json to include googleapis dependency. Fix minor formatting in award_of_pride.js.

This commit is contained in:
MacM1 2026-01-16 09:54:55 +07:00
parent 3e1abb0bec
commit 60c5130d65
20 changed files with 24944 additions and 1 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -184,7 +184,7 @@ function scrapeOnePage(menuId, page, saveHtml = false) {
} }
(function main() { (function main() {
const menuId = 1402; // กิจกรรม const menuId = 1402;
const totalPages = 1; const totalPages = 1;
const all = []; const all = [];

384
km-learning-organization.js Normal file
View File

@ -0,0 +1,384 @@
// หน้าแรก > งานบริการ > KM องค์กรแห่งการเรียนรู้
const { execSync } = require("child_process");
const cheerio = require("cheerio");
const fs = require("fs");
const path = require("path");
const axios = require("axios").default;
const BASE = "https://ladsawai.go.th";
const OUT = path.join(process.cwd(), "KM องค์กรแห่งการเรียนรู้");
fs.mkdirSync(OUT, { recursive: true });
function curlHtml(url) {
return execSync(
`curl -L -s "${url}" -H "User-Agent: Mozilla/5.0" -H "Accept-Language: th-TH,th;q=0.9"`,
{ encoding: "utf8", maxBuffer: 30 * 1024 * 1024 }
);
}
function absUrl(href) {
if (!href) return null;
if (href.startsWith("http")) return href;
if (href.startsWith("/")) return BASE + href;
return BASE + "/" + href;
}
function scrapeDetailImagesContent(detailUrl) {
const html = curlHtml(detailUrl);
const $ = cheerio.load(html);
// ---------- images ----------
const imgSet = new Set();
$(".maingroup.gallery a[href]").each((_, a) => {
const href = ($(a).attr("href") || "").trim();
const full = absUrl(href);
if (full) imgSet.add(full);
});
if (imgSet.size === 0) {
$("a[href]").each((_, a) => {
const href = ($(a).attr("href") || "").trim();
const full = absUrl(href);
if (full && /\.(jpg|jpeg|png|webp|gif)(\?|$)/i.test(full)) imgSet.add(full);
});
}
// ---------- content ----------
// ✅ เลือกกล่องที่ไม่ใช่ gallery และ "มีข้อความจริง"
const candidates = $(".col-12.maingroup").not(".gallery");
let bestBox = null;
let bestScore = -1;
candidates.each((_, el) => {
const $el = $(el);
// เอา text โดยตัดของไม่เกี่ยว (emoji img, script, style)
const text = $el
.clone()
.find("img, script, style")
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
const pCount = $el.find("p").length;
const score = (text ? text.length : 0) + pCount * 50; // ให้ p มีน้ำหนักเพิ่ม
if (score > bestScore) {
bestScore = score;
bestBox = $el;
}
});
let content = "";
if (bestBox && bestBox.length) {
const lines = [];
// วนตามลำดับจริงใน DOM: ทั้งหัวข้อ (h2) และเนื้อหา (p)
bestBox.find("h2, p").each((_, el) => {
const $node = $(el);
const tag = ($node.prop("tagName") || "").toLowerCase();
const t = $node
.clone()
.find("img") // ตัดรูป emoji ใน p/h2
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
if (!t) return;
// แยกหัวข้อให้เด่นขึ้นเล็กน้อย (ยังคงเป็น plain text)
if (tag === "h2") lines.push(t);
else lines.push(t);
});
content = lines.length
? lines.join("\n")
: bestBox
.clone()
.find("img, script, style")
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
}
let mainImageUrl = ''
try{
const mainImageDiv = $(".imagestopic img[src]");
const src = ($(mainImageDiv).attr("src") || "").trim();
const full = absUrl(src);
if (full) mainImageUrl = full;
}
catch(error){
mainImageUrl = ''
}
return { imgs: [...imgSet], text: content, mainImage: mainImageUrl };
}
function buildUrl(menuId, page) {
return `${BASE}/public/list/data/index/menu/${menuId}/page/${page}`;
}
function detectTotalPages($) {
let maxPage = 1;
$("a").each((_, a) => {
const t = $(a).text().trim();
if (/^\d+$/.test(t)) maxPage = Math.max(maxPage, Number(t));
});
return maxPage;
}
function extractFileLinksFromDetail(detailUrl) {
const html = curlHtml(detailUrl);
const $ = cheerio.load(html);
const files = [];
$("a.uploadconfig_link").each((_, a) => {
const el = $(a);
const href = el.attr("href");
const dataHref = el.attr("data-href");
const fileUrl = absUrl(dataHref || href);
if (!fileUrl) return;
const text = el.text().replace(/\s+/g, " ").trim() || null
let title = text
let downloadCount = 0
if(text && text.includes('ดาวน์โหลดแล้ว')){
try {
const splitList = text.split(' ดาวน์โหลดแล้ว ')
title = splitList[0]
downloadCount = parseInt(splitList[1].replace('ครั้ง', '').trim())
} catch (error) {
title = text
downloadCount = 0
}
}
files.push({
text: title,
url: fileUrl,
downloadCount: downloadCount
});
});
// fallback: ลิงก์ไฟล์แบบตรง ๆ
$("a[href]").each((_, a) => {
const href = $(a).attr("href");
const u = absUrl(href);
if (!u) return;
if (/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|zip|rar)(\?|$)/i.test(u)) {
if (!files.some((f) => f.url === u)) {
files.push({ text: $(a).text().trim() || null, url: u });
}
}
});
return files;
}
// ✅ ยิง api /status/1/ เพื่อเอา path จริง
async function resolveRealFilePath(fileUrl) {
try {
// กันกรณีมี / ท้ายอยู่แล้ว
const statusUrl = fileUrl.replace(/\/$/, "") + "/status/1/";
const res = await axios.get(statusUrl, { timeout: 30000 });
return res?.data?.path || null;
} catch (e) {
return null;
}
}
// ✅ limit concurrency แบบง่าย (กันยิงหนักเกิน)
async function mapLimit(arr, limit, mapper) {
const ret = [];
let i = 0;
async function worker() {
while (i < arr.length) {
const idx = i++;
ret[idx] = await mapper(arr[idx], idx);
}
}
const workers = Array.from({ length: Math.min(limit, arr.length) }, worker);
await Promise.all(workers);
return ret;
}
async function scrapeOnePage(menuId, page, saveHtml = false) {
const url = buildUrl(menuId, page);
const html = curlHtml(url);
if (saveHtml) {
fs.writeFileSync(
path.join(OUT, `debug-menu-${menuId}-page-${page}.html`),
html,
"utf8"
);
}
const $ = cheerio.load(html);
// ✅ แปลง rows เป็น array ก่อน
const rows = $(".row.data-row").toArray();
// ✅ ประมวลผลแบบมี limit (เช่น 5 concurrent)
const items = (await mapLimit(rows, 5, async (row) => {
const el = $(row);
const a = el.find("a.listdataconfig_link[href]").first();
if (!a.length) return null;
const title =
a.find("label.font-weight").text().replace(/\s+/g, " ").trim() ||
a.text().replace(/\s+/g, " ").trim();
if (!title) return null;
const detailUrl = absUrl(a.attr("href"));
let files = [];
let realPathFiles = []
try {
if (detailUrl) files = extractFileLinksFromDetail(detailUrl);
for(let i = 0; i < files.length; i++){
const file = files[i]
let realPath = null;
let fileObject = {
fileName: file.text,
fileUrl: file.url, // ไฟล์จากหน้า detail
filePath: "", // ✅ ของจริงจาก api /status/1/
downloadCount: file.downloadCount
}
try {
const fileUrl = file?.url ? absUrl(file.url) : null;
if (fileUrl) {
realPath = await resolveRealFilePath(fileUrl);
fileObject.filePath = `https://ladsawai.go.th/public/${realPath}`
}
} catch (error) {
realPath = null;
}
realPathFiles.push(fileObject)
}
} catch (e) {
files = [];
}
let detail = undefined
if(files.length == 0){
const { text, imgs, mainImage } = detailUrl ? scrapeDetailImagesContent(detailUrl) : [];
detail = {
img: imgs,
content: text,
mainImage: mainImage
}
}
let detailHtmlPath = ''
if (saveHtml) {
try {
// Extract id and menu from URL: /public/list/data/detail/id/{id}/menu/{menu}/page/{page}
const urlMatch = detailUrl.match(/\/id\/(\d+)\/menu\/(\d+)/);
const id = urlMatch ? urlMatch[1] : null;
// const menu = urlMatch ? urlMatch[2] : null;
const detailPageHtml = curlHtml(detailUrl);
detailHtmlPath = `debug-menu-${menuId}-detail-${id}.html`
fs.writeFileSync(
path.join(OUT, detailHtmlPath),
detailPageHtml,
"utf8"
);
} catch (error) {
console.error('error :', error)
detailHtmlPath = ''
}
}
return {
title,
detailUrl: detailUrl || null,
files: realPathFiles,
detail: detail,
detailPageHtml: detailHtmlPath ?? undefined, // ไฟล์จากหน้า detail
sourcePage: page,
sourceUrl: url,
};
}))
.filter(Boolean); // ตัด null ออก
const output = {
source: url,
scrapedAt: new Date().toISOString(),
menuId,
page,
count: items.length,
items,
};
fs.writeFileSync(
path.join(OUT, `menu-${menuId}-page-${page}.json`),
JSON.stringify(output, null, 2),
"utf8"
);
console.log(`✅ page ${page} -> items ${items.length}`);
return { $, items };
}
(async function main() {
const menuId = 1628;
const first = await scrapeOnePage(menuId, 1, true);
const totalPages = detectTotalPages(first.$);
console.log("✅ totalPages =", totalPages);
const all = [];
const seen = new Set();
function addItems(items) {
for (const it of items) {
const key = `${it.title}|${it.detailUrl || ""}|${it.filePath || ""}`;
if (seen.has(key)) continue;
seen.add(key);
all.push(it);
}
}
addItems(first.items);
for (let p = 2; p <= totalPages; p++) {
const { items } = await scrapeOnePage(menuId, p, false);
addItems(items);
}
const merged = {
menuId,
totalPages,
scrapedAt: new Date().toISOString(),
totalItems: all.length,
items: all,
};
const outAll = path.join(OUT, `menu-${menuId}-all.json`);
fs.writeFileSync(outAll, JSON.stringify(merged, null, 2), "utf8");
console.log("🎉 Saved all:", outAll);
console.log("🎉 Total unique:", all.length);
})();

View File

@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "lsw-website-484309",
"private_key_id": "6a86a07bc9d5c655d4d9b96462ab02c0d61d221e",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGm6pr5y1LguDH\ni5zfv7zpzGkaXSxWDoMIBfYf0s/cDuHFtObN1zE/6KErOFLaUQsS8ngvpVX9hNSf\n3X5F6E/1MQB4a/KgMbozP3AeaGTceyyd33QTKNSgTdSFcnJVHovmS37xfWL68jRa\nnj0toiq7C/46/VzzM41RNubiczVXt5Rer5YptRCSc9Pwv0gQkvrDNAsJqLX6+QW6\n/PVlR0ZUewB+dEQJO5ksVaOUhlfvrapx/HuxCZB4FA8V9alt2sefpeCv0OWSb/2Z\nWGtPfdXA3AIlKTefiUaMTAjF1YC0SaUzq9jVobnhE1Ub4dkufAj50vBjHDMxdUif\nT7NieruFAgMBAAECggEAUWsORbbbLDoGkPcsg9NUDBp2uc6ZdtvzHm5nNCuVd7aI\nGqcq+RZvQ65Hp/KqkIIpwoYw/ANRCaGTEshX1CvE35TLhxJlwAMyvICUo3qTYomC\nRGQO7y3NYLwXU++TbE6d9nZbn38R/SMekEmPde4li1GC0sb7/F1VYQZbR1kIdKD+\nKCvif0xvovkwQQi3aGM/nTYXeJDdkhEaVA/mD8Hc5yVauBK/W5eXqUMNuusDAKuy\nvR83ke5e/dLoN7VTBlMqUmDapbGtzWszTFmbK/SoY38IoD+Msz+0Ia5QFL7lyAMy\ndkJuHsz+IFZ3lBPBO1qT3alASIFUDNVs+a3m4Ja67wKBgQDkHuy+wYwQEDBD5ICp\nrLdlND8kfXbUc3CB1cJAF7KET063A3GWplYFzBHmCisVAPqLembfM7nQLrVRJbJG\nHnC+hq1TT7lVjHwPgdp275joa75rVgZiLR3IdQBWcXb1vIsTzzBgOVheZh7Dxk4I\nKpE4UQ8YomTaR/1eKNWpB/3TFwKBgQDe4WTuRhTvdVIsMNgew1jaFDUS7PHrQj6T\nBne5MHGAJOkJFkKa9Gw3kvzwMKIH9U0UgaZAS05XdLY85XxqEve+T9vT+1adA7pX\nh6sWKZLHHKBEkeTkxVaxWK5yzn9dJA11zsF5Xt5xQ6e+hLn69YpYcbealN/DJ367\nCvFj7B83wwKBgQChGR3D0Ndi+Ku9Jn+eU7ToKa91y4zBmAyaBCU8MgAF5CQIpsvu\nweT6DxWMyR2HpbtKCNThR5wvYuz1M5PkZNbmFiINNb4CpkVuhhuL5sSrTnuZPZUg\nfBAOYmIsqdCC1fW5tZXKPnUjpSaQx1iP98+6X7Qzh2uFo1VQy7Gnv1cHXQKBgEwe\nEghGKvQ0zyGEdOrcsEWaTR3vihdcgl5YAR9f6gNnl6ag0ZJ2E1dPfc7R7SRmpDJy\nrMKcdV7s3ygg/8KCQ9XdFChrWAM7uLIYBVgGTrhtkFaatN9kfd0Helx/JYQ7wdUQ\nDYdT3Qg1oN4yGgoZPWxDOf8zBNBzdpaOgC4t/+NdAoGAKG6sLkRIE5Ian8UbXUbC\nulkleeAzaI5l77oNh8ldcBFhyKPBeyjt1sAPApVPno8NGcKcQCXoBBG1UyGdk/MQ\n0yD8bnmEllPQbvi6zwV4vW+2SuDeT4nn2ofUj5VQzKqyfj+WOm5+Mzg47x/v4pEx\nNVhcWLtXVMQb8DpUKpgcPzQ=\n-----END PRIVATE KEY-----\n",
"client_email": "lsw-google-drive@lsw-website-484309.iam.gserviceaccount.com",
"client_id": "105782650926280820675",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/lsw-google-drive%40lsw-website-484309.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

View File

@ -13,6 +13,7 @@
"axios": "^1.13.2", "axios": "^1.13.2",
"cheerio": "^1.0.0-rc.12", "cheerio": "^1.0.0-rc.12",
"fetch-blob": "^4.0.0", "fetch-blob": "^4.0.0",
"googleapis": "^170.0.0",
"got": "^14.6.5", "got": "^14.6.5",
"node-fetch": "^2.7.0", "node-fetch": "^2.7.0",
"playwright": "^1.57.0" "playwright": "^1.57.0"

143
read-google-drive.js Normal file
View File

@ -0,0 +1,143 @@
const API_KEY = 'AIzaSyAobSJ6RDkfIj6oUNYhvRjygkAODzQocyg';
const DEFAULT_FOLDER_ID = '1Q6LJW_3YarYcUUvUPKqfH7DqPDuJ-8ra'; // รหัสที่อยู่หลัง /folders/ ใน URL
const UPLOAD_TO = 'https://web-lsw-dev.nueamek.app/api/upload-file';
const { google } = require('googleapis');
const fs = require('fs');
// 1. ระบุ path ของไฟล์ JSON ที่คุณโหลดมา
const KEYFILEPATH = 'lsw-website-484309-6a86a07bc9d5.json';
// 2. กำหนดสิทธิ์ (Scopes) - ในที่นี้คืออ่านไฟล์ใน Drive
const SCOPES = ['https://www.googleapis.com/auth/drive.readonly'];
// 3. สร้างตัวตน (Auth Client)
const auth = new google.auth.GoogleAuth({
keyFile: KEYFILEPATH,
scopes: SCOPES,
});
async function listFiles(deep = 0,folderId = undefined, folderName = '') {
// https://www.googleapis.com/drive/v3/files
const url = `https://www.googleapis.com/drive/v3/files?q='${folderId ?? DEFAULT_FOLDER_ID}'+in+parents&key=${API_KEY}`;
let files = []
try {
const response = await fetch(url);
const data = await response.json();
if (data.files && data.files.length > 0) {
let forTest = data.files
if(deep == 0){
forTest = data.files.slice(0, 1)
}
data.files.forEach(async file => {
// console.log(file);
console.log(`ชื่อไฟล์: ${file.name}, ID: ${file.id}`);
if(file.mimeType.includes('folder')){
const fileResultList = await listFiles(deep+1, file.id, file.name)
const onlyHaveUrlList = fileResultList.filter(fileResult => fileResult.url)
files.push(...onlyHaveUrlList)
}
else if(file.mimeType.includes('image/jpeg')){
const fileResult = await downloadAndUpload(file.id, file.name)
if(fileResult.url){
files.push(fileResult)
}
}
});
} else {
console.log('ไม่พบไฟล์ในโฟลเดอร์นี้');
}
} catch (error) {
console.error('เกิดข้อผิดพลาด:', error);
}
if(deep == 1 && folderName){
const payload = {
menuId: 402,
templateId: 2,
tag: 2,
title: folderName,
content: '',
startAt: "2026-01-14",
filedoc: null,
imageList: files,
}
}
return files
}
async function downloadAndUpload(fileId, fileName) {
try {
// #region วิธีที่ง่ายแต่ access มากไปจะโดน google block เพราะคิดว่าเป็น bot
// // 1. ดาวน์โหลดเนื้อหาไฟล์จาก Google Drive (ใช้ alt=media)
// const downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media&key=${API_KEY}`;
// const response = await fetch(downloadUrl);
// console.log('response', response)
// if (!response.ok) {
// // อ่านรายละเอียด Error จาก Google
// const errorText = await response.text();
// console.error("Error Detail:", errorText);
// throw new Error('Download failed');
// }
// const fileBlob = await response.blob();
// // 2. สร้าง FormData เพื่อเตรียมส่งไปยัง API ของคุณ
// const formData = new FormData();
// // 'file' คือชื่อ field ที่ API ของคุณรอรับ (เปลี่ยนได้ตามความเหมาะสม)
// formData.append('file', fileBlob, fileName);
// #endregion
// #region Service Account
const drive = google.drive({ version: 'v3', auth });
// 1. การดึงเนื้อหาไฟล์ (Media)
const res = await drive.files.get(
{ fileId: fileId, alt: 'media' },
// { responseType: 'stream' }
{ responseType: 'arraybuffer' }
);
// คุณสามารถส่ง res.data นี้เข้า FormData เพื่อส่งต่อไปยัง API ของคุณได้เลย
// 2. สร้าง FormData เพื่อเตรียมส่งไปยัง API ของคุณ
// แปลง ArrayBuffer ที่ได้เป็น Blob
const fileBlob = new Blob([res.data]);
const formData = new FormData();
formData.append('file', fileBlob, fileName);
// #endregion
// 3. ส่งข้อมูลไปยัง API ของคุณด้วย POST method
const uploadResponse = await fetch(UPLOAD_TO, {
method: 'POST',
body: formData
});
const result = await uploadResponse.json();
// console.log(`อัปโหลดไฟล์ ${fileName} สำเร็จ:`, result);
return result
} catch (error) {
console.error(`เกิดข้อผิดพลาดกับไฟล์ ${fileName}:`, error);
return {
error: error
}
}
}
// // ตัวอย่างการใช้งานร่วมกับรายชื่อไฟล์ที่ได้จากข้อก่อนหน้า
// async function processAllFiles(files) {
// for (const file of files) {
// // กรองเอาเฉพาะไฟล์ .js (ถ้าจำเป็น)
// if (file.name.endsWith('.js')) {
// await downloadAndUpload(file.id, file.name);
// }
// }
// }
// downloadAndUpload('14SGY4irPJ1FwUA5472zlyYtzHvDNaCQ4', 'test')
listFiles();

View File

@ -0,0 +1,242 @@
// หน้าแรก > งานบริการ > แนะนำสถานที่ท่องเที่ยว
const { execSync } = require("child_process");
const cheerio = require("cheerio");
const fs = require("fs");
const path = require("path");
const BASE = "https://ladsawai.go.th";
const OUT = path.join(process.cwd(), "แนะนำสถานที่ท่องเที่ยว");
fs.mkdirSync(OUT, { recursive: true });
function curlHtml(url) {
return execSync(
`curl -L -s "${url}" -H "User-Agent: Mozilla/5.0" -H "Accept-Language: th-TH,th;q=0.9"`,
{ encoding: "utf8", maxBuffer: 20 * 1024 * 1024 }
);
}
function absUrl(src) {
if (!src) return null;
if (src.startsWith("http")) return src;
return BASE + src;
}
function scrapeDetailImagesContent(detailUrl) {
const html = curlHtml(detailUrl);
const $ = cheerio.load(html);
// ---------- images ----------
const imgSet = new Set();
$(".maingroup.gallery a[href]").each((_, a) => {
const href = ($(a).attr("href") || "").trim();
const full = absUrl(href);
if (full) imgSet.add(full);
});
if (imgSet.size === 0) {
$("a[href]").each((_, a) => {
const href = ($(a).attr("href") || "").trim();
const full = absUrl(href);
if (full && /\.(jpg|jpeg|png|webp|gif)(\?|$)/i.test(full)) imgSet.add(full);
});
}
// ---------- content ----------
// ✅ เลือกกล่องที่ไม่ใช่ gallery และ "มีข้อความจริง"
const candidates = $(".col-12.maingroup").not(".gallery");
let bestBox = null;
let bestScore = -1;
candidates.each((_, el) => {
const $el = $(el);
// เอา text โดยตัดของไม่เกี่ยว (emoji img, script, style)
const text = $el
.clone()
.find("img, script, style")
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
const pCount = $el.find("p").length;
const score = (text ? text.length : 0) + pCount * 50; // ให้ p มีน้ำหนักเพิ่ม
if (score > bestScore) {
bestScore = score;
bestBox = $el;
}
});
let content = "";
if (bestBox && bestBox.length) {
const lines = [];
bestBox.find("p").each((_, p) => {
const t = $(p)
.clone()
.find("img") // ตัดรูป emoji ใน p
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
if (t) lines.push(t);
});
content = lines.length
? lines.join("\n")
: bestBox
.clone()
.find("img, script, style")
.remove()
.end()
.text()
.replace(/\s+/g, " ")
.trim();
}
let mainImageUrl = ''
try{
const mainImageDiv = $(".imagestopic img[src]");
const src = ($(mainImageDiv).attr("src") || "").trim();
const full = absUrl(src);
if (full) mainImageUrl = full;
}
catch(error){
mainImageUrl = ''
}
return { imgs: [...imgSet], text: content, mainImage: mainImageUrl };
}
function scrapeOnePage(menuId, page, saveHtml = false) {
const url = `${BASE}/public/list/data/index/menu/${menuId}/page/${page}`;
const html = curlHtml(url);
if (saveHtml) {
fs.writeFileSync(path.join(OUT, `page-menu-${menuId}-page-${page}.html`), html, "utf8");
}
const $ = cheerio.load(html);
const items = [];
$(".row.data-row").each((_, row) => {
const el = $(row);
const title = el
.find(".col-12.col-sm-10")
.text()
.replace(/\s+/g, " ")
.trim();
const detailRef = el
.find("a.listdataconfig_link ") // a.listdataconfig_link
.attr("href")
.trim();
const date = el.find(".col-sm-2").last().text().trim();
const imgSrc = el.find("img").attr("src");
if (!title) return;
const linkD = `https://ladsawai.go.th` + detailRef
const { text, imgs, mainImage } = linkD ? scrapeDetailImagesContent(linkD) : [];
let detailHtmlPath = ''
if (saveHtml) {
try {
// Extract id and menu from URL: /public/list/data/detail/id/{id}/menu/{menu}/page/{page}
const urlMatch = linkD.match(/\/id\/(\d+)\/menu\/(\d+)/);
const id = urlMatch ? urlMatch[1] : null;
// const menu = urlMatch ? urlMatch[2] : null;
const detailPageHtml = curlHtml(linkD);
detailHtmlPath = `debug-menu-${menuId}-detail-${id}.html`
fs.writeFileSync(
path.join(OUT, detailHtmlPath),
detailPageHtml,
"utf8"
);
} catch (error) {
console.error('error :', error)
detailHtmlPath = ''
}
}
items.push({
title,
detailRef: linkD,
detail:{
img: imgs,
content: text,
mainImage: mainImage
},
date: date || null,
image: absUrl(imgSrc),
detailPageHtml: detailHtmlPath ?? undefined, // ไฟล์จากหน้า detail
sourcePage: page,
sourceUrl: url,
});
});
const output = {
source: url,
scrapedAt: new Date().toISOString(),
menuId,
page,
count: items.length,
items,
};
const outJson = path.join(OUT, `list-menu-${menuId}-page-${page}.json`);
fs.writeFileSync(outJson, JSON.stringify(output, null, 2), "utf8");
console.log(`✅ page ${page} -> items ${items.length}`);
return items;
}
(function main() {
const menuId = 1545;
const totalPages = 1;
const all = [];
const seen = new Set();
// ถ้าไม่อยากให้มี HTML 53 ไฟล์ ให้เป็น false
const saveHtml = true;
for (let page = 1; page <= totalPages; page++) {
const items = scrapeOnePage(menuId, page, saveHtml);
// รวม + กันซ้ำ
for (const it of items) {
const key = `${it.title}|${it.date || ""}|${it.image || ""}`;
if (seen.has(key)) continue;
seen.add(key);
all.push(it);
}
}
const merged = {
menuId,
totalPages,
scrapedAt: new Date().toISOString(),
totalItems: all.length,
items: all,
};
const outAll = path.join(OUT, `list-menu-${menuId}-all.json`);
fs.writeFileSync(outAll, JSON.stringify(merged, null, 2), "utf8");
console.log("✅ Saved merged JSON:", outAll);
console.log("✅ Total unique items:", all.length);
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,59 @@
{
"menuId": 1545,
"totalPages": 1,
"scrapedAt": "2026-01-14T07:29:52.933Z",
"totalItems": 3,
"items": [
{
"title": "ตลาดกลางลาดสวาย",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1396/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_3456_1.jpg?820",
"https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_3456_2.jpg?454"
],
"content": "ตลาดกลางลาดสวาย ตั้งอยู่เลขที่ 52/39 หมู่ 5 ตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี เป็นตลาดขนาดใหญ่ บนพื้นที่กว่า 30,000 ตารางเมตร ตั้งอยู่บนถนน ลำลูกกา คลองสี่ (ซอยสวนเกษตร) เปิดให้บริการลูกค้าหลากหลายโซน โดยจัดแบ่งออกเป็นโซนต่าง ๆ ได้แก่ โซนตลาดสด โซนโต้รุ่ง โซนพลาซ่า โซนศูนย์อาหาร โซนตลาดนัด ห้องเช่าสำหรับธุรกิจขนาดใหญ่ อยู่ภายใต้หลังคาขนาดใหญ่ ซึ่งครอบคลุมพื้นที่การค้าทั้งหมด และมีพื้นที่จอดรดกว่า 500 คัน อยู่โดยรอบโครงการ เปิดจำหน่ายสินค้าและบริการต่าง ๆ ทุกวัน ตั้งแต่เวลา 06.00-22.00 น.",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_topic_1396.jpg?105"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_topic_1396_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1396.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
},
{
"title": "วัดคลองชัน",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1395/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_3453_1.jpg?9",
"https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_3453_2.jpg?841"
],
"content": "วัดคลองชัน เป็นวัดราษฎร์สังกัดคณะสงฆ์ฝ่ายมหานิกาย ตั้งอยู่ในตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี มีเนื้อที่วัด 14 ไร่ 1 งาน 12 ตารางวา พื้นที่วัดเป็นที่ราบลุ่มอยู่ริมคลองหกวาสายล่าง มีถนนสายลำลูกกาผ่านทางทิศเหนือ\nวัดคลองชันสร้างเมื่อ พ.ศ. 2440 ไม่พบหลักฐานว่าใครเป็นผู้สร้าง เดิมชื่อ วัดสาลีราษฏร์บำรุง ต่อมาเปลี่ยนเป็น วัดปากคลองชัน ตามสภาพที่ตั้งของวัดในขณะนั้น ต่อมาคำว่า \"ปาก\" หายไปเมื่อใดไม่ทราบ ได้เรียกสั้น ๆ ว่า \"วัดคลองชัน\" และได้ใช้นามนี้มาจนปัจจุบัน วัดได้รับพระราชทานวิสุงคามสีมา เมื่อวันที่ 14 พฤษภาคม พ.ศ. 2449 ทางวัดยังเปิดการเรียนการสอนพระปริยัติธรรมตั้งแต่ พ.ศ. 2452 รวมถึงให้ทางราชการสร้างโรงเรียนประชาบาลสอนระดับประถมศึกษาในที่ดินของวัดอีกด้วย\nอาคารเสนาสนะ ได้แก่ อุโบสถสร้าง เมื่อ พ.ศ. 2453 กุฏิสงฆ์ ศาลาการเปรียญ วิหาร หอสวดมนต์ หอระฆัง หอกลาง ด้านปูชนียวัตถุสำคัญ คือ พระประธานในอุโบสถ หน้าตักกว้าง 49 นิ้ว เป็นพระพุทธสิหิงค์จำลอง รูปหล่อหมอชีวกโกมารภัจจ์ 1 องค์ รูปเหมือนอดีตเจ้าอาวาส เจดีย์ประดิษฐานรอยพระพุทธบาทจำลอง มีพระสงฆ์ที่มรณภาพแล้วร่างไม่สลายไปตามธรรมชาติ 1 รูป และวิหารหลวงพ่อโสธรจำลอง",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_topic_1395.jpg?257"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_topic_1395_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1395.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
},
{
"title": "วัดกลางคลองสื่",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1394/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_3450_1.jpg?598",
"https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_3450_2.jpg?228"
],
"content": "วัดกลางคลองสี่ เดิมมีนามว่า วัดใหม่กลางคลองสี่ ตั้งอยู่ที่หมู่ที่ 5 บ้านคลองสี่ ตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี สร้างขึ้นในปี พ.ศ. 2453 โดยชาวไทยเชื้อสายมอญ ทีอพยพมาจากเมืองมะละแม่งสมัยพระเจ้ากรุงธนบุรีและมาตั้งถิ่นฐานที่บ้านบางตลาดปากเกร็ด นนทบุรี ต่อมาเมื่อมีการพัฒนาทุ่งรังสิตเมืองธัญบุรี ชาวมอญบางส่วนย้ายถิ่นฐานมาทำมาหากินทำนาในที่แห่งนี้ และสร้างวัดนี้ขึ้น หลังจากนั้นชาวบ้านได้อาราธนาพระภิกษุจากวัดสายไหมมาจำพรรษา และได้นิมนต์พระอาจารย์ด๊วด ญาณวโร (พระครูวิเศษธัญญโศภิต) จากวัดสนามเหนือ อำเภอปากเกร็ด จังหวัดนนทบุรีมาเป็นเจ้าอาวาสวัด หลวงปู่ด๊วด ญาณวโร เป็นพระภิกษุสงฆ์ที่เป็นครูบาอาจารย์ที่ชาวปทุมธานีเคารพนับถือไม่เคยเสื่อมคลาย ท่านได้สนับสนุนการศึกษาด้วยดีมาตลอด ได้เปิดโรงเรียนพระปริยัติธรรมและโรงเรียนประชาบาลขึ้นเป็นแห่งแรกในอำเภอลำลูกกา เมื่อสิ้นหลวงปู่ด๊วด ญาณวโร พระอาจารย์ทองอินทร์ เตชวุฑโฒ (พระมงคลศีลาจารย์) ได้ดำเนินการก่อสร้างบูรณะซ่อมแซมวัดได้เจริญอย่างมากในทุก ๆ ด้าน ทั้งได้สนับสนุนทุนการศึกษา ให้แก่โรงเรียนวัดกลางคลองสี่ตลอด ท่านเป็นพระเถรานุเถระที่มีอายุและพรรษากาลมากถึง 96 ปี ที่เป็นที่เคารพของชาวบ้านและคณะสงฆ์ในจังหวัดปทุมธานี วัดแห่งนี้ได้รับพระราชทานวิสุงคามสีมาเมื่อวันที่ 21 กุมภาพันธ์ พ.ศ. 2467 และผูกพันธสีมาเมื่อวันที่ 27 กุมภาพันธ์ พ.ศ. 2526 เดิมวัดแห่งนี้มีนามว่า \"วัดใหม่กลางคลองสี่\" แต่ได้เป็นนามเป็น \"วัดกลางคลองสี่\" เมื่อปี พ.ศ. 2480",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_topic_1394.jpg?799"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_topic_1394_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1394.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
}
]
}

View File

@ -0,0 +1,60 @@
{
"source": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1",
"scrapedAt": "2026-01-14T07:29:52.926Z",
"menuId": 1545,
"page": 1,
"count": 3,
"items": [
{
"title": "ตลาดกลางลาดสวาย",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1396/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_3456_1.jpg?820",
"https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_3456_2.jpg?454"
],
"content": "ตลาดกลางลาดสวาย ตั้งอยู่เลขที่ 52/39 หมู่ 5 ตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี เป็นตลาดขนาดใหญ่ บนพื้นที่กว่า 30,000 ตารางเมตร ตั้งอยู่บนถนน ลำลูกกา คลองสี่ (ซอยสวนเกษตร) เปิดให้บริการลูกค้าหลากหลายโซน โดยจัดแบ่งออกเป็นโซนต่าง ๆ ได้แก่ โซนตลาดสด โซนโต้รุ่ง โซนพลาซ่า โซนศูนย์อาหาร โซนตลาดนัด ห้องเช่าสำหรับธุรกิจขนาดใหญ่ อยู่ภายใต้หลังคาขนาดใหญ่ ซึ่งครอบคลุมพื้นที่การค้าทั้งหมด และมีพื้นที่จอดรดกว่า 500 คัน อยู่โดยรอบโครงการ เปิดจำหน่ายสินค้าและบริการต่าง ๆ ทุกวัน ตั้งแต่เวลา 06.00-22.00 น.",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_topic_1396.jpg?105"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1396/pics_topic_1396_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1396.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
},
{
"title": "วัดคลองชัน",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1395/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_3453_1.jpg?9",
"https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_3453_2.jpg?841"
],
"content": "วัดคลองชัน เป็นวัดราษฎร์สังกัดคณะสงฆ์ฝ่ายมหานิกาย ตั้งอยู่ในตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี มีเนื้อที่วัด 14 ไร่ 1 งาน 12 ตารางวา พื้นที่วัดเป็นที่ราบลุ่มอยู่ริมคลองหกวาสายล่าง มีถนนสายลำลูกกาผ่านทางทิศเหนือ\nวัดคลองชันสร้างเมื่อ พ.ศ. 2440 ไม่พบหลักฐานว่าใครเป็นผู้สร้าง เดิมชื่อ วัดสาลีราษฏร์บำรุง ต่อมาเปลี่ยนเป็น วัดปากคลองชัน ตามสภาพที่ตั้งของวัดในขณะนั้น ต่อมาคำว่า \"ปาก\" หายไปเมื่อใดไม่ทราบ ได้เรียกสั้น ๆ ว่า \"วัดคลองชัน\" และได้ใช้นามนี้มาจนปัจจุบัน วัดได้รับพระราชทานวิสุงคามสีมา เมื่อวันที่ 14 พฤษภาคม พ.ศ. 2449 ทางวัดยังเปิดการเรียนการสอนพระปริยัติธรรมตั้งแต่ พ.ศ. 2452 รวมถึงให้ทางราชการสร้างโรงเรียนประชาบาลสอนระดับประถมศึกษาในที่ดินของวัดอีกด้วย\nอาคารเสนาสนะ ได้แก่ อุโบสถสร้าง เมื่อ พ.ศ. 2453 กุฏิสงฆ์ ศาลาการเปรียญ วิหาร หอสวดมนต์ หอระฆัง หอกลาง ด้านปูชนียวัตถุสำคัญ คือ พระประธานในอุโบสถ หน้าตักกว้าง 49 นิ้ว เป็นพระพุทธสิหิงค์จำลอง รูปหล่อหมอชีวกโกมารภัจจ์ 1 องค์ รูปเหมือนอดีตเจ้าอาวาส เจดีย์ประดิษฐานรอยพระพุทธบาทจำลอง มีพระสงฆ์ที่มรณภาพแล้วร่างไม่สลายไปตามธรรมชาติ 1 รูป และวิหารหลวงพ่อโสธรจำลอง",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_topic_1395.jpg?257"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1395/pics_topic_1395_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1395.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
},
{
"title": "วัดกลางคลองสื่",
"detailRef": "https://ladsawai.go.th/public/list/data/detail/id/1394/menu/1545/page/1",
"detail": {
"img": [
"https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_3450_1.jpg?598",
"https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_3450_2.jpg?228"
],
"content": "วัดกลางคลองสี่ เดิมมีนามว่า วัดใหม่กลางคลองสี่ ตั้งอยู่ที่หมู่ที่ 5 บ้านคลองสี่ ตำบลลาดสวาย อำเภอลำลูกกา จังหวัดปทุมธานี สร้างขึ้นในปี พ.ศ. 2453 โดยชาวไทยเชื้อสายมอญ ทีอพยพมาจากเมืองมะละแม่งสมัยพระเจ้ากรุงธนบุรีและมาตั้งถิ่นฐานที่บ้านบางตลาดปากเกร็ด นนทบุรี ต่อมาเมื่อมีการพัฒนาทุ่งรังสิตเมืองธัญบุรี ชาวมอญบางส่วนย้ายถิ่นฐานมาทำมาหากินทำนาในที่แห่งนี้ และสร้างวัดนี้ขึ้น หลังจากนั้นชาวบ้านได้อาราธนาพระภิกษุจากวัดสายไหมมาจำพรรษา และได้นิมนต์พระอาจารย์ด๊วด ญาณวโร (พระครูวิเศษธัญญโศภิต) จากวัดสนามเหนือ อำเภอปากเกร็ด จังหวัดนนทบุรีมาเป็นเจ้าอาวาสวัด หลวงปู่ด๊วด ญาณวโร เป็นพระภิกษุสงฆ์ที่เป็นครูบาอาจารย์ที่ชาวปทุมธานีเคารพนับถือไม่เคยเสื่อมคลาย ท่านได้สนับสนุนการศึกษาด้วยดีมาตลอด ได้เปิดโรงเรียนพระปริยัติธรรมและโรงเรียนประชาบาลขึ้นเป็นแห่งแรกในอำเภอลำลูกกา เมื่อสิ้นหลวงปู่ด๊วด ญาณวโร พระอาจารย์ทองอินทร์ เตชวุฑโฒ (พระมงคลศีลาจารย์) ได้ดำเนินการก่อสร้างบูรณะซ่อมแซมวัดได้เจริญอย่างมากในทุก ๆ ด้าน ทั้งได้สนับสนุนทุนการศึกษา ให้แก่โรงเรียนวัดกลางคลองสี่ตลอด ท่านเป็นพระเถรานุเถระที่มีอายุและพรรษากาลมากถึง 96 ปี ที่เป็นที่เคารพของชาวบ้านและคณะสงฆ์ในจังหวัดปทุมธานี วัดแห่งนี้ได้รับพระราชทานวิสุงคามสีมาเมื่อวันที่ 21 กุมภาพันธ์ พ.ศ. 2467 และผูกพันธสีมาเมื่อวันที่ 27 กุมภาพันธ์ พ.ศ. 2526 เดิมวัดแห่งนี้มีนามว่า \"วัดใหม่กลางคลองสี่\" แต่ได้เป็นนามเป็น \"วัดกลางคลองสี่\" เมื่อปี พ.ศ. 2480",
"mainImage": "https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_topic_1394.jpg?799"
},
"date": null,
"image": "https://ladsawai.go.th/public/list_upload/backend/list_1394/pics_topic_1394_thumbnail.jpg",
"detailPageHtml": "debug-menu-1545-detail-1394.html",
"sourcePage": 1,
"sourceUrl": "https://ladsawai.go.th/public/list/data/index/menu/1545/page/1"
}
]
}

File diff suppressed because one or more lines are too long