Pada sebuah dokumen dengan paragraf terpanjang 151 karakter, jusText dengan pengaturan default menghasilkan nol karakter. Bukan ekstraksi yang kepotong — melainkan string kosong. Turunkan satu ambang sampai tepat satu paragraf lolos, dan dokumen yang sama langsung menghasilkan 832 karakter. Turunkan lagi, hasilnya tetap 832.
Pada fixture ini, perilakunya seperti jurang, bukan tanjakan bertahap. Apakah default-nya berada di sisi yang tepat atau malah salah sangat bergantung pada panjang paragraf dan sebaran boilerplate di korpus target.
Apa itu jusText, dan mengapa kepadatan leksikal penting
Dibanding extractor lain dalam set fixture ini, jusText sangat bergantung pada kepadatan stopword spesifik bahasa. Blok dengan porsi kata fungsi yang tinggi — seperti the, and, of, was — lebih mungkin merupakan teks artikel. Sinyal leksikal itu bukan satu-satunya penentu: panjang paragraf, kepadatan tautan, batas blok dari HTML, jarak ke heading, kelas tetangga, dan pemrosesan berbasis konteks juga ikut memengaruhi hasil.
Referensi resmi: repositori resmi jusText.

Karena classifier ini memakai daftar stopword per bahasa, jusText menyertakan 100 daftar. Lapisan leksikal spesifik bahasa yang eksplisit inilah pembeda paling jelas dalam perbandingan ini, meski kualitas multibahasa tidak diuji.
Versi yang diuji: 3.0.2, BSD 2-Clause, 822 bintang GitHub. Python 3.14.2.
Tebingnya, diukur

Classifier jusText berjalan dalam dua tahap. Tahap tanpa konteks memberi label tiap paragraf sebagai good, bad, short, atau neargood. Lalu tahap yang peka konteks menaikkan neargood menjadi good — tetapi hanya jika ia berada di sebelah blok yang sudah good. Sebuah paragraf hanya mendapat status good secara mandiri jika melewati length_high, yang default-nya 200 karakter.
Pada dokumen yang tidak ada paragrafnya melampaui 200 karakter, tidak ada yang menjadi pemicu promosi, dan setiap blok neargood jatuh menjadi boilerplate. Seluruh halaman kembali kosong.
Saya menyapu ambang pada fixture yang paragraf terpanjangnya 151 karakter:
length_high | Paragraf diklasifikasikan good | Karakter yang dikembalikan |
|---|---|---|
| 200 (default) | 0 | 0 |
| 150 | 8 | 832 |
| 120 | 8 | 832 |
| 100 | 8 | 832 |
| 80 | 8 | 832 |
justext-length-threshold.json.
Pada fixture ambang ini, satu paragraf yang melewati garis itu mengubah semua delapan paragraf target menjadi output, dan melonggarkan lagi tidak menambah apa pun. Trace-nya konsisten dengan tahap konteks yang menaikkan tetangga neargood yang memenuhi syarat di sekitar blok good yang sudah ada; ini tidak berarti semua tetangga akan dipromosikan tanpa syarat di halaman mana pun.
Sebelum mengaitkan perubahan itu ke length_high, saya menyapu length_low pada empat nilai yang dipadukan dengan max_link_density pada dua nilai: delapan kombinasi, semuanya menghasilkan nol. Mengubah salah satu dari dua pengaturan itu tidak mengembalikan output pada fixture ini.
Di seluruh set 22 fixture, polanya konsisten: 2 dari 22 fixture menghasilkan output pada length_high=200, 9 dari 22 pada 150, 15 dari 22 pada 120.
Ada dua hal yang bukan berarti demikian. Ini tidak berarti jusText bekerja buruk — pada halaman natural-language yang nyata dengan default, ia menghasilkan 1.190 karakter teks artikel yang bersih, karena paragraf berita yang nyata memang melewati 200 karakter sejak awal. Dan ini juga tidak berarti default itu salah; ini berarti default mengasumsikan paragraf yang panjang, dan kamu perlu menilai dulu apakah korpusmu seperti itu sebelum menjalankan apa pun.
Sisi lain dari set fixture ini: kebocoran lebih tinggi pada default
Pada set fixture berlabel ini dengan pengaturan default, jusText mencatat kebocoran boilerplate tertinggi.
| Library | Article recall (semua 22) | Boilerplate leak | Content-token precision | Contaminating tokens |
|---|---|---|---|---|
| Readability | 1.0000 | 0.2353 | 0.9109 | 35 |
| trafilatura | 0.9865 | 0.0588 | 0.9411 | 4 |
| newspaper4k | 0.9865 | 0.0000 | 0.9452 | 0 |
| resiliparse | 0.9054 | 0.0588 | 0.9381 | 7 |
| jusText | 0.8378 | 0.4706 | 0.8760 | 74 |
| goose3 | 0.8243 | 0.0000 | 1.0000 | 0 |
sixway-scores.json. Satu set fixture, satu scorer, setiap unit ditandai dengan sentinel unik sehingga pemulihan bisa dicek secara tepat lewat substring membership.

