add pictures

This commit is contained in:
2026-10-17 18:32:59 +02:00
parent c5f963f08f
commit aa0bc4e960
10 changed files with 1273 additions and 64 deletions
+48 -8
View File
@@ -13,6 +13,8 @@ das komplette serverjonas search
- `fix_pages_search_vector_trigger.sql` – einmalig laufen lassen: kappelt den Text,
der im DB-Trigger `pages_search_vector_update()` in `to_tsvector()` einfließt
(Postgres hartes Limit: 1.048.575 Bytes pro `tsvector`)
- `add_pages_pictures.sql` – einmalig laufen lassen: legt `pages.pictures`
(`text[]`) für die Bild-URLs der gecrawlten Seiten an (idempotent)
## Sehr große Seiten / tsvector-Limit
@@ -47,14 +49,22 @@ Fetch übersprungen und als `done` markiert.
Der Crawler wartet nie auf einer langsamen oder blockierten Domain:
1. **Claim mit Host-Check:** Beim Holen des nächsten Queue-Eintrags prüft der
Worker pro Kandidat (Prioritätsreihenfolge, bis zu
`JONASSEARCH_CLAIM_SCAN_LIMIT` Kandidaten), ob der Host gerade crawlbar ist
(Per-Host-Delay aus robots.txt bzw. `JONASSEARCH_DELAY`, aktive
Backoff-Sperre). Nicht crawlbare Hosts werden übersprungen – der Worker
arbeitet automatisch auf einer anderen Domain weiter und kehrt zurück,
sobald der Host wieder darf. Ist gerade gar kein Host crawlbar, schläft
der Worker bis zum frühesten freigegebenen Host (gekappet bei
`JONASSEARCH_MAX_IDLE_SLEEP`, dann wird neu gescannt).
Worker, ob der Host gerade crawlbar ist (Per-Host-Delay aus robots.txt bzw.
`JONASSEARCH_DELAY`, aktive Backoff-Sperre). Nicht crawlbare Hosts werden
übersprungen – der Worker arbeitet automatisch auf einer anderen Domain
weiter und kehrt zurück, sobald der Host wieder darf. Ist gerade gar kein
Host crawlbar, schläft der Worker bis zum frühesten freigegebenen Host
(gekappet bei `JONASSEARCH_MAX_IDLE_SLEEP`, dann wird neu gescannt).
**Wichtig bei großen Queues:** Die bekannten blockierten Hosts werden
direkt in der Claim-Query ausgeschlossen (nicht nur innerhalb des kleinen
Kandidatenfensters von `JONASSEARCH_CLAIM_SCAN_LIMIT`). Blockierte Zeilen
bleiben sonst als `pending` oben in der Prioritätsreihenfolge stehen: Ein
Host mit Tausenden wartenden URLs würde dann bei jedem Rescan dasselbe
Fenster füllen und alle anderen Hosts der Queue unsichtbar machen.
Höchstens `JONASSEARCH_CLAIM_BUSY_HOST_LIMIT` Hosts (die mit der längsten
Restwartezeit) gehen in die Query; weitere werden weiterhin pro Kandidat
übersprungen.
2. **Backoff bei Blocks:** HTTP 429/5xx/403/401 und Netzwerkfehler setzen den
Host auf exponentielles Backoff (z. B. 429: 60 s, sich verdoppelnd bis
30 min; 403/401: 10 min bis 2 h). Ein `Retry-After`-Header wird zusätzlich
@@ -67,6 +77,36 @@ Der Crawler wartet nie auf einer langsamen oder blockierten Domain:
nicht inline geschlafen: das Item wird ohne Versuchs-Zählung zurückgestellt
und solange eine andere Domain gecrawlt.
## Bildersuche (`pages.pictures`)
Der Crawler speichert zu jeder Seite die gefundenen Bild-URLs in
`pages.pictures`: absolute http(s)-URLs, pro Seite dedupliziert, ohne
URL-Fragmente. Erfasst werden `<img src>`, gängige Lazy-Loading-Attribute
(`data-src`, `data-lazy-src`, `data-original`), `srcset` (auch in
`<picture><source>`), `og:image`/`twitter:image` sowie
`<link rel="image_src">`. Relative Pfade werden gegen die Seiten-URL
aufgelöst; `data:`, `javascript:`, `ftp:` und nicht-öffentliche Hosts
werden verworfen. Die Bilder selbst werden **nicht** heruntergeladen oder
lokal gespeichert.
Einmalige Migration der Datenbank:
```bash
psql -h 127.0.0.1 -p 25432 -U jonassearch -d jonassearch \
-f add_pages_pictures.sql
```
Die Migration ist idempotent (`ADD COLUMN IF NOT EXISTS`) und lässt
bestehende Zeilen unverändert. Bereits gecrawlte Seiten erhalten ihre
Bilder beim nächsten Crawl; bis dahin behandeln die Abfragen `NULL` und
`'{}'` identisch als „keine Bilder“. Die Websuche ist davon unberührt.
Die Suchmaschine bietet dafür den Tab **Bilder** (`GET /api/images`).
Pro Quellseite werden höchstens `JONASSEARCH_IMAGES_PER_SOURCE_PAGE`
Bilder angezeigt; die Kacheln laden die Bilder direkt von der
Original-URL (Lazy Loading, defekte Bilder werden ausgeblendet). Details
stehen in [search/README.md](search/README.md).
## Nicht crawlbare Ziele (localhost, IPs, nicht-echte Domains)
Der Crawler folgt nur echten, öffentlich auflösbaren Domains. Bereits in