Jsdom: implementasi innerText

Dibuat pada 25 Sep 2015  ·  26Komentar  ·  Sumber: jsdom/jsdom

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.

feature layout

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

Semua 26 komentar

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.

Sepertinya ada beberapa gerakan dalam semua ini dengan spesifikasi draf di sini . Lihat juga semua referensi . Tidak ada masalah pada repo, jadi saya ingin tahu seberapa lengkapnya / seberapa cepat kemajuannya.

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
  });
});
Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

machineghost picture machineghost  ·  4Komentar

kentmw picture kentmw  ·  3Komentar

josephrexme picture josephrexme  ·  4Komentar

tolmasky picture tolmasky  ·  4Komentar

philipwalton picture philipwalton  ·  4Komentar