JavaScript: screenshot rendered web page Browser style - javascript

I assume this question might have been asked before but after hours of searching, I haven't found anything satisfying.
Here's my question: Is it possible to screenshot a fully rendered web page using JavaScript? A little like what most browsers do on windows on the press of ctrl+p.
I have looked into a lot of alternative solutions like html2Canvas.js
but none suits my needs. The biggest issue being my web page almost entirely rendered on client side using Javascript. This is also why server side solution like PhantomJS are hardly applicable.
I need the screenshots to be printed as image or PDF.
Any idea?
Thanks.

Have you looked into Puppeteer by Google?
If you're able to run it on your server, it might be exactly what you're looking for. See their example code:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();

Related

13172:13172:0130/132851.112358:ERROR:ozone_platform_x11.cc(238) Missing X server or $DISPLAY in Puppeteer

Okay, so I'm fairly new to using puppeteer in JavaScript, so I apologize for my inexperience. I'll try my best to stay up to date with this forum and provide any extra information that is asked of me, but I'm a CS student, so please be patient.
So I've set up Puppeteer on both my desktop computer at home and my personal laptop that I take with me, but my laptop has been having issues ever since I've tried getting it up. My desktop executes my personal project's code perfectly fine with no errors or issues in a chromium headful browser. My laptop though seems to have been having the same error, which I believe has to entirely do with the way I downloaded it.
Here is an example of something I'm trying to do:
const { executablePath } = require('puppeteer');
const puppeteer = require('puppeteer-extra')
const url = "https://www.google.com/"
async function createPage() {
const browser = await puppeteer.launch({headless: false, executablePath: executablePath(), args: ['--disable-web-security', '--disable-features=IsolateOrigins,site-per-process']});
const page = await browser.newPage();
return page;
}
async function openPage(page) {
await page.goto(url);
}
async function screenshot_photo(page) {
await page.screenshot({path: 'screenshot.jpg'});
await page.close()
}
async function testing() {
var page = await createPage();
await openPage(page);
await screenshot_photo(page);
}
testing();
My error in my terminal is as follows:
Error: Failed to launch the browser process!
[16533:16533:0130/140329.896545:ERROR:ozone_platform_x11.cc(238)] Missing X server or $DISPLAY
[16533:16533:0130/140329.896887:ERROR:env.cc(255)] The platform failed to initialize. Exiting.
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
Other useful info:
I'm running my code in WSL: Ubuntu on both systems
Node version: v19.1.0
npm version: 9.3.1
echoing display gives me me a blank output
Just to elaborate, the code I've written above works perfectly fine on my desktop with no issues.
I've tried troubleshooting this issue for quite a while and believe I might have an idea of what the issue is, but unsure what approach to take. When I originally tried to get puppeteer on my laptop, I came across many different errors and issues before I finally landed on the dreaded $DISPLAY error.
I've tried reinstalling node, npm and puppeteer many times. I've tried manually installing a chromium (PUPPETEER_SKIP_DOWNLOAD) and changing the executablePath to where the browser downlaoded. I tried switching to different versions of puppeteer. All these attempts lead me to worse errors and I felt would be counterintuitive since everything works fine on my desktop. The code I provided works perfectly fine headless and even screenshots the webpage, but with my project, I really need a headful display.
My idea is that there was an issue with my installation and that's the reason why I can't have my headful browser display to my screen on my laptop. So any help in reinstalling everything from the ground up, fixing my $DISPLAY, or just walking me through it would be greatly appreciated as I'm still trying to learn!
Thank you so much!

Headless Chrome to Execute Javascript

I want to Server side render my React Application. So the request first comes to my web server (written in Rust). I aggregate all the data required to generate the html.
After that I want to execute my React application using headless Chrome.
Every example of headless chrome shows me to "navigate to a page".
Using Nodejs for example using Puppeteer library
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'});
await page.pdf({path: 'hn.pdf', format: 'A4'});
await browser.close();
})();
Instead of navigating to a URL, I just want to use the headless Chrome as a JavaScript engine, which given a JavaScript executes it.
I looked but nowhere I could find a example of that.
Well, quick look at pupetter API shows this one:
page.evaluate(pageFunction[, ...args])
pageFunction <function|string> Function to be evaluated in the page context
...
Exact link to API: https://github.com/puppeteer/puppeteer/blob/v3.1.0/docs/api.md#pageevaluatepagefunction-args

