PhantomJS: injecting a script before any other scripts run

Pavel picture Pavel · Mar 17, 2013 · Viewed 7.8k times · Source

Using PhantomJS, I'd like to inject some JS as if there was an extra <script> tag before any other <script> tags. This is because the scripts on the page use some functions that PhantomJS does not have, namely Function.prototype.bind and window.webkitRequestAnimationFrame. I have a JS file with custom implementations of the two and I'd like PhantomJS to use them when running the scripts on the page.

The difficulty is that if I do page.injectJs before page.open, the script is injected into an empty page and is not carried over to the page being opened.

Alternatively, if I do page.injectJs after page.open, it's too late as the JavaScript errors (undefined functions) have already occurred.

I've found a way that appears to work, but is obviously a hack:

page.onResourceReceived = function() {
    page.injectJs('phantom-hacks.js')
};

This injects it many times (twice for each resource, apparently), but that's okay because my script is idempotent. However, I'd like to know the proper way to do this: inject it only once and before any scripts on the page are run.

Thanks :)

Answer

Andrey Petrenko picture Andrey Petrenko · Mar 17, 2013

I don't think there's a "proper" way to inject such script other than hooking to events. I've spent half a year working massively with PhantomJs and found no way to inject before all the errors start happening but after the page finished loading.

I would try to go through onInitialized, onLoadStarted, onLoadFinished. Inside the hooks I would call to page.evaluate() which would just modify DOM to have this extra whatever place you like.

I think one of them (the hooks) should give you the right timing you want.

Cheers