47% kebocoran boilerplate dan 74 token pengotor — dua kali lipat tingkat kebocoran Readability dan lebih dari dua kali kontaminasinya pada set sintetis berlabel ini. Ini adalah hasil diagnostik pada default, bukan peringkat produk yang stabil untuk semua kasus.
Kebocoran yang teramati konsisten dengan tahap konteks yang sama yang terlibat dalam efek tebing tadi. Blok neargood yang memenuhi syarat bisa dipromosikan jika kelas blok di sekitarnya dan aturan jaraknya memungkinkan; promo atau komentar yang mirip teks artikel di samping teks artikel bisa saja lolos melewati batas. Hasil fixture menunjukkan blok berlabel mana yang bocor, sementara mekanisme sederhananya tetap bersifat kondisional pada aturan konteks jusText yang spesifik.
Recall-nya 0.8378, ketiga dari bawah, dan seluruh kehilangan berasal dari ambang: ia tidak mengambil apa pun pada satu artikel 129 karakter, tidak mengambil apa pun pada halaman berisi sepuluh paragraf pendek, dan tidak mengambil apa pun pada dokumen yang nyaris kosong.
Inventaris stoplist bahasa
Sembilan puluh sembilan stoplist lain.
justext.get_stoplists() mengembalikan 100 bahasa. Classifier ini memang dirancang berbasis bahasa, bukan sekadar menerjemahkan heuristik bahasa Inggris, dan mengganti bahasa hanya perlu satu argumen:
import justext
paragraphs = justext.justext(html, justext.get_stoplist("Czech"))
text = "\n".join(p.text for p in paragraphs if not p.is_boilerplate)
trafilatura dan goose3 juga punya perilaku terkait bahasa, tetapi review ini tidak memberi skor pada extractor mana pun dengan ground truth non-Inggris. 100 stoplist bawaan jusText menjadikannya kandidat yang jelas untuk evaluasi multibahasa; inventaris saja tidak membuktikan kualitas ekstraksi di bahasa-bahasa itu, atau bahwa kompetitor menanganinya lebih buruk.
API-nya terdiri dari dua fungsi dan sembilan konstanta yang bisa diatur — length_low 70, length_high 200, stopwords_low 0.30, stopwords_high 0.32, max_link_density 0.20, max_heading_distance 200, plus penanganan encoding. Ringkas, mudah dibaca, dan semuanya terdokumentasi di signature.
Instalasi dan kecepatan
pip install justext menarik 3 paket — paling sedikit dalam perbandingan ini — dan 22.4 MiB, kurang dari dua detik.
Referensi resmi: jusText di PyPI.
| Library | Paket | site-packages | Cold import | Extraction p50 |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 s | 0.06 ms |
| jusText | 3 | 22.4 MiB | 0.777 s | 0.56 ms |
| goose3 | 16 | 44.3 MiB | 2.181 s | 1.85 ms |
| newspaper4k | 22 | 47.5 MiB | 2.812 s | 2.69 ms |
| trafilatura | 17 | 69.9 MiB | 1.584 s | 0.51 ms |
install-and-import.json. Masing-masing library berada di virtualenv kosong tersendiri.
Tiga paket dan 22.4 MiB adalah dependensi kecil dalam perbandingan ini, dan median ekstraksi 0.56 ms cukup dekat dengan 0.51 milik trafilatura dalam harness ini. Pengukuran lingkungan tidak memisahkan ukuran paket berdasarkan tipe file, jadi tidak bisa mengatakan berapa banyak jejak disk yang berasal dari stoplist.
Pertanyaan pemeliharaan, dijawab dengan hati-hati
Ukuran pemeliharaan berbasis tanggal yang dipakai di sini adalah push repositori terakhir dan rilis PyPI terakhir, keduanya 2025-02-25. Itu tujuh belas bulan sebelum pengujian. Total delapan rilis, 91 fork, 9 isu terbuka, tidak diarsipkan.
Classifier PyPI mencantumkan dukungan Python sampai 3.9. Saya menjalankannya di 3.14.2 dan ia terpasang, ter-import dalam 0.777 s, lalu mengekstrak pada 19 dari 22 fixture tanpa satu exception pun.
Jadi metadata-nya tertinggal lima versi Python dari kenyataan, dan kenyataannya adalah ia tetap bekerja. Itulah perbedaan yang berguna: repositori yang sepi adalah sinyal tentang dukungan, bukan otomatis tentang fungsi. Untuk library yang seluruh algoritmanya adalah metode publik 2011 ditambah seperangkat word list, status "selesai" itu masuk akal — tidak banyak lagi yang perlu diubah, dan stoplist tidak membusuk seperti workaround anti-bot.
Apa arti repo yang sepi: kalau kamu menemukan bug, kamu memperbaikinya sendiri atau melakukan fork. Timbang itu dengan sembilan isu terbuka, yang bukan profil library yang tenggelam dalam masalah yang belum ditangani.
Memori, dan apa yang dilakukan HTML rusak terhadapnya
Dua pertanyaan operasional diukur terpisah di sini.
Konteks stress-test yang lebih luas ada di perbandingan memori dan HTML cacat untuk sepuluh library.
Peak resident memory, via /usr/bin/time -l, satu proses baru per sel — import floor adalah biaya library saat dimuat dan idle, sedangkan peak sudah termasuk dokumen.
| Library | Runtime | Import floor | 226 KB peak | 10 MB peak |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json. Baseline Python dan Node tidak bisa dibandingkan langsung satu sama lain; interpreter ada di dalam keduanya.
Import floor jusText adalah 30.3 MiB dan peak-nya pada fixture 10 MB ini 431.2 MiB, sekitar 14.2 kali floor import dan 43.1 kali ukuran input dalam RSS absolut. Satu fixture dan satu proses tidak cukup untuk menetapkan kurva skala umum; baseline Python dan Node juga tetap tidak sebanding.
HTML rusak. Dua belas dokumen, masing-masing merusak tepat satu hal — tag tak ditutup, inline element yang salah nesting, atribut tanpa tanda kutip dengan spasi, penutup nyasar, tanpa <html> sama sekali, atribut duplikat, dokumen terpotong di tengah tag, entity yang rusak, <script> tak tertutup, deklarasi charset yang menyesatkan, komentar yang berisi markup, dan nesting 600 lapis — plus dua kontrol yang well-formed pada ukuran yang sama, karena "hasilnya nol" hanya bermakna tentang malformedness jika library itu juga diam pada dokumen bersih dengan ukuran yang sama.
justext melempar exception pada 0 dari 14 dan mengembalikan kosong pada 13, memulihkan 0/33 sentinel yang dinilai di seluruh fixture rusak (malformed-results.json). Kontrol pendek yang well-formed juga mengembalikan 0 karakter; kontrol panjang yang well-formed menjadi satu-satunya hasil non-kosong dengan 1.333 karakter. Semua dua belas fixture rusak tetap kosong, dan kasus <script> yang tidak tertutup dikecualikan dari scoring survivability sentinel. Batch ini menunjukkan toleransi parser — tanpa exception — tetapi tidak bisa mengatribusikan diamnya hasil pada malformedness, bukan pada ambang ukuran yang sudah diukur sebelumnya.
Kelebihan dan kekurangan
Kelebihan. 100 stoplist bahasa, dan classifier yang benar-benar dibangun di sekitarnya, bukan sekadar diterjemahkan ke dalamnya. Jumlah dependensi paling kecil dalam perbandingan ini, hanya 3 paket. Ekstraksi median 0.56 ms. Sembilan konstanta tuning yang terdokumentasi dan mudah dibaca. BSD 2-Clause. Berjalan mulus di Python 3.14 meski classifier PyPI berhenti di 3.9.
Kekurangan. Kebocoran boilerplate tertinggi dalam tes sintetis ini pada default: 47%, dengan 74 token pengotor. Fixture paragraf pendek mengembalikan string kosong saat tidak ada paragraf yang melewati length_high. Recall 0.8378 pada set ini. Push repositori terakhir dan rilis terakhir tercatat tujuh belas bulan sebelum pengujian, jadi kepemilikan pemeliharaan perlu dipertimbangkan.
Siapa yang sebaiknya memakai, dan siapa yang sebaiknya tidak
Evaluasi jusText untuk korpus multibahasa karena permukaan stoplist spesifik bahasa memang eksplisit dan luas. Tes ini menginventarisasi 100 stoplist tetapi tidak mengukur kualitas multibahasa. Ia juga kandidat yang baik ketika dependensi 3 paket dan kontrol threshold yang eksplisit cocok untuk deployment.
Lewatkan jika kamu memasok model per token, karena 74 token pengotor dibanding nol pada goose3 dan newspaper4k adalah biaya langsung. Lewatkan untuk halaman dengan paragraf pendek — blurb produk, listing, changelog, entri FAQ — kecuali kamu memang sengaja mengatur length_high. Dan lewatkan jika kamu butuh dependensi yang aktif dipelihara demi alasan kepatuhan atau procurement, yang memang batasan nyata meski kodenya bekerja.
Kalau tetap memakainya, sesuaikan length_high dengan sampel validasi berlabel, bukan menyalin default atau aturan persentil. Uji beberapa ambang yang masuk akal dan ukur baik recall artikel maupun precision boilerplate; menurunkan gerbang bisa menyelamatkan prosa pendek sekaligus ikut mempromosikan blok tetangga yang tidak diinginkan.
Di mana API terkelola cocok
jusText memakai HTML yang sudah kamu miliki, seperti semua library dalam perbandingan ini. Tidak satu pun dari library ini mengambil halaman, merender JavaScript, atau menangani lapisan anti-bot.
Untuk fixture yang sama di seluruh enam extractor, lihat perbandingan ekstraksi enam library.
Layanan hosted fetch/render/extraction, termasuk Thunderbit milik kami, punya batas tanggung jawab yang berbeda. Thunderbit tidak dibenchmark di sini. Pembedanya adalah klasifikasi prosa dari HTML yang disediakan versus layanan yang mengambil dan memproses URL; artikel ini tidak memberi perbandingan kualitas dengan metrik yang sama.
Framing yang jujur: stoplist multibahasa jusText adalah kemampuan nyata dan gratis. Kalau masalahmu adalah mengambil halaman dalam banyak bahasa, bukan mengklasifikasikan prosa di dalamnya, itu pembelian yang berbeda.
Untuk lanskap yang lebih luas, roundup web scraping API kami membahas opsi hosted dan pillar open-source scraper membahas yang self-hosted. Jika output ditujukan ke model, mengonversi HTML ke Markdown di Python adalah titik di mana sebagian besar fidelitas hilang.
Coba Thunderbit untuk Ekstraksi Data Web
Apakah kamu harus memakai jusText?
Ini kandidat kalau korpusnya multibahasa atau distribusi panjang paragrafnya memang cocok untuk tuning ambang yang eksplisit. Validasi kedua sifat itu sebelum deployment.
100 stoplist bawaan adalah fitur desain yang nyata, tetapi akurasi multibahasa tidak diuji. Tebing ambang itu bisa disetel; apakah nilai yang lebih rendah bisa diterima bergantung pada recall dan precision boilerplate yang diukur pada sampel berlabel.
Pada set sintetis bahasa Inggris ini dengan default, newspaper4k tidak membocorkan satu pun unit boilerplate berlabel dan memulihkan 0.9865 unit artikel. Itu menjadikannya kandidat pembanding untuk beban kerja ini, bukan rekomendasi pengganti universal.
Coba Thunderbit untuk Ekstraksi Data Web Get Started Free
FAQ
Mengapa jusText mengembalikan string kosong, bukan ekstraksi sebagian?
Classifer-nya punya dua tahap. Sebuah paragraf hanya mendapat kelas good secara mandiri jika berada di atas length_high (default 200 karakter); tahap kedua lalu mempromosikan blok tetangga neargood. Kalau tidak ada paragraf yang melewati ambang, tidak ada seed, sehingga semua kandidat turun menjadi boilerplate dan hasilnya kosong. Ini memang all-or-nothing sejak desainnya, bukan gagal menemukan jawaban parsial.
Apakah jusText ditinggalkan? Push repositori terakhir dan rilis PyPI terakhir sama-sama pada 2025-02-25 — tujuh belas bulan sebelum pengujian — dan classifier PyPI berhenti di Python 3.9. Namun ia terpasang dan berjalan di Python 3.14.2 tanpa exception, dan 9 isu terbuka bukan backlog yang besar. Baca tanggal-tanggal itu sebagai risiko pemeliharaan, bukan bukti perilaku yang rusak; risiko praktisnya adalah kamu mungkin perlu memperbaiki bug sendiri.
Mengapa kebocoran boilerplate-nya lebih besar daripada Readability? Pada set fixture ini, blok tetangga yang mirip prosa dan memenuhi syarat melewati batas output di bawah aturan konteks default. Promosi bergantung pada kelas blok, jarak, dan konteks, bukan otomatis untuk setiap tetangga. Hasil terukurnya adalah kebocoran unit boilerplate 47% dan 74 token pengotor pada default.
Bagaimana cara memakainya untuk bahasa lain?
justext.justext(html, justext.get_stoplist("German")). get_stoplists() mengembalikan seluruh 100 yang tersedia. Stoplist adalah input leksikal spesifik bahasa untuk classifier yang juga memakai panjang paragraf, kepadatan tautan, segmentasi dari HTML, jarak ke heading, dan konteks blok tetangga. Ini mengubah input bahasa; itu sendiri tidak memvalidasi kualitas ekstraksi bahasa Jerman.
Apa yang tidak diuji di sini?
Halaman nyata, sama sekali — ini adalah fixture terkontrol dengan unit berlabel. Kemampuan multibahasa, yang merupakan nilai jual utama library ini, diinventarisasi pada 100 stoplist tetapi tidak diberi skor pada teks non-Inggris. Kasus batas encoding, meski jusText menyediakan parameter encoding, default_encoding, dan enc_errors. Dan max_heading_distance serta dua threshold rasio stopword dibiarkan pada default sepanjang pengujian.


