jsdomは、Webスクレイピングに最適なツールです。 ただし、 textContent
は、html2text変換用の読み取り可能なテキストを取得するための非常に不便な方法です。
多くの場合、ごくわずかなinnerText
有用性についてのすばらしい記事があります。
http://perfectionkills.com/the-poor-misunderstood-innerText/
著者は、非常に遅い回避策としてgetSelection().toString()
を提案していますが、 getSelection
はまだjsdomに実装されていません。
jsdomにinnerText
を実装することを検討していただけますか? 著者はそれについて素晴らしい調査を行い、最後に簡単な仕様を追加しました。
rangyこととどのような残念Selection
とinnerText
:ライブラリはjsdomと互換性がありませんhttps://github.com/timdown/rangy/issues/348
したがって、innerTextは標準ではなく、少なくとも1つの主要なエンジン(Firefox)に実装されていません。 標準がなければ、実装すべきではないと思います。
仕様からすると、基本的なレイアウトのサポートなしではinnerText
適切に実装できないようです。
ええ、これはとにかくjsdomで実際に実装可能になることはなく、多くのインフラストラクチャの作業がなければ...誰も彼らの希望を得ることができません:(。
レイアウトサポート要件について: https :
WHATWGの採用により、実装する予定はありますか?
ええ...仕様にはjsdomにはない多くのものが必要ですが、CSSボックスの周り:(。何をすべきかわからない。
これをjsdomと一緒にプラグインするためのライブラリはありますか?
@domenicは、なぜこれがそのようなインフラストラクチャのオーバーホールであるかについての知識を落とす
よろしくお願いします🙏/ cc @vsemozhetbyt
主な問題は、 innerText
がガイダンスのためにレイアウトエンジンに依存しており、jsdomにはレイアウトエンジンがないという事実です。 https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attributeおよび
http://perfectionkills.com/the-poor-misunderstood-innerText/ 。 2番目のリンクから:
innerTextが、テキストがページにどのように表示されるかをほぼ正確に表していることに注目してください。 一方、textContentは奇妙なことをします—それはによって作成された改行を無視します
ブロックとしてスタイル設定された要素(この場合)の周囲ただし、マークアップで定義されているスペースは保持されます。
まだ範囲外で回避策はありませんか?
どうやら仕様は言う:
この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合、 [強調を追加]すると、この要素のtextContentIDL属性と同じ値が返されます。
回避策は、単にtextContent
返すことだと思います。
私たちは十分なCSSを実装しているので、それは当てはまらないと思います。 レイアウトパーツは実装していません...
こんにちはみんな、これに関するニュースはありますか?
ヘッドレスクロームを使用するだけです:)
@corehが言及したその仕様からの@domenic :
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute
この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合は、この要素の
textContent
IDL属性と同じ値を返します。
https://html.spec.whatwg.org/multipage/rendering.html#being -rendered
要素にCSSレイアウトボックス、SVGレイアウトボックス、または他のスタイル言語の同等のものが関連付けられている場合、その要素はレンダリングされます。
jsdom
がレイアウトパーツを実装していない場合、それは「レンダリングされていない」という意味ではありませんか?
このメッセージは、関数の実装を変更せずにテストに合格する方法が必要な、このgithubスレッドに到達した人を対象としています。
テストファイルの先頭のコピーパスタ:
// 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;
},
});
当然、上記の説明からの警告が適用されます。
他の誰かがこの問題に遭遇した場合、私はそれをさらに一歩進め、 sanitize-html
パッケージを使用して、基本的にブラウザーが実行していることを取得しました(JSDOMセットアップは不要であることがわかったため、インポートしなかったことに注意してください)これを私のJestセットアップファイルに入れるときですが、Jestを使用していない場合は、 @ benypowersが推奨するglobal.Element = (new JSDOM()).window.Element
セットアップを使用することをお勧めします):
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
});
私も同様のニーズがありましたが、 textContent
を使用するだけではなく、少し先に進みたいと思っていました。これも、特にcssによって隠された要素に関して、ブラウザーが実際に行うことを正確に表したものではありませんが、それは良いことです。私のユースケースには十分です:
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
}
お気の毒に!
どうやら仕様は言う:
この要素がレンダリングされていない場合、またはユーザーエージェントが非CSSユーザーエージェントである場合、[強調を追加]すると、この要素のtextContentIDL属性と同じ値が返されます。
回避策は、単にtextContentを返すことだと思います。
私たちは十分なCSSを実装しているので、それは当てはまらないと思います。 レイアウトパーツは実装していません...
@domenicは、仕様のより自由な解釈を検討してください
textContent
は、CSSルールの適用が高すぎる場合、フォールバックとして明示的に許可されます
また、innerTextはgetterおよびsetterとして指定されます
私がスペックエディターであることを考えると、「CSSルールの適用が高すぎる場合」はスペックが言っていることではないと確信を持って述べることができます。
..それは「ユーザーエージェントが非CSSユーザーエージェントである場合」の私の解釈でした
「CSSユーザーエージェント」と「非CSSユーザーエージェント」の違いは何ですか?
どうですか:
CSSユーザーエージェントは「CSSルールを適用」して結果を出力できます(グラフィックまたはテキスト)
非CSSユーザーエージェントは「CSSルールを適用する」にはあまりにも愚かです
私たちは十分なCSSを実装しているので、それは当てはまらないと思います。
どういう意味? window.getComputedStyle?
textContentへのフォールバックは、標準のインターフェースを実装しないよりも優れています
たぶん、 textContent
値を使用して、テストの実行中にinnerText
結果をjsdom
置き換えることができます。 例えば:
describe('mytest', () => {
beforeAll(() => {
Object.defineProperty(HTMLElement.prototype, 'innerText', {
get() {
return this.textContent;
}
});
});
it('should ok', () => {
// test assertions
});
});
最も参考になるコメント
他の誰かがこの問題に遭遇した場合、私はそれをさらに一歩進め、
sanitize-html
パッケージを使用して、基本的にブラウザーが実行していることを取得しました(JSDOMセットアップは不要であることがわかったため、インポートしなかったことに注意してください)これを私のJestセットアップファイルに入れるときですが、Jestを使用していない場合は、 @ benypowersが推奨するglobal.Element = (new JSDOM()).window.Element
セットアップを使用することをお勧めします):