Jsdom: Implémentation de innerText

Créé le 25 sept. 2015  ·  26Commentaires  ·  Source: jsdom/jsdom

jsdom est un excellent outil pour le scraping Web. Cependant, le textContent est un moyen très peu pratique d'obtenir du texte lisible pour la conversion html2text.

Il y a un article merveilleux sur l'utilité des innerText négligeables dans de nombreux cas :

http://perfectionkills.com/the-poor-misunderstood-innerText/

L'auteur suggère getSelection().toString() comme solution de contournement très lente, mais getSelection n'est pas encore implémenté dans le jsdom .

Pourriez-vous envisager une implémentation du innerText dans le jsdom ? L'auteur a fait une grande exploration à ce sujet, il a même ajouté une simple spécification à la fin.

feature layout

Commentaire le plus utile

Au cas où quelqu'un d'autre rencontre ce problème, j'ai fait un pas de plus et j'ai utilisé le package sanitize-html pour obtenir fondamentalement ce que fait le navigateur (notez que je n'ai pas importé la configuration JSDOM car j'ai trouvé que ce n'était pas nécessaire lorsque vous placez cela dans mon fichier de configuration Jest, mais si vous n'utilisez pas Jest, vous souhaiterez utiliser la configuration global.Element = (new JSDOM()).window.Element recommandée par @bennypowers ):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

Tous les 26 commentaires

Et quel dommage que la bibliothèque Selection et innerText longiligne ne soit pas compatible avec https://github.com/timdown/rangy/issues/348

Ainsi, innerText n'est pas standard et n'est pas implémenté dans au moins un moteur majeur (Firefox). Sans norme, je ne pense pas que nous devrions la mettre en œuvre.

On dirait qu'il y a du mouvement dans tout ça avec un brouillon de spécifications ici . Voir aussi toutes les références . Il n'y a cependant aucun problème sur le dépôt, donc je me demande à quel point il est déjà complet / à quel point les progrès seront rapides.

D'après les spécifications, il semble que nous ne puissions pas implémenter correctement innerText sans un support de mise en page de base.

Ouais, cela ne va pas vraiment être implémentable dans jsdom de toute façon, sans beaucoup de travail d'infrastructure... personne n'a d'espoir :(.

En ce qui concerne les exigences de prise en charge de la mise en page : https://github.com/rocallahan/innerText-spec/issues/2

Existe-t-il un plan pour le mettre en œuvre en raison de l'adoption du WHATWG ?

Ouais... Bien que la spécification nécessite beaucoup de choses que jsdom n'a pas, autour des boîtes CSS :(. Je ne sais pas quoi faire.

Existe-t-il une bibliothèque à connecter avec jsdom ?

@domenic souhaite-t-il savoir pourquoi il s'agit d'une telle refonte de l'infrastructure ? Nous pensions que le gorille de 800 livres dans la pièce laisserait la clé. Mais on dirait que ça ne va nulle part. Comme vous le savez, j'ai enveloppé ma tête autour des entrailles de jsdom. Où serait un bon endroit dans le référentiel pour commencer à réviser le code d'un nouveau jsdom ?

Merci d'avance /cc @vsemozhetbyt

Le principal problème est le fait que innerText s'appuie sur le moteur de mise en page pour obtenir des conseils, et jsdom n'a pas de moteur de mise en page. Voir https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute et
http://perfectionkills.com/the-poor-misunderstood-innerText/ . Depuis le deuxième lien :

Remarquez comment innerText représente presque exactement comment le texte apparaît sur la page. textContent, d'autre part, fait quelque chose d'étrange - il ignore les nouvelles lignes créées par
et autour des éléments stylisés en tant que bloc ( dans ce cas).

Toujours hors de portée et aucune solution de contournement ?

Apparemment, la spécification dit:

Si cet élément n'est pas rendu, ou si l'agent utilisateur est un agent utilisateur non CSS, [emphase ajoutée] renvoie alors la même valeur que l'attribut IDL textContent sur cet élément.

Je pense qu'une solution de contournement serait alors de simplement renvoyer textContent .

Nous implémentons suffisamment de CSS pour que je ne pense pas que cela s'applique. Nous n'implémentons tout simplement pas les parties de la mise en page...

Salut les gars, des nouvelles sur celui-ci?

Utilisez simplement du chrome sans tête :)

@domenic de cette spécification mentionnée par @coreh :
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute

Si cet élément n'est pas rendu , ou si l'agent utilisateur n'est pas un agent utilisateur CSS, retournez la même valeur que l'attribut IDL textContent sur cet élément.

https://html.spec.whatwg.org/multipage/rendering.html#being -rendered

Un élément est rendu s'il a des zones de mise en page CSS, des zones de mise en page SVG ou un équivalent dans d'autres langages de style.

Si jsdom n'implémente pas les parties de la mise en page, cela ne signifie-t-il pas que « ne pas être rendu » s'applique ?

Ce message s'adresse à toute personne atteignant ce fil de discussion github qui souhaite simplement obtenir un moyen de réussir ses tests sans modifier ses implémentations de fonction.

copypasta pour le haut de vos fichiers de test :

// Expose JSDOM Element constructor
global.Element = (new JSDOM()).window.Element;
// 'Implement' innerText in JSDOM: https://github.com/jsdom/jsdom/issues/1245
Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return this.textContent;
  },
});

Naturellement, les mises en garde de la discussion ci-dessus s'appliquent.

Au cas où quelqu'un d'autre rencontre ce problème, j'ai fait un pas de plus et j'ai utilisé le package sanitize-html pour obtenir fondamentalement ce que fait le navigateur (notez que je n'ai pas importé la configuration JSDOM car j'ai trouvé que ce n'était pas nécessaire lorsque vous placez cela dans mon fichier de configuration Jest, mais si vous n'utilisez pas Jest, vous souhaiterez utiliser la configuration global.Element = (new JSDOM()).window.Element recommandée par @bennypowers ):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

j'avais un besoin similaire mais je voulais aller un peu plus loin que la simple utilisation du textContent - encore une fois, ce ne sera pas une représentation précise de ce que font réellement les navigateurs, en particulier en ce qui concerne les éléments cachés par css, mais c'est bien assez pour mon cas d'utilisation:

function innerText(el)
  el = el.cloneNode(true) // can skip if mutability isn't a concern
  el.querySelectorAll('script,style').forEach(s => s.remove())
  return el.textContent
}

Quel dommage!

Apparemment, la spécification dit:

Si cet élément n'est pas rendu, ou si l'agent utilisateur est un agent utilisateur non CSS , [emphase ajoutée] renvoie alors la même valeur que l'attribut textContent IDL sur cet élément.

Je pense qu'une solution de contournement serait alors de simplement renvoyer textContent.

Nous implémentons suffisamment de CSS pour que je ne pense pas que cela s'applique. Nous n'implémentons tout simplement pas les parties de la mise en page...

@domenic s'il vous plaît envisager une interprétation plus libérale de la spécification

textContent est explicitement autorisé comme solution de repli, lorsque l'application des règles CSS est trop coûteuse

aussi, innerText est spécifié comme getter et setter

Étant donné que je suis l'éditeur des spécifications, je peux affirmer avec certitude que "lorsque l'application des règles CSS coûte trop cher" n'est pas ce que dit la spécification.

.. c'était mon interprétation de "si l'agent utilisateur est un agent utilisateur non CSS"

quelle est la différence entre un "agent utilisateur CSS" et un "agent utilisateur non CSS" ?

qu'en est-il de:
un agent utilisateur CSS peut "appliquer des règles CSS" et afficher le résultat (graphique ou textuel)
un agent utilisateur non CSS est trop stupide pour "appliquer les règles CSS"

Nous implémentons suffisamment de CSS pour que je ne pense pas que cela s'applique.

que veux-tu dire? window.getComputedStyle ?

un repli vers textContent est toujours mieux que de ne pas implémenter une interface standard

Peut-être que nous pouvons simplement utiliser la textContent pour remplacer le résultat de innerText lors de l'exécution des tests avec jsdom . Par example:

describe('mytest', () => {
  beforeAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'innerText', {
      get() {
        return this.textContent;
      }
    });
  });
  it('should ok', () => {
  // test assertions
  });
});
Cette page vous a été utile?
0 / 5 - 0 notes