jsdom adalah alat yang hebat untuk web scraping. Namun textContent
adalah cara yang sangat merepotkan untuk mendapatkan teks yang dapat dibaca untuk konversi html2text.
Ada artikel bagus tentang kegunaan innerText
dapat diabaikan dalam banyak kasus:
http://perfectionkills.com/the-poor-misunderstood-innerText/
Penulis menyarankan getSelection().toString()
sebagai solusi yang sangat lambat, tetapi getSelection
belum diimplementasikan di jsdom .
Bisakah Anda mempertimbangkan penerapan innerText
di jsdom ? Penulis telah melakukan eksplorasi hebat tentangnya, dia bahkan menambahkan spesifikasi sederhana di bagian akhir.
Dan sayang sekali pustaka Selection
dan innerText
rangy tidak kompatibel dengan https://github.com/timdown/rangy/issues/348
Jadi, innerText tidak standar, dan tidak diimplementasikan di setidaknya satu mesin utama (Firefox). Tanpa standar, saya rasa kita tidak perlu menerapkannya.
Firefox telah menerapkan: https://bugzilla.mozilla.org/show_bug.cgi?id=264412
WHATWG harus disetujui: https://github.com/whatwg/compat/issues/5#issuecomment -168049752
Dari spek sepertinya kami tidak dapat mengimplementasikan innerText
dengan benar tanpa dukungan tata letak dasar.
Ya, ini tidak akan benar-benar dapat diterapkan di jsdom, tanpa banyak pekerjaan infrastruktur ... tidak ada yang terlalu berharap :(.
Mengenai persyaratan dukungan tata letak: https://github.com/rocallahan/innerText-spec/issues/2
Apakah ada rencana untuk mengimplementasikannya karena adopsi WHATWG?
Ya... Meskipun spesifikasi membutuhkan banyak hal yang tidak dimiliki jsdom, di sekitar kotak CSS :(. Tidak yakin apa yang harus dilakukan.
Apakah ada lib untuk ini untuk dihubungkan dengan jsdom?
@domenic care untuk memberikan sedikit pengetahuan tentang mengapa ini merupakan perbaikan infrastruktur? Kami pikir gorila seberat 800 pon di ruangan itu akan meninggalkan lo-key. Tapi sepertinya tidak kemana-mana. Seperti yang Anda tahu telah membungkus kepalaku di sekitar jeroan jsdom. Di mana tempat yang bagus di repo untuk mulai meninjau kode ke jsdom newb?
Terima kasih sebelumnya 🙏 /cc @vsemozhetbyt
Masalah utama adalah fakta bahwa innerText
bersandar pada mesin tata letak untuk panduan, dan jsdom tidak memiliki mesin tata letak. Lihat https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute dan
http://perfectionkills.com/the-poor-misunderstood-innerText/ . Dari tautan kedua:
Perhatikan bagaimana innerText hampir secara tepat merepresentasikan dengan tepat bagaimana teks muncul di halaman. textContent, di sisi lain, melakukan sesuatu yang aneh — mengabaikan baris baru yang dibuat oleh
dan di sekitar elemen styled-as-block ( dalam kasus ini).
Masih di luar jangkauan dan tidak ada solusi?
Rupanya spesifikasi mengatakan:
Jika elemen ini tidak dirender, atau jika agen pengguna adalah agen pengguna non-CSS, [penekanan ditambahkan] maka kembalikan nilai yang sama dengan atribut IDL textContent pada elemen ini.
Saya pikir solusinya adalah dengan mengembalikan textContent
.
Kami menerapkan cukup banyak CSS yang menurut saya tidak berlaku. Kami hanya tidak menerapkan bagian tata letak ...
Hi guys, ada kabar tentang yang satu ini?
Cukup gunakan chrome tanpa kepala :)
@domenic dari spesifikasi yang disebutkan @coreh :
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute
Jika elemen ini tidak dirender , atau jika agen pengguna adalah agen pengguna non-CSS, maka kembalikan nilai yang sama dengan atribut
textContent
IDL pada elemen ini.
https://html.spec.whatwg.org/multipage/rendering.html#being -rendered
Sebuah elemen sedang dirender jika memiliki kotak tata letak CSS terkait, kotak tata letak SVG, atau yang setara dalam bahasa gaya lainnya.
Jika jsdom
tidak mengimplementasikan bagian tata letak, bukankah itu berarti "tidak dirender" berlaku?
Pesan ini untuk siapa saja yang mencapai utas github ini yang hanya ingin cara agar tes mereka lulus tanpa mengubah implementasi fungsinya.
copypasta untuk bagian atas file pengujian Anda:
// 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;
},
});
Tentu saja, peringatan dari diskusi di atas berlaku.
Jika ada orang lain yang mengalami masalah ini, saya mengambilnya 1 langkah lebih jauh dan menggunakan paket sanitize-html
untuk mendapatkan pada dasarnya apa yang dilakukan browser (perhatikan saya tidak mengimpor pengaturan JSDOM karena saya merasa itu tidak diperlukan ketika meletakkan ini di file pengaturan Jest saya tetapi jika Anda tidak menggunakan Jest maka Anda akan ingin menggunakan pengaturan global.Element = (new JSDOM()).window.Element
yang direkomendasikan @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
});
saya memiliki kebutuhan yang sama tetapi ingin melangkah lebih jauh dari sekadar menggunakan textContent
- sekali lagi, ini tidak akan menjadi representasi akurat dari apa yang sebenarnya dilakukan browser, terutama sehubungan dengan elemen yang disembunyikan oleh css, tetapi itu bagus cukup untuk kasus penggunaan saya:
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
}
Sayang sekali!
Rupanya spesifikasi mengatakan:
Jika elemen ini tidak dirender, atau jika agen pengguna adalah agen pengguna non-CSS , [penekanan ditambahkan] maka kembalikan nilai yang sama dengan atribut IDL textContent pada elemen ini.
Saya pikir solusinya adalah dengan mengembalikan textContent.
Kami menerapkan cukup banyak CSS yang menurut saya tidak berlaku. Kami hanya tidak menerapkan bagian tata letak ...
@domenic tolong pertimbangkan interpretasi spesifikasi yang lebih liberal
textContent
secara eksplisit diperbolehkan sebagai fallback, ketika penerapan aturan CSS terlalu mahal
juga, innerText ditentukan sebagai pengambil dan penyetel
Mengingat bahwa saya adalah editor spesifikasi, saya dapat menyatakan dengan pasti bahwa "bila penerapan aturan CSS terlalu mahal" bukanlah apa yang dikatakan oleh spesifikasi tersebut.
.. itu interpretasi saya tentang "jika agen pengguna adalah agen pengguna non-CSS"
apa perbedaan antara "agen pengguna CSS" dan "agen pengguna non-CSS"?
bagaimana dengan:
agen pengguna CSS dapat "menerapkan aturan CSS" dan menampilkan hasilnya (grafik atau tekstual)
agen pengguna non-CSS terlalu bodoh untuk "menerapkan aturan CSS"
Kami menerapkan cukup banyak CSS yang menurut saya tidak berlaku.
Apa maksudmu? window.getComputedStyle?
mundur ke textContent masih lebih baik daripada tidak mengimplementasikan antarmuka standar
Mungkin kita bisa menggunakan nilai textContent
untuk mengganti hasil innerText
saat menjalankan tes dengan jsdom
. Sebagai contoh:
describe('mytest', () => {
beforeAll(() => {
Object.defineProperty(HTMLElement.prototype, 'innerText', {
get() {
return this.textContent;
}
});
});
it('should ok', () => {
// test assertions
});
});
Komentar yang paling membantu
Jika ada orang lain yang mengalami masalah ini, saya mengambilnya 1 langkah lebih jauh dan menggunakan paket
sanitize-html
untuk mendapatkan pada dasarnya apa yang dilakukan browser (perhatikan saya tidak mengimpor pengaturan JSDOM karena saya merasa itu tidak diperlukan ketika meletakkan ini di file pengaturan Jest saya tetapi jika Anda tidak menggunakan Jest maka Anda akan ingin menggunakan pengaturanglobal.Element = (new JSDOM()).window.Element
yang direkomendasikan @bennypowers ):