CSC portal Playwright scraper + import 16 open government IT vacancies

This commit is contained in:
Jonathan Sykes
2026-08-16 20:56:01 +08:00
parent bcbecbb49a
commit 0cdfc4806c
5 changed files with 102 additions and 0 deletions

49
scripts/add-csc-jobs.ts Normal file
View File

@@ -0,0 +1,49 @@
/** Add still-open CSC portal listings (scraped 2026-08-16) to the tracker. */
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const CSC = "https://csc.gov.ph/career/";
const common = {
source: "csc.gov.ph", url: CSC, remoteType: "onsite", phEligibility: "yes",
payCurrency: "PHP", payPeriod: "month", status: "prospect",
};
// posting: [title, agency, region, itemNo, closing, notes]
const rows: [string, string, string, string, string, string][] = [
["Computer Programmer II (2 items) + III", "Department of Finance", "NCR", "OSEC-DOFB-COMPRO2-1-1998 / COMPRO2-11-2000 / COMPRO3-8-2000", "2026-08-26", "CP II ≈ SG-15, CP III ≈ SG-18"],
["Information Systems Analyst II + III (3 items)", "Department of Finance", "NCR", "OSEC-DOFB-INFOSA2-5-2000 / INFOSA3-3-2000 / INFOSA3-4-2000", "2026-08-26", "ISA II ≈ SG-16, ISA III ≈ SG-19. Same DOF batch as the CP items — one application effort covers both."],
["Legislative Staff Officer III (Computer Programmer IV)", "House of Representatives", "NCR", "501-001 (HRB-LSO3-66-2000)", "2026-08-21", "Senior programmer item in Congress"],
["Information Systems Analyst III", "Bureau of Soils and Water Management (DA)", "NCR", "OSEC-DAB-INFOSA3-8-1998", "2026-08-26", "ISA III ≈ SG-19"],
["Information Technology Officer II", "Department of Economy, Planning, and Development", "NCR", "ITO2-33-2014", "2026-08-23", "ITO II ≈ SG-22 — highest-paying of the open NCR items"],
["Information Systems Analyst II", "Philippine Reclamation Authority", "NCR", "51", "2026-08-19", "GOCC — may have own salary structure"],
["Computer Programmer III + II", "City Government of Angeles", "Region III", "72 / 73", "2026-08-20", "Pampanga"],
["Computer Programmer III", "Provincial Government of Bohol", "Region VII", "132", "2026-08-20", "Also hiring ITO I (149-2026-01, same deadline)"],
["Computer Programmer III", "MGO Pili (Capital), Camarines Sur", "Region V", "03-01-001-15", "2026-08-25", ""],
["Computer Programmer I", "MGO Polangui, Albay", "Region V", "20", "2026-08-27", "Entry level, CP I ≈ SG-11"],
["Computer Programmer II + III", "Provincial Government of Basilan", "BARMM", "4 / 11", "2026-08-27", ""],
["Computer Programmer I (2 items)", "Provincial Government of Davao del Sur", "Region XI", "1069 / 213", "2026-08-20", ""],
["Information Systems Analyst I", "West Visayas State University", "Region VI", "WVSUB-INFOSA1-45-2023", "2026-08-23", "SUC"],
["Information Systems Analyst II", "Provincial Government of Guimaras", "Region VI", "935", "2026-08-30", "Longest-open deadline of the batch"],
["Information Systems Analyst I", "Provincial Government of Siquijor", "Region VII", "PHO-52-54", "2026-08-21", ""],
["Information Technology Officer I", "MGO Plaridel, Bulacan", "Region III", "19", "2026-08-26", "Near NCR"],
];
async function main() {
for (const [title, agency, region, item, closing, extra] of rows) {
const exists = await prisma.job.findFirst({ where: { title, company: agency } });
if (exists) { console.log("skip:", agency, title); continue; }
await prisma.job.create({
data: {
...common,
title, company: agency,
location: region + ", Philippines",
description: `CSC Job Portal listing. Plantilla item: ${item}. Closing date: ${closing}. ${extra}`,
requirements: "Per CSC qualification standards for the position (education, eligibility, training, experience). See the posting's Details on the CSC portal; apply directly to the agency, not the CSC.",
tags: "government,csc-portal,onsite" + (region === "NCR" ? ",NCR" : ""),
notes: `Deadline ${closing}. Scraped from csc.gov.ph/career 2026-08-16 (filter Position: programmer/analyst/ITO). Applications go to the agency's HR, usually with CS Form 212, eligibility proof, transcripts.`,
},
});
console.log("added:", agency, "—", title);
}
}
main().finally(() => prisma.$disconnect());

20
scripts/csc-scrape.ts Normal file
View File

@@ -0,0 +1,20 @@
import { chromium } from "playwright";
async function main() {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
viewport: { width: 1366, height: 900 },
});
const page = await ctx.newPage();
const resp = await page.goto("https://csc.gov.ph/career/", { waitUntil: "domcontentloaded", timeout: 60000 });
console.log("status:", resp?.status());
await page.waitForTimeout(8000); // let any JS/Cloudflare settle
console.log("title:", await page.title());
const text = (await page.innerText("body").catch(() => "")).slice(0, 1500);
console.log("---body preview---");
console.log(text);
await page.screenshot({ path: "/tmp/claude-1000/-home-josh-development-personal-tasks/c55d38eb-c0a2-4a78-b5c5-78f6d6ca1fa6/scratchpad/csc.png", fullPage: false });
await browser.close();
}
main().catch((e) => { console.error(e); process.exit(1); });

BIN
scripts/csc-search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

33
scripts/csc-search.ts Normal file
View File

@@ -0,0 +1,33 @@
/** Search the CSC job portal for a position keyword. Usage: npx tsx scripts/csc-search.ts "Computer Programmer" */
import { chromium } from "playwright";
async function main() {
const keyword = process.argv[2] ?? "Computer Programmer";
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
viewport: { width: 1366, height: 900 },
});
const page = await ctx.newPage();
await page.goto("https://csc.gov.ph/career/", { waitUntil: "domcontentloaded", timeout: 60000 });
await page.waitForTimeout(4000);
await page.fill("#col2_filter", keyword);
await page.click('button[name="sort_list"]', { noWaitAfter: true });
await page.waitForLoadState("domcontentloaded");
await page.waitForTimeout(6000);
// Show up to 100 rows if a length selector exists.
const len = page.locator('select[name="jobs_length"]');
if (await len.count()) {
await len.selectOption("100").catch(() => {});
await page.waitForTimeout(3000);
}
const rows = await page.locator("table tbody tr").allInnerTexts();
console.log(`rows: ${rows.length}`);
for (const r of rows.slice(0, 60)) console.log("• " + r.replace(/\s*\n\s*/g, " | ").slice(0, 300));
await page.screenshot({ path: "scripts/csc-search.png", fullPage: true });
await browser.close();
}
main().catch((e) => { console.error(e); process.exit(1); });