Loggen Sie sich auf hopper ein. Gehen Sie in Ihr Homeverzeichnis, erzeugen Sie ein Verzeichnis myplaywright, wechseln Sie hinein und installieren Sie das playwright-Modul und die entsprechenden Abhängigkeiten.
mkdir myplaywright
cd myplaywright
npm init -y
npm install playwright@latest
npx playwright install
Öffnen Sie den Editor vim mit dem
Dateinamen first.js und geben Sie 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();
Starten Sie dann das Skript mit:
node first.js
Dann sollte ein Screenshot im aktuellen Pfad als png existieren.
Sie können auf das Erscheinen eines Elementes warten und Javascript-Code in den Ausführungskontext des Browsers injizieren:
await page.waitForSelector('#header')
await page.evaluate(()=>{
document.querySelector('#header').innerHTML='neu'
})
Mit setViewportSize können Sie 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 Sie direkt in ein selektiertes Feld tippen - mit keyboard.press drücken Sie 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 injizieren:
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');
// injiziere 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.