chore: update search scripts, extra sources and post drafts
Adds the one-off scripts accumulated across recent sessions, removes temp scripts whose searches now live in config.ts as role-family sweeps, and updates fetch-other.ts plus the LinkedIn post drafts.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env bun
|
||||
import type { SearchConfig } from "../config.ts";
|
||||
import { fetchJobs, isEnglishContent, JUNIOR_TITLE_RE, JAVA_TITLE_RE } from "../fetch.ts";
|
||||
|
||||
const CSV = "./results/jobs.csv";
|
||||
|
||||
// Titles the engineer-centric KEYWORDS list never searches for.
|
||||
const BROAD_KEYWORDS = [
|
||||
"Implementation Manager",
|
||||
"Implementation Consultant",
|
||||
"Implementation Specialist",
|
||||
"Solutions Consultant",
|
||||
"Solution Architect",
|
||||
"Technical Consultant",
|
||||
"Technical Account Manager",
|
||||
"Technical Program Manager",
|
||||
"Technical Project Manager",
|
||||
"Delivery Manager",
|
||||
"Integration Engineer",
|
||||
"Integration Specialist",
|
||||
"Customer Success Engineer",
|
||||
"Sales Engineer",
|
||||
"Presales Engineer",
|
||||
"Digital Transformation",
|
||||
"Product Owner",
|
||||
"Scientific Software",
|
||||
"Research Software",
|
||||
"Automation Engineer",
|
||||
"Systems Integration",
|
||||
].join(" OR ");
|
||||
|
||||
// Microsoft stack = hard no (see cv/polo.md).
|
||||
const MICROSOFT_RE = /\b(\.net|dotnet|c#|azure|sharepoint|dynamics|power\s*(platform|bi|apps|automate)|sccm|intune|windows\s*server|m365|office\s*365|uipath)\b/i;
|
||||
const SAP_RE = /\bsap\b|\bs\/4hana\b|\bsalesforce\b|\bservicenow\b/i;
|
||||
|
||||
const AREAS: SearchConfig[] = [
|
||||
{ label: "Basel (city)", keywords: BROAD_KEYWORDS, geoId: "103383283", location: "Basel", workType: ["onsite", "hybrid"], timePosted: "week" },
|
||||
{ label: "Basel Metropolitan Area", keywords: BROAD_KEYWORDS, geoId: "90009885", location: "Basel Metropolitan Area", workType: ["onsite", "hybrid"], timePosted: "week" },
|
||||
{ label: "Basel-Country", keywords: BROAD_KEYWORDS, geoId: "107117530", location: "Basel-Country", workType: ["onsite", "hybrid"], timePosted: "week" },
|
||||
];
|
||||
|
||||
const existingIds = new Set<string>();
|
||||
try {
|
||||
const text = await Bun.file(CSV).text();
|
||||
for (const line of text.split("\n").slice(1)) {
|
||||
const id = line.match(/\/jobs\/view\/(\d+)\//)?.[1];
|
||||
if (id) existingIds.add(id);
|
||||
}
|
||||
} catch { /* first run */ }
|
||||
|
||||
type Row = { id: string; title: string; company: string; location: string; link: string; posted: string; isNew: boolean };
|
||||
const seen = new Set<string>();
|
||||
const rows: Row[] = [];
|
||||
|
||||
for (const config of AREAS) {
|
||||
// raw: true — bypass SOFTWARE_TITLE_RE so non-engineer titles survive
|
||||
const jobs = await fetchJobs(config, { raw: true });
|
||||
console.error(`[${config.label}] ${jobs.length} jobs`);
|
||||
for (const job of jobs) {
|
||||
if (seen.has(job.id)) continue;
|
||||
seen.add(job.id);
|
||||
const t = job.title;
|
||||
if (JUNIOR_TITLE_RE.test(t)) { console.error(` junior: ${t}`); continue; }
|
||||
if (JAVA_TITLE_RE.test(t)) { console.error(` java: ${t}`); continue; }
|
||||
if (MICROSOFT_RE.test(t)) { console.error(` MS stack: ${t}`); continue; }
|
||||
if (SAP_RE.test(t)) { console.error(` SAP/SF/SNOW: ${t}`); continue; }
|
||||
rows.push({
|
||||
id: job.id, title: t, company: job.company,
|
||||
location: (job as any).location ?? "", link: job.link,
|
||||
posted: (job as any).postedAt ?? "", isNew: !existingIds.has(job.id),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const survivors: Row[] = [];
|
||||
for (const r of rows) {
|
||||
if (await isEnglishContent(r.id)) survivors.push(r);
|
||||
else console.error(` DE/FR content dropped: ${r.title} — ${r.company}`);
|
||||
}
|
||||
|
||||
console.error(`\n${survivors.length} survivors (${survivors.filter((r) => r.isNew).length} not in CSV)`);
|
||||
console.log(JSON.stringify(survivors, null, 2));
|
||||
Reference in New Issue
Block a user