Logge Dich auf hopper ein. Gehe in Dein Homeverzeichnis, erzeuge ein Verzeichnis myplaywright, wechsel hinein und installiere das playwright-Modul und die entsprechenden Abhängigkeiten.
mkdir myplaywright
cd myplaywright
npm init -y
npm install playwright@latest
npx playwright install chromium
Öffne den Editor vim mit dem
Dateinamen first.js und gib den folgenden Code ein:
const playwright = require("playwright-core");
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
async function main() {
const browser = await playwright.chromium.launch({});
const context = await browser.newContext({});
const page = await context.newPage();
page.on("console", (msg) => {
console.log(msg.text());
});
page.on("load", () => console.log("page loaded"));
await page.goto(
"https://informatik.hs-bremerhaven.de/docker-oradfelder-web/pd.html",
);
await delay(1000)
await page.screenshot({ path: "playwright.png", fullPage: true });
await browser.close();
}
main();
Starte dann das Skript mit:
node first.js
Dann sollte ein Screenshot im aktuellen Pfad als png existieren.
Wir können auf Erscheinen eines Elementes warten und Javascript-Code in den Ausführungskontext des Browsers injezieren:
await page.waitForSelector('#header',{state:"attached"})
await page.evaluate(()=>{
document.querySelector('#header').innerHTML='neu'
})
Auf hopper (debian trixie) ist es zur Zeit notwendig bei waitForSelector noch den Zustand attached mitzugeben, weil mehrere Elemente nicht im Zustand visible sind, obwohl sie sichtbar sind. Das geschieht unter Ubuntu 24.04 in Euren virtuellen Maschinen nicht. Ebenso geschieht das nur mit playwright@latest, was zur Zeit des Schreibens hier Version 1.55 entspricht. Version 1.52 ist die letzte, die im Moment unter Debian Trixie funktioniert. Playwright ist ein wenig fragil, wenn es nicht unter Ubuntu läuft.
Mit setViewportSize können wir die Größe des Browserfensters verändern:
await page.setViewportSize ({width: 1920,height: 1080});
Mit dem Dollar-Operator verkürzt man die evaluate/querySelector-Schachtelung. Mit der Funktion type können wir direkt in ein selektiertes Feld tippen - mit keyboard.press drücken wir einzelne Tasten.
const input = await page.$("input[name='thename']")
await input.focus()
await input.type('MOIN ',{ delay:100 })
//vierfach-Klick zum Markieren
await input.click({ clickCount: 4 })
await new Promise(e => setTimeout(e, 1000));
await page.type('input[name=thename]', 'moin', {delay: 100})
await page.keyboard.press('Enter')
Üblicherweise wird man auch im headless-Modus die Ausgaben auf der Konsole im Browser abfangen wollen. Wieder ist der Kontext unterschiedlich und es muss das jeweilige Ereignis von der einen Konsole abgefangen und weitergeleitet werden:
page.on('console', msg => {
console.log("console:"+msg.text())
});
Bisweilen ist es notwendig, bestimmten Code beim Laden des Dokumentes, jedoch vor dem Ausführen von Script-Tags auszuführen:
await page.addInitScript(() => {
Object.defineProperty(navigator, "languages", {
get: function() {
return ["en-US", "en"];
}
})
});
Mit exposeFunction lässt sich eine Funktion nachträglich in den Javascript-Kontext des Browser injezieren:
let outer='outerValue'
function outerFunction(){
console.log("called outerFunction from Browser Context")
}
await page.exposeFunction('myFunction', (arg) => {
console.log(`Called with: ${arg} outer:${outer}`);
outerFunction();
});
await page.evaluate(()=>{ myFunction('myArg');});
Mit Selektoren lässt sich fokussieren, anklicken, etc
await page.focus('input[name=submitter]')
await new Promise(e => setTimeout(e, 1000));
await page.locator('input[name=submitter]',(e)=>e.click())
// oder
const submitter = await page.locator('input[name=submitter]')
await submitter.click()
Einzelne Ereignisse lassen sich abfangen:
page.on('load', () => console.log('page loaded'));
page.on('frameattached',() => console.log('attached'));
page.on('framenavigated', () => console.info('frame navigated'));
page.on('dialog', async dialog => {
console.info(`dialog: ${dialog.message()}`);
await dialog.dismiss();
});
page.on('request', request => console.info(`request: ${request.url()}`));
page.on('requestfinished', request => console.info(`request finished: ${request.url()}`));
page.on('response', response => console.info(`response: ${response.url()}`));
page.on('workercreated', worker => console.info(`worker created: ${worker.url()}`));
page.on('workerdestroyed', worker => console.info(`worker destroyed: ${worker.url()}`));
page.once('close', () => console.info('page closed'));
Der Datei-Download ist bei Playwright eher einfach:
const downloadPromise = page.waitForEvent("download");
await page.getByText("download").click();
// Wait for the download process to complete
const download = await downloadPromise;
console.log(await download.path());
// Save downloaded file somewhere
await download.saveAs("download.png");
Der Upload - typischerweise per Ajax - funktioniert einfach , wenn sich die Seite entsprechend verhält: Wenn der Upload fertig ist, sollte irgendetwas an der Seite sich ändern.
await page.waitForSelector('input[type=file]');
await page.locator('input[type=file]').setInputFiles("playwright.png")
await page.locator("#uploader").click();
await page.waitForSelector('#uploadedlink');
Einige weitere hilfreiche Funktionen:
// warte bis der Ausdruck wahr wird
await page.waitForFunction('counter>3');
// injeziere Script-Tag vom Server
await page.addScriptTag({url:"pd-script.js"})
// ... oder lokal
await page.addScriptTag({path:"pd-localscript.js"})
// globale Variablen müssen dort über window. ...
// gesetzt werden
// click und warte auf Navigation
const [response] = await Promise.all([
page.waitForNavigation(),
page.click("a.mylink"),
]);
// bzw:
const elements = await Promise.all([
page.waitForNavigation(),
page.click("a.mylink"),
]);
console.log(elements[0])
// den Inhalt der Seite abholen
let content=await page.content()
// cookies lesen
let cookies=await page.context().cookies()
Im Gegensatz zu Puppeteer lässt sich Playwright auch gut aus Java und Python heraus nutzen. Insgesamt lohnt es sich aber sicher, aus Javascript heraus zu arbeiten - das ist schließlich die originäre Sprache des Webs.
Wenn playwright im eigenen Docker oder in der eigenen Ubuntu-VM installiert werden soll, fehlen vermutlich noch einige Abhängigkeiten im System. Das wird am besten mit npx playwright install-deps nachgeholt - dann natürlich als root-User bzw. mit sudo.