J'ai utilisé l'astuce suivante pour désactiver phantomjs anti aliasing sous Linux. PhantomJS est construit en utilisant fontconfig, et cette bibliothèque recherche un fichier "fonts.conf" dans plusieurs endroits: voir https://www.freedesktop.org/software/fontconfig/fontconfig-user.html.
En créant le fonts.conf suivant, nous pouvons désactiver l'antialiasing pour fontconfig:
<match target="font">
<edit mode="assign" name="antialias">
<bool>false</bool>
</edit>
</match>
L'un des emplacements est définie par une variable d'environnement, selon les spécifications: $ XDG_CONFIG_HOME/fontconfig/fonts.conf . Donc, en créant un fichier temporaire comme /tmp/phantomjs-config/fontconfig/fonts.conf avec le contenu ci-dessus, puis en définissant XDG_CONFIG_HOME dans/tmp/phantomjs-config, nous disons à fontconfig de lire ce fichier.
Il y a cependant un problème: la classe PhantomJSDriver, par défaut, ne permet pas de définir les variables d'environnement. Ce qui est triste, car le code de travail sous-jacent, PhantomWebDriverService, le permet.
Pour résoudre cela, je créé une petite classe d'aide dans laquelle je copiais des méthodes protégées de PhantomJSDriverService:
public class MyPhantomDriverService {
public static PhantomJSDriverService createDefaultService(Capabilities desiredCapabilities, Map<String, String> env) {
Proxy proxy = null;
if (desiredCapabilities != null) {
proxy = Proxy.extractFrom(desiredCapabilities);
}
File phantomjsfile = findPhantomJS(desiredCapabilities, "https://github.com/ariya/phantomjs/wiki", "http://phantomjs.org/download.html");
File ghostDriverfile = findGhostDriver(desiredCapabilities, "https://github.com/detro/ghostdriver/blob/master/README.md", "https://github.com/detro/ghostdriver/downloads");
Builder builder = new Builder();
builder.usingPhantomJSExecutable(phantomjsfile)
.usingGhostDriver(ghostDriverfile)
.usingAnyFreePort()
.withProxy(proxy)
.withLogFile(new File("phantomjsdriver.log"))
.usingCommandLineArguments(findCLIArgumentsFromCaps(desiredCapabilities, "phantomjs.cli.args"))
.usingGhostDriverCommandLineArguments(findCLIArgumentsFromCaps(desiredCapabilities, "phantomjs.ghostdriver.cli.args"));
if(null != env)
builder.withEnvironment(env);
return builder.build();
}
public static File findPhantomJS(Capabilities desiredCapabilities, String docsLink, String downloadLink) {
String phantomjspath;
if (desiredCapabilities != null && desiredCapabilities.getCapability("phantomjs.binary.path") != null) {
phantomjspath = (String)desiredCapabilities.getCapability("phantomjs.binary.path");
} else {
phantomjspath = (new ExecutableFinder()).find("phantomjs");
phantomjspath = System.getProperty("phantomjs.binary.path", phantomjspath);
}
Preconditions.checkState(phantomjspath != null, "The path to the driver executable must be set by the %s capability/system property/PATH variable; for more information, see %s. The latest version can be downloaded from %s", "phantomjs.binary.path", docsLink, downloadLink);
File phantomjs = new File(phantomjspath);
checkExecutable(phantomjs);
return phantomjs;
}
protected static File findGhostDriver(Capabilities desiredCapabilities, String docsLink, String downloadLink) {
String ghostdriverpath;
if (desiredCapabilities != null && desiredCapabilities.getCapability("phantomjs.ghostdriver.path") != null) {
ghostdriverpath = (String)desiredCapabilities.getCapability("phantomjs.ghostdriver.path");
} else {
ghostdriverpath = System.getProperty("phantomjs.ghostdriver.path");
}
if (ghostdriverpath != null) {
File ghostdriver = new File(ghostdriverpath);
Preconditions.checkState(ghostdriver.exists(), "The GhostDriver does not exist: %s", ghostdriver.getAbsolutePath());
Preconditions.checkState(ghostdriver.isFile(), "The GhostDriver is a directory: %s", ghostdriver.getAbsolutePath());
Preconditions.checkState(ghostdriver.canRead(), "The GhostDriver is not a readable file: %s", ghostdriver.getAbsolutePath());
return ghostdriver;
} else {
return null;
}
}
protected static void checkExecutable(File exe) {
Preconditions.checkState(exe.exists(), "The driver executable does not exist: %s", exe.getAbsolutePath());
Preconditions.checkState(!exe.isDirectory(), "The driver executable is a directory: %s", exe.getAbsolutePath());
Preconditions.checkState(exe.canExecute(), "The driver is not executable: %s", exe.getAbsolutePath());
}
private static String[] findCLIArgumentsFromCaps(Capabilities desiredCapabilities, String capabilityName) {
if (desiredCapabilities != null) {
Object cap = desiredCapabilities.getCapability(capabilityName);
if (cap != null) {
if (cap instanceof String[]) {
return (String[])((String[])cap);
}
if (cap instanceof Collection) {
try {
Collection<String> capCollection = (Collection<String>)cap;
return (String[])capCollection.toArray(new String[capCollection.size()]);
} catch (Exception var4) {
System.err.println(String.format("Unable to set Capability '%s' as it was neither a String[] or a Collection<String>", capabilityName));
}
}
}
}
return new String[0];
}
}
Avec ce nouveau code, je peux maintenant créer un PhantomJSDriver comme suit:
//-- 1. Make a temp directory which will contain our fonts.conf
String tmp = System.getProperty("java.io.tmpdir");
if(tmp == null) {
tmp = "/tmp";
}
File dir = new File(tmp + File.separator + "/_phantomjs-config/fontconfig");
dir.mkdirs();
if(! dir.exists()) {
throw new IOException("Can't create fontconfig directory to override phantomjs font settings at " + dir);
}
File conf = new File(dir, "fonts.conf");
String text = "<match target=\"font\">\n"
+ "<edit mode=\"assign\" name=\"antialias\">\n"
+ "<bool>false</bool>\n"
+ "</edit>\n"
+ "</match>";
try(FileOutputStream fos = new FileOutputStream(conf)) {
fos.write(text.getBytes("UTF-8"));
}
//-- Set the XDG_CONFIG_HOME envvar; this is used by fontconfig as one of its locations
Map<String, String> env = new HashMap<>();
env.put("XDG_CONFIG_HOME", dir.getParentFile().getAbsolutePath());
PhantomJSDriverService service = MyPhantomDriverService.createDefaultService(capabilities, env);
wd = new PhantomJSDriver(service, capabilities);
Problèmes avec le code
Le problème le plus important avec ce code est qu'il peut échouer s'il existe des fichiers fonts.conf (comme $ HOME/.fonts.conf). à définir anti aliasing. Mais pour mon test, cela fonctionne bien.
La même astuce fonctionne aussi pour Headless Chrome;)
Pour désactiver l'anti aliasing sur le chrome sans tête utiliser le même code ci-dessus pour générer le fichier fonts.conf, puis allouer une WebDriver Chrome comme suit:
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeDriverService.Builder;
...
Map<String, String> env = new HashMap<>();
env.put("XDG_CONFIG_HOME", dir.getParentFile().getAbsolutePath());
Builder builder = new Builder();
builder.usingAnyFreePort();
builder.withEnvironment(env);
ChromeDriverService service = builder.build();
return new ChromeDriver(service, dc);
Je vous suggère de commencer à vous en éloigner. Comme il n'est plus supporté maintenant. https://groups.google.com/forum/#!topic/phantomjs/9aI5d-LDuNE –
Je sais, mais les gens l'utilisent encore. Transition à quelque chose d'autre n'est pas fait aussi rapidement;) – fjalvingh
En fait, la même astuce fonctionne également avec Chrome sans tête;) Je vais mettre à jour la réponse avec ça aussi. – fjalvingh