A static site listing on-duty ("nöbetçi") pharmacies in Turkish provinces, built with Astro. Pharmacy data is scraped daily from official provincial chamber of pharmacists pages into static JSON, so the deployed site needs no backend.
The scraping approach (selectors, parsing logic) is ported from the earlier
Gleam implementation on this repository's main branch, a scraper for the same
Antalya source page using headless Chrome. This version uses a plain fetch +
cheerio instead, since the source pages turned out
to be server-rendered and don't require JS execution.
src/
data/ scraped CityData JSON, one file per city (e.g. antalya.json)
lib/
cities.ts registry of known cities (slug, name, source URL)
types.ts Pharmacy / CityData contract shared with the UI
pages/ Astro pages (UI is owned separately from the scraper)
scripts/
scrape.ts scraper entrypoint, run per city
| Command | Action |
|---|---|
npm install |
Install dependencies |
npm run scrape -- <slug> |
Scrape a city (e.g. npm run scrape -- antalya) and write src/data/<slug>.json |
npm run dev |
Start local dev server |
npm run build |
Build the static site to ./dist/ |
npm run preview |
Preview the production build locally |
There are two deploy workflows, both deploying dist/ to Cloudflare Pages
(project eczane) via wrangler:
-
.github/workflows/deploy.ymlruns on push tomainand onworkflow_dispatch. It builds and deploys only — it does not run the scraper, so the site builds from whatever JSON is currently committed insrc/data/. -
.github/workflows/update-data.ymlruns daily (and onworkflow_dispatch). It scrapes fresh data into the working tree, builds, and deploys — all without committing. The daily refresh therefore produces no commits onmain; thesrc/data/*.jsonfiles committed to the repo act only as a build-time baseline.
Both workflows use the same CLOUDFLARE_API_TOKEN secret and CLOUDFLARE_ACCOUNT_ID repository variable. To update the committed baseline (e.g. after adding a city), run
npm run scrape -- <slug> locally and commit the resulting file under
src/data/.
- Add an entry to
src/lib/cities.tswith aslug, displayname, and the province's on-duty pharmacy source URL. - Inspect the source page's HTML and adjust the selectors in
scripts/scrape.tsif the markup differs from Antalya's (.ilce,.ilcebas,.nobetciDivstructure). - Run
npm run scrape -- <slug>and verifysrc/data/<slug>.jsonlooks correct (plausible pharmacy count, mostly non-null coordinates). - If you want the daily CI refresh to cover the new city, add a corresponding
npm run scrape -- <slug>line to.github/workflows/update-data.yml.