How to get a screenshot/preview of another website

Is there a way in which you can get a screenshot of another websites pages?
e.g: you introduce a url in an input, hit enter, and a script gives you a screenshot of the site you put in. I manage to do it with headless browsers, but I fear that could take too much resources and time, to launch. let's say phantomjs each time the input is used the headless browser would need to get the new data, I investigate HotJar, it does something similar to what I'm looking for, but it gives you a script that you must put into the page header, which is fine by me, afterwards, you get a preview, how does it work?, and how can one replicate it?
Do you want a print screen of your page or someone else's?
Own page
Use puppeteer or phantomJS with Beverly build of your site, this way you will only run it when it changes, and have a screenshot ready at any time.
Foreign page
You have access to it (the owner runs your script)
Either try to get into his build pipeline, and use solution from above.
Or use this solution Using HTML5/Canvas/JavaScript to take in-browser screenshots.
You don't have any access
Use some long-running process that will give you screenshot when asked.
Imagine a server with one URL endpoint: screenshot.example.com?facebook.com.
The long-running server has a puppeteer/phantomJS instance ready to go when given URL, it will flood that page, get the screenshot and send it back. The browser will actually think of it as a slow ping image request.
You can make this with puppeteer
install with: npm i puppeteer
save the following code to example.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
and run it with:
node example.js

Capturing application screen with JavaScript

Is it possible to capture the entire window as screenshot using JavaScript?
The application might contain many iframes and div's where content are loaded asynchronously.
I have explored canvas2image but it works on an html element, using the same discards any iframe present on the page.
I am looking for a solution where the capture will take care of all the iframes present.
The only way to capture the contents of an iframe using ONLY JavaScript in the webpage (No extensions, or application running outside the browser on a users system) is to use the HTMLIFrameElement.getScreenshot() API in Firefox. This API is non-standard, and ONLY works in Firefox.
For any other browser, no. An iframe is typically sandboxed, and as such it is not accessible by the browser by design.
The best way to get a screenshot of a webpage that I have found and use, is an instance of Headless Chrome or Headless Firefox. These will take a screenshot of everything on the page, just as a user would see it.
Yes, widh Puppeteer it is possible.
1 - Just install the dependency:
npm i puppeteer-core
2 - Create JavaScript file, screenshot.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://yourweb.com');
await page.screenshot({path: 'screenshot.png'});
await browser.close();
})();
3 - Run:
node screenshot.js
Source
Web pages are not the best things to be "screenshoted", because of their nature; they can include async elements, frames or something like that, they are usually responsive etc...
For your purpose the best way is to use external api or an external service, I think is not a good idea to try doing that with JS.
You should try https://www.url2png.com/

Puppeteer: is there a way to access the DevTools Network API?

I am trying to use Puppeteer for end-to-end tests. These tests require accessing the network emulation capabilities of DevTools (e.g. to simulate offline browsing).
So far I am using chrome-remote-interface, but it is too low-level for my taste.
As far as I know, Puppeteer does not expose the network DevTools features (emulateNetworkConditions in the DevTools protocol).
Is there an escape hatch in Puppeteer to access those features, e.g. a way to execute a Javascript snippet in a context in which the DevTools API is accessible?
Thanks
Edit:
OK, so it seems that I can work around the lack of an API using something like this:
const client = page._client;
const res = await client.send('Network.emulateNetworkConditions',
{ offline: true, latency: 40, downloadThroughput: 40*1024*1024,
uploadThroughput: 40*1024*1024 });
But I suppose it is Bad Form and may slip under my feet at any time?
Update: headless Chrome now supports network throttling!
In Puppeteer, you can emulate devices (https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageemulateoptions) but not network conditions. It's something we're considering, but headless Chrome needs to support network throttling first.
To emulate a device, I'd use the predefined devices found in DeviceDescriptors:
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto('https://www.google.com');
// other actions...
browser.close();
});

Categories