Jsdom: innerText implementation

Erstellt am 25. Sept. 2015  ·  26Kommentare  ·  Quelle: jsdom/jsdom

jsdom ist ein großartiges Tool zum Web-Scraping. Allerdings ist textContent ein sehr unpraktischer Weg, um lesbaren Text für die html2Text-Konvertierung zu erhalten.

Es gibt einen wunderbaren Artikel über die Nützlichkeit von vernachlässigbaren innerText in vielen Fällen:

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

Der Autor schlägt getSelection().toString() als sehr langsamen Workaround vor, aber getSelection ist noch nicht in jsdom implementiert.

Könnten Sie eine Implementierung von innerText im jsdom in

feature layout

Hilfreichster Kommentar

Für den Fall, dass noch jemand auf dieses Problem stößt, bin ich noch einen Schritt weiter gegangen und habe das Paket sanitize-html , um im Wesentlichen zu erfahren, was der Browser tut (beachten Sie, dass ich das JSDOM-Setup nicht importiert habe, da ich festgestellt habe, dass es nicht benötigt wird Wenn Sie dies in meine Jest-Setup-Datei einfügen, aber wenn Sie Jest nicht verwenden, sollten Sie das global.Element = (new JSDOM()).window.Element Setup verwenden, das @bennypowers empfohlen hat):

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
});

Alle 26 Kommentare

Und wie schade, dass die ausgeklügelte Selection und innerText Bibliothek nicht mit jsdom kompatibel https://github.com/timdown/rangy/issues/348

InnerText ist also kein Standard und nicht in mindestens einer wichtigen Engine (Firefox) implementiert. Ohne einen Standard sollten wir ihn meiner Meinung nach nicht implementieren.

Sieht so aus, als ob die ganze Sache mit einer Entwurfsspezifikation hier etwas in Bewegung Referenzen . Es gibt jedoch keine Probleme mit dem Repo, daher frage ich mich, wie vollständig es bereits ist / wie schnell der Fortschritt sein wird.

Firefox hat implementiert: https://bugzilla.mozilla.org/show_bug.cgi?id=264412

WHATWG scheint zu genehmigen: https://github.com/whatwg/compat/issues/5#issuecomment -168049752

Aus der Spezifikation geht hervor, dass wir innerText ohne grundlegende Layoutunterstützung nicht richtig implementieren können.

Ja, das wird in jsdom sowieso nicht wirklich umsetzbar sein, ohne viel Infrastrukturarbeit... niemand macht sich Hoffnungen :(.

Was die Anforderungen an die Layoutunterstützung betrifft: https://github.com/rocallahan/innerText-spec/issues/2

Gibt es einen Plan, dies aufgrund der Einführung der WHATWG zu implementieren?

Ja ... Obwohl die Spezifikation eine Menge Dinge erfordert, die jsdom nicht hat, um CSS-Boxen :(. Nicht sicher, was zu tun ist.

Gibt es eine Bibliothek dafür, die mit jsdom verbunden werden kann?

@domenic möchte ich wissen, warum dies eine solche Infrastrukturüberholung ist? Wir dachten, der 800 Pfund schwere Gorilla im Zimmer würde den Schlüssel verlassen. Aber es sieht so aus, als ob es nirgendwo hinführt. Wie Sie wissen, habe ich meinen Kopf in die Innereien von jsdom gewickelt. Wo wäre ein großartiger Ort im Repository, um mit der Überprüfung von Code für einen jsdom-Neuling zu beginnen?

Vielen Dank im Voraus 🙏 /cc @vsemozhetbyt

Das Hauptproblem ist die Tatsache, dass sich innerText zur Orientierung auf die Layout-Engine stützt und jsdom keine Layout-Engine hat. Siehe https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute und
http://perfectionkills.com/the-poor-misunderstood-innerText/ . Aus dem zweiten Link:

Beachten Sie, dass innerText fast genau die Darstellung von Text auf der Seite darstellt. textContent hingegen macht etwas Seltsames – es ignoriert Zeilenumbrüche, die von . erstellt wurden
und um als Block gestylte Elemente ( in diesem Fall).

Immer noch außerhalb des Geltungsbereichs und kein Workaround?

Offenbar sagt die Spezifikation:

Wenn dieses Element nicht gerendert wird oder wenn der Benutzeragent ein Nicht-CSS-Benutzeragent ist, gibt [Hervorhebung hinzugefügt] denselben Wert wie das textContent-IDL-Attribut für dieses Element zurück.

Ich denke, ein Workaround wäre, einfach textContent .

Wir implementieren genug CSS, das meiner Meinung nach nicht zutrifft. Wir implementieren nur die Layout-Teile nicht...

Hallo Leute, gibt es hierzu Neuigkeiten?

Verwenden Sie einfach kopfloses Chrom :)

@domenic aus dieser Spezifikation, die @coreh erwähnt hat:
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute

Wenn dieses Element nicht gerendert wird oder wenn der Benutzeragent ein Nicht-CSS-Benutzeragent ist, geben Sie denselben Wert wie das textContent IDL-Attribut für dieses Element zurück.

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

Ein Element wird gerendert, wenn es über verknüpfte CSS-Layout-Boxen, SVG-Layout-Boxen oder ein Äquivalent in anderen Stilsprachen verfügt.

Wenn jsdom Layoutteile nicht implementiert, bedeutet das nicht, dass "nicht gerendert" zutrifft?

Diese Nachricht richtet sich an alle, die diesen Github-Thread erreichen und nur eine Möglichkeit suchen, ihre Tests erfolgreich zu machen, ohne ihre Funktionsimplementierungen zu ändern.

Copypasta für den Anfang Ihrer Testdateien:

// 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;
  },
});

