Last active
October 4, 2024 12:21
-
-
Save munro/7f81bd1657499866f7c2 to your computer and use it in GitHub Desktop.
Selenium wait for all images to load, including background images.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from textwrap import dedent | |
def wait_until_images_loaded(driver, timeout=30): | |
"""Waits for all images & background images to load.""" | |
driver.set_script_timeout(timeout) | |
driver.execute_async_script(dedent(''' | |
// Function to extract URL from CSS 'url()' function | |
function extractCSSURL(text) { | |
var url_str = text.replace(/.*url\((.*)\).*/, '$1'); | |
// If the URL is enclosed with double quotes | |
if (url_str[0] === '"') { | |
return JSON.parse(url_str); | |
} | |
// If the URL is enclosed with single quotes | |
if (url_str[0] === "'") { | |
return JSON.parse( | |
url_str | |
.replace(/'/g, '__DOUBLE__QUOTE__HERE__') | |
.replace(/"/g, "'") | |
.replace(/__DOUBLE__QUOTE__HERE__/g, '"') | |
); | |
} | |
// Return the URL as is | |
return url_str; | |
} | |
// Function to create a promise that resolves when the image is loaded | |
function imageResolved(url) { | |
return new Promise(function (resolve) { | |
var img = new Image(); | |
img.onload = function () { | |
resolve(url); | |
}; | |
img.src = url; | |
// If the image is already loaded, resolve the promise immediately | |
if (img.complete) { | |
resolve(url); | |
} | |
}); | |
} | |
// The last argument is expected to be a callback function | |
var callback = arguments[arguments.length - 1]; | |
Promise.all([ | |
// Get all img tags, create a promise for each one | |
...Array.from(document.querySelectorAll('img[src]'), img => imageResolved(img.src)), | |
// Get all inline styles with 'url()' and create a promise for each one | |
...Array.from(document.querySelectorAll('[style*="url("]'), elem => imageResolved(extractCSSURL(elem.style.cssText))) | |
]) | |
.then(function () { | |
// After all images are loaded, wait for all fonts to load | |
return document.fonts.ready; | |
}) | |
.then(function() { | |
// After all fonts are loaded, check for images in CSS stylesheets | |
let cssImagesPromises = []; | |
for(let i = 0; i < document.styleSheets.length; i++) { | |
let rules = document.styleSheets[i].cssRules; | |
for (let j = 0; j < rules.length; j++) { | |
let style = rules[j].style; | |
// Check if a background image is found and if it's a URL | |
if (style && String(style.backgroundImage).startsWith('url(')) { | |
let url = extractCSSURL(style.backgroundImage); | |
cssImagesPromises.push(imageResolved(url)); | |
} | |
} | |
} | |
return Promise.all(cssImagesPromises); | |
}) | |
.then(function () { | |
// Call the callback function when all promises are resolved | |
callback(arguments); | |
}); | |
return undefined; | |
''')) |
Awesome yet functional for the poor souls, not for making bad decisions, thank you very much!!!
I haven't fully tested this (which is why I haven't updated the gist) but here's code that works without jQuery dependency:
Let me know if this works and I'll update the gist!!
// Function to extract URL from CSS 'url()' function
function extractCSSURL(text) {
var url_str = text.replace(/.*url\((.*)\).*/, '$1');
// If the URL is enclosed with double quotes
if (url_str[0] === '"') {
return JSON.parse(url_str);
}
// If the URL is enclosed with single quotes
if (url_str[0] === "'") {
return JSON.parse(
url_str
.replace(/'/g, '__DOUBLE__QUOTE__HERE__')
.replace(/"/g, "'")
.replace(/__DOUBLE__QUOTE__HERE__/g, '"')
);
}
// Return the URL as is
return url_str;
}
// Function to create a promise that resolves when the image is loaded
function imageResolved(url) {
return new Promise(function (resolve) {
var img = new Image();
img.onload = function () {
resolve(url);
};
img.src = url;
// If the image is already loaded, resolve the promise immediately
if (img.complete) {
resolve(url);
}
});
}
// The last argument is expected to be a callback function
var callback = arguments[arguments.length - 1];
Promise.all([
// Get all img tags, create a promise for each one
...Array.from(document.querySelectorAll('img[src]'), img => imageResolved(img.src)),
// Get all inline styles with 'url()' and create a promise for each one
...Array.from(document.querySelectorAll('[style*="url("]'), elem => imageResolved(extractCSSURL(elem.style.cssText)))
])
.then(function () {
// After all images are loaded, wait for all fonts to load
return document.fonts.ready;
})
.then(function() {
// After all fonts are loaded, check for images in CSS stylesheets
let cssImagesPromises = [];
for(let i = 0; i < document.styleSheets.length; i++) {
let rules = document.styleSheets[i].cssRules;
for (let j = 0; j < rules.length; j++) {
let style = rules[j].style;
// Check if a background image is found and if it's a URL
if (style && String(style.backgroundImage).startsWith('url(')) {
let url = extractCSSURL(style.backgroundImage);
cssImagesPromises.push(imageResolved(url));
}
}
}
return Promise.all(cssImagesPromises);
})
.then(function () {
// Call the callback function when all promises are resolved
callback(arguments);
});
return undefined;
I haven't fully tested this (which is why I haven't updated the gist) but here's code that works without jQuery dependency:
Let me know if this works and I'll update the gist!!
// Function to extract URL from CSS 'url()' function function extractCSSURL(text) { var url_str = text.replace(/.*url\((.*)\).*/, '$1'); // If the URL is enclosed with double quotes if (url_str[0] === '"') { return JSON.parse(url_str); } // If the URL is enclosed with single quotes if (url_str[0] === "'") { return JSON.parse( url_str .replace(/'/g, '__DOUBLE__QUOTE__HERE__') .replace(/"/g, "'") .replace(/__DOUBLE__QUOTE__HERE__/g, '"') ); } // Return the URL as is return url_str; } // Function to create a promise that resolves when the image is loaded function imageResolved(url) { return new Promise(function (resolve) { var img = new Image(); img.onload = function () { resolve(url); }; img.src = url; // If the image is already loaded, resolve the promise immediately if (img.complete) { resolve(url); } }); } // The last argument is expected to be a callback function var callback = arguments[arguments.length - 1]; Promise.all([ // Get all img tags, create a promise for each one ...Array.from(document.querySelectorAll('img[src]'), img => imageResolved(img.src)), // Get all inline styles with 'url()' and create a promise for each one ...Array.from(document.querySelectorAll('[style*="url("]'), elem => imageResolved(extractCSSURL(elem.style.cssText))) ]) .then(function () { // After all images are loaded, wait for all fonts to load return document.fonts.ready; }) .then(function() { // After all fonts are loaded, check for images in CSS stylesheets let cssImagesPromises = []; for(let i = 0; i < document.styleSheets.length; i++) { let rules = document.styleSheets[i].cssRules; for (let j = 0; j < rules.length; j++) { let style = rules[j].style; // Check if a background image is found and if it's a URL if (style && String(style.backgroundImage).startsWith('url(')) { let url = extractCSSURL(style.backgroundImage); cssImagesPromises.push(imageResolved(url)); } } } return Promise.all(cssImagesPromises); }) .then(function () { // Call the callback function when all promises are resolved callback(arguments); }); return undefined;
I can confirm this script works great thanks!
awesome updated 😄
I'm on a phone afk rn but I did modify the callback var to be a function that returns that value instead so it would work
Sent from Proton Mail Android
…-------- Original Message --------
On 6/14/24 5:46 PM, Ryan Munro wrote:
@munro commented on this gist.
---------------------------------------------------------------
awesome updated 😄
—
Reply to this email directly, [view it on GitHub](https://gist.github.com/munro/7f81bd1657499866f7c2#gistcomment-5089485) or [unsubscribe](https://github.com/notifications/unsubscribe-auth/AACJRU3AUJXFQRAVGO6EY3LZHOFF7BFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVAZDSNZRGY4DSNNHORZGSZ3HMVZKMY3SMVQXIZI).
You are receiving this email because you commented on the thread.
Triage notifications on the go with GitHub Mobile for [iOS](https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675) or [Android](https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's an incredible job. Thank you for accomplishing this great work 8 years ago.