Lizenzen Freepik

Alle Lizenzen von Freepik wurden einmal via Javascript mit Playwright heruntergeladen. Hier gibt es einmal die Liste aller knapp 1900 heruntergeladenen Grafiken: lizenzen

Zu allen, zu denen wir noch eine Lizenz aufrufen konnten, habe ich das PDF auf dem Morpheus hinterlegt. 84 von 1895 haben kein Lizenzdokument mehr, da der Autor die Grafik von Freepik entfernt hat. Die sind in der CSV mit “nicht verfügbar” markiert.

Zum Herunterladen wurde ein autonomer Browser mit Playwright und Javascript genutzt, Skripte hier:

// Freepik/Magnific: Lizenz-PDFs + Metadaten automatisch sichern
// Voraussetzung: Node.js 18+
// npm i playwright
// npx playwright install chromium
// Start: node lizenzen-download.js
//
// Ergebnis: Ordner ./lizenzen mit allen PDFs + lizenzen.csv
// Das Skript kann jederzeit abgebrochen und neu gestartet werden –
// bereits erledigte Zeilen werden übersprungen.

const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');

// ---------- Einstellungen ----------
const BASE = 'https://www.magnific.com/de/user/downloads?type=regular&page=';
const START_PAGE = 1;
const END_PAGE = 95;
const OUT_DIR = path.resolve('lizenzen');
const CSV_FILE = path.join(OUT_DIR, 'lizenzen.csv');
const DEBUG = true; // zeigt beim ersten Lauf den Inhalt aller Zellen der ersten Zeile
const DOWNLOAD_TIMEOUT = 15000; // ms, wie lange auf das PDF gewartet wird
const PAUSE_MIN = 1000, PAUSE_MAX = 2500; // Pause zwischen Downloads (Server schonen)

// Texte, an denen erkannt wird, dass das Lizenzdokument fehlt (bei Bedarf ergänzen)
const NOT_AVAILABLE_TEXTS = ['nicht mehr verfügbar', 'nicht verfügbar', 'not available', 'no longer available'];

// ---------- Zeile auswerten ----------
// Passen Sie das an, nachdem Sie die DEBUG-Ausgabe gesehen haben.
// cells = Array mit dem sichtbaren Text jeder Spalte (td) der Zeile.
function parseRow(cells) {
const col1 = (cells[0] || '').split('\n').map(s => s.trim()).filter(Boolean);
const title = col1[0] || '';
// Lizenzgeber: Zeile mit "von"/"by", sonst zweite Zeile der ersten Spalte
let author = col1.find(l => /^(von|by)\s/i.test(l)) || col1[1] || '';
author = author.replace(/^(von|by)\s+/i, '');
// Datum: erste Zelle, in der ein Datum vorkommt
const dateRe = /\d{1,2}[./-]\d{1,2}[./-]\d{2,4}|\d{4}-\d{2}-\d{2}|\d{1,2}\.?\s+\p{L}+\.?\s+\d{4}/u;
let date = '';
for (const c of cells) { const m = c.match(dateRe); if (m) { date = m[0]; break; } }
return { title, author, date };
}

// ---------- Hilfsfunktionen ----------
const sleep = ms => new Promise(r => setTimeout(r, ms));
const pause = () => sleep(PAUSE_MIN + Math.random() * (PAUSE_MAX - PAUSE_MIN));
const safe = s => (s || 'ohne-titel').replace(/[\\/:*?"<>|\n\r]+/g, '_').slice(0, 80).trim();
const csvCell = v => `"${String(v ?? '').replace(/"/g, '""')}"`;

function loadDone() {
const done = new Set();
if (!fs.existsSync(CSV_FILE)) {
fs.writeFileSync(CSV_FILE, '\uFEFF' + ['Seite', 'Zeile', 'Bezeichnung', 'Lizenzgeber', 'Download-Datum', 'Lizenz-PDF', 'Dateiname'].map(csvCell).join(';') + '\n');
return done;
}
for (const line of fs.readFileSync(CSV_FILE, 'utf8').split('\n').slice(1)) {
const m = line.match(/^"(\d+)";"(\d+)"/);
if (m) done.add(`${m[1]}-${m[2]}`);
}
return done;
}

function appendCsv(row) {
fs.appendFileSync(CSV_FILE, row.map(csvCell).join(';') + '\n');
}

// ---------- Hauptprogramm ----------
(async () => {
fs.mkdirSync(OUT_DIR, { recursive: true });
const done = loadDone();

const ctx = await chromium.launchPersistentContext('./browser-profil', {
headless: false,
acceptDownloads: true,
// channel: 'chrome', // einkommentieren, falls der Login mit Google in Chromium blockiert wird
});
const page = ctx.pages()[0] || await ctx.newPage();

await page.goto(BASE + START_PAGE);
console.log('\nBitte im Browserfenster einloggen (nur beim ersten Mal nötig),');
console.log('dann hier im Terminal ENTER drücken …');
await new Promise(r => process.stdin.once('data', r));

let debugShown = false;

for (let p = START_PAGE; p <= END_PAGE; p++) {
await page.goto(BASE + p, { waitUntil: 'domcontentloaded' });
try {
await page.waitForSelector('table.w-full > tbody tr', { timeout: 20000 });
} catch {
console.warn(`Seite ${p}: keine Tabelle gefunden – übersprungen`);
continue;
}
await sleep(1000);

const rows = page.locator('table.w-full > tbody > tr');
const count = await rows.count();
console.log(`\nSeite ${p}: ${count} Zeilen`);

for (let i = 0; i < count; i++) {
const key = `${p}-${i + 1}`;
if (done.has(key)) continue;

const row = rows.nth(i);
const cells = await row.locator('td').allInnerTexts();

if (DEBUG && !debugShown) {
console.log('\n--- DEBUG: Zellen der ersten Zeile ---');
cells.forEach((c, n) => console.log(`td[${n + 1}]:`, JSON.stringify(c)));
console.log('--------------------------------------\n');
debugShown = true;
}

const { title, author, date } = parseRow(cells);
const button = row.locator('td:nth-child(3) > div:nth-child(1) > button:nth-child(1)');

let status = 'nicht verfügbar';
let fileName = '';

const rowText = cells.join(' ').toLowerCase();
const hasButton = (await button.count()) > 0 && await button.isEnabled().catch(() => false);

if (hasButton && !NOT_AVAILABLE_TEXTS.some(t => rowText.includes(t))) {
try {
const [result] = await Promise.all([
Promise.race([
page.waitForEvent('download', { timeout: DOWNLOAD_TIMEOUT }).then(d => ({ d })),
ctx.waitForEvent('page', { timeout: DOWNLOAD_TIMEOUT }).then(np => ({ np })),
]),
button.click(),
]);

fileName = `S${String(p).padStart(2, '0')}-Z${String(i + 1).padStart(2, '0')}_${safe(title)}.pdf`;

if (result.d) {
await result.d.saveAs(path.join(OUT_DIR, fileName));
status = 'verfügbar';
} else if (result.np) {
// PDF öffnet in neuem Tab statt als Download
await result.np.waitForLoadState().catch(() => {});
const url = result.np.url();
const resp = await ctx.request.get(url);
if (resp.ok() && (resp.headers()['content-type'] || '').includes('pdf')) {
fs.writeFileSync(path.join(OUT_DIR, fileName), await resp.body());
status = 'verfügbar';
} else {
fileName = '';
}
await result.np.close();
}
} catch {
// Kein Download innerhalb des Timeouts → prüfen, ob eine Meldung erscheint
const body = (await page.locator('body').innerText()).toLowerCase();
status = NOT_AVAILABLE_TEXTS.some(t => body.includes(t)) ? 'nicht verfügbar' : 'Fehler – prüfen';
fileName = '';
}
}

appendCsv([p, i + 1, title, author, date, status, fileName]);
done.add(key);
console.log(` ${key}: ${status} | ${title} | ${author} | ${date}`);
await pause();
}
}

console.log(`\nFertig. Ergebnisse in: ${CSV_FILE}`);
await ctx.close();
process.exit(0);
})();

 

Zur Ausführung war folgendes notwendig:

npm i playwright
npx playwright install chromium
node lizenzen-download.js

Schreibe einen Kommentar

Menü schließen