Natürlich gelten die Vorbehalte aus der obigen Diskussion.

Für den Fall, dass noch jemand auf dieses Problem stößt, bin ich noch einen Schritt weiter gegangen und habe das Paket sanitize-html , um im Wesentlichen zu erfahren, was der Browser tut (beachten Sie, dass ich das JSDOM-Setup nicht importiert habe, da ich festgestellt habe, dass es nicht benötigt wird Wenn Sie dies in meine Jest-Setup-Datei einfügen, aber wenn Sie Jest nicht verwenden, sollten Sie das global.Element = (new JSDOM()).window.Element Setup verwenden, das @bennypowers empfohlen hat):

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
});

Ich hatte ein ähnliches Bedürfnis, wollte aber etwas weiter gehen, als nur textContent - auch hier wird dies keine genaue Darstellung dessen sein, was Browser tatsächlich tun, insbesondere in Bezug auf Elemente, die von CSS ausgeblendet werden, aber es ist gut genug für meinen Anwendungsfall:

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
}

Was für eine Schande!

Offenbar sagt die Spezifikation:

Wenn dieses Element nicht gerendert wird oder wenn der Benutzeragent ein Nicht-CSS-Benutzeragent ist , gibt [Hervorhebung hinzugefügt] denselben Wert wie das textContent-IDL-Attribut für dieses Element zurück.

Ich denke, ein Workaround wäre dann, einfach textContent zurückzugeben.

Wir implementieren genug CSS, das meiner Meinung nach nicht zutrifft. Wir implementieren nur die Layout-Teile nicht...

@domenic bitte erwägen Sie eine liberalere Interpretation der Spezifikation

textContent ist explizit als Fallback erlaubt, wenn die Anwendung von CSS-Regeln zu teuer ist

außerdem wird innerText als getter und setter angegeben

Da ich der Spezifikationseditor bin, kann ich mit Sicherheit sagen, dass "wenn die Anwendung von CSS-Regeln zu teuer ist" nicht das ist, was die Spezifikation sagt.

.. das war meine Interpretation von "wenn der Benutzeragent ein Nicht-CSS-Benutzeragent ist"

Was ist der Unterschied zwischen einem "CSS-Benutzeragenten" und einem "Nicht-CSS-Benutzeragenten"?

wie wäre es mit:
ein CSS-Benutzeragent kann "CSS-Regeln anwenden" und das Ergebnis ausgeben (grafisch oder textuell)
ein Nicht-CSS-Benutzeragent ist zu dumm, um "CSS-Regeln anzuwenden"

Wir implementieren genug CSS, das meiner Meinung nach nicht zutrifft.

Was meinen Sie? window.getComputedStyle?

ein Fallback auf textContent ist immer noch besser, als keine Standardschnittstelle zu implementieren

Vielleicht können wir einfach den textContent verwenden, um das Ergebnis von innerText beim Ausführen von Tests durch jsdom zu ersetzen. Beispielsweise:

describe('mytest', () => {
  beforeAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'innerText', {
      get() {
        return this.textContent;
      }
    });
  });
  it('should ok', () => {
  // test assertions
  });
});
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen