Früher gabe es dort auch eine aggregierte Liste je Typenschein mit den Angaben wieviele Fahrzeuge eingelöst sind mit diesem Typenschein usw.
Die Daten sind unter folgendem Link immer noch verfügbar:
Aber nicht mehr aggregiert, also je eingelöstem Fahrzeug eine Zeile (BEST.txt für die normalen Fahrzeuge). DIe liste Tab getrennt und 1.9 GB gross. Also die Liste mal runtergeladen und ein mit grep die Zeilen mit den passenden Typenscheinen rausgesucht. Da nicht jeder eine bash Konsole zur Verfügung hat, fragte ich nachher eine KI ob das nicht auch mit javascript lokal im Browser geht. Geht ohne Probleme inzwischen. Ich möchte euch das Miniskript nicht vorenthalten:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>ASTRA Typenschein-Abfrage</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 900px; margin: 30px auto; padding: 0 20px; color: #333; }
.box { background: #f5f5f7; padding: 20px; border-radius: 8px; margin-bottom: 20px; border: 1px solid #e5e5ea; }
input, button { padding: 10px; font-size: 16px; border-radius: 5px; border: 1px solid #ccc; margin-right: 10px; }
input[type="text"] { text-transform: uppercase; width: 150px; }
button { background: #0071e3; color: white; border: none; cursor: pointer; font-weight: bold; }
button:hover { background: #0077ed; }
button:disabled { background: #aeaeaf; cursor: not-allowed; }
#status { font-weight: bold; margin-top: 10px; color: #666; }
.download-link { display: inline-block; margin-top: 12px; color: #0071e3; text-decoration: none; font-size: 14px; }
.download-link:hover { text-decoration: underline; }
.card { background: white; border: 1px solid #d2d2d7; border-radius: 8px; padding: 15px; margin-top: 15px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
.card-header { font-weight: bold; border-bottom: 2px solid #0071e3; padding-bottom: 5px; margin-bottom: 10px; color: #0071e3; display: flex; justify-content: space-between; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 8px; font-size: 14px; }
.grid div { padding: 4px; border-bottom: 1px solid #f0f0f0; }
.label { font-weight: bold; color: #555; }
</style>
</head>
<body>
<h2>🇨🇭 ASTRA Fahrzeugbestand-Abfrage</h2>
<div class="box">
<label style="display: block; margin-bottom: 10px; font-weight: bold;">Schritt 1: BEST.txt auswählen</label>
<input type="file" id="fileInput" accept=".txt">
<div id="status">Bitte Datei auswählen...</div>
<a class="download-link" href="https://opendata.astra.admin.ch/ivzod/1000-Fahrzeuge_IVZ/1300-Fahrzeugbestaende/1320-Datensaetze_monatlich/" target="_blank">🔗 Hier die aktuellste BEST.txt beim ASTRA herunterladen</a>
</div>
<div class="box">
<label style="display: block; margin-bottom: 10px; font-weight: bold;">Schritt 2: Typenschein suchen</label>
<input type="text" id="tsInput" placeholder="Z.B. 1VA345" disabled>
<button id="searchBtn" disabled>Suchen</button>
</div>
<h3 id="resultTitle">Ergebnisse</h3>
<div id="results"></div>
<script>
const fileInput = document.getElementById('fileInput');
const tsInput = document.getElementById('tsInput');
const searchBtn = document.getElementById('searchBtn');
const statusDiv = document.getElementById('status');
const resultsDiv = document.getElementById('results');
const resultTitle = document.getElementById('resultTitle');
let file = null;
let headers = [];
// Datei-Auswahl überwachen
fileInput.addEventListener('change', async (e) => {
file = e.target.files[0];
if (!file) return;
statusDiv.innerText = "Lese Spaltenstruktur ein...";
// Die erste Zeile (Header) einlesen
const stream = file.stream();
const reader = stream.getReader();
const decoder = new TextDecoder('utf-8');
let { value, done } = await reader.read();
const firstChunk = decoder.decode(value);
const firstLine = firstChunk.split('\n')[0];
headers = firstLine.split('\t').map(h => h.trim());
// Reader stoppen, wir brauchen noch nicht mehr
await reader.cancel();
statusDiv.innerHTML = `Datei bereit: <strong>${file.name}</strong> (${(file.size / (1024*1024*1024)).toFixed(2)} GB)<br>Spalten erfolgreich geladen.`;
tsInput.disabled = false;
searchBtn.disabled = false;
});
// Suchfunktion
searchBtn.addEventListener('click', async () => {
const searchTS = tsInput.value.replace(/[\s.]/g, '').toUpperCase();
if (!searchTS) return alert("Bitte Typenschein eingeben!");
searchBtn.disabled = true;
tsInput.disabled = true;
resultsDiv.innerHTML = "";
resultTitle.innerText = "Suche läuft...";
const stream = file.stream();
const reader = stream.getReader();
const decoder = new TextDecoder('utf-8');
let partialLine = "";
let count = 0;
let lineIndex = 0;
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
const lines = (partialLine + chunk).split('\n');
// Die letzte Zeile könnte unvollständig sein, für den nächsten Durchlauf merken
partialLine = lines.pop();
for (let line of lines) {
lineIndex++;
if (lineIndex === 1) continue; // Kopfzeile überspringen
const columns = line.split('\t');
// Spalte 11 (Index 10) ist die Typengenehmigungs-Nr
if (columns[10] && columns[10].trim().toUpperCase() === searchTS) {
count++;
renderVehicleCard(columns, count);
}
}
}
// Eventuellen Rest verarbeiten
if (partialLine) {
const columns = partialLine.split('\t');
if (columns[10] && columns[10].trim().toUpperCase() === searchTS) {
count++;
renderVehicleCard(columns, count);
}
}
resultTitle.innerText = `Suche beendet. Total gefundene Fahrzeuge: ${count}`;
searchBtn.disabled = false;
tsInput.disabled = false;
if (count === 0) {
resultsDiv.innerHTML = "<p>Keine Fahrzeuge mit diesem Typenschein gefunden.</p>";
}
});
// Fahrzeug-Karte im HTML zeichnen
function renderVehicleCard(columns, index) {
const card = document.createElement('div');
card.className = 'card';
// Zähler dreistellig formatieren (z.B. 001)
const formattedIndex = String(index).padStart(3, '0');
let html = `<div class="card-header">
<span>Fahrzeug #${index}</span>
<span>^^^ ${formattedIndex} ^^^</span>
</div>
<div class="grid">`;
// Alle Spalten untereinander ausgeben
headers.forEach((header, i) => {
const value = columns[i] ? columns[i].trim() : '';
html += `<div><span class="label">${header}:</span> ${value}</div>`;
});
html += `</div>`;
card.innerHTML = html;
resultsDiv.appendChild(card);
}
</script>
</body>
</html>
Speichern als ts_abfrage.html oder so im Browser öffnen und dann auf der Webseite die lokal gespeicherte BEST.txt (oder ANDERE.txt,… nicht getestet) auswählen und nach dem Typenschein suchen. Typenschein eingeben (ohne Zusatz: M, C, X, Y am Schluss falls vorhanden) und jedes Fahrzeug wird ausgegeben. Das eigene via Zulassungskanton, PLZ, Farbe,… suchen.
Gruss
tomix