html2text chỉ cài một gói với dung lượng 0,2 MiB — nhỏ hơn chín lần so với lựa chọn Python gần nhất và nhỏ hơn bốn mươi lần so với lựa chọn Node. Công cụ này hoàn thành cả bốn trang trong bộ chuyển đổi và giữ nguyên toàn bộ 16 probe nội dung thân được đăng ký. Các probe này chỉ kiểm tra xem những chuỗi body được chọn có còn xuất hiện hay không; chúng không chấm điểm cấu trúc phân cấp, mức độ lồng danh sách, đích liên kết, nội dung lặp lại hay độ chính xác đầy đủ của bảng.
Công cụ này cũng được cấp phép theo GPL-3.0-or-later, đây là đặc điểm duy nhất trong phép so sánh này không xuất hiện trong bất kỳ benchmark nào nhưng lại có thể khiến một thư viện bị loại hoàn toàn.
html2text là gì
html2text là một thư viện Python chuyển HTML sang văn bản gần giống Markdown. Nguồn gốc của nó bắt đầu từ bản gốc của Aaron Swartz, và nhánh được duy trì hiện tại đang ở 2025.4.15 — một bản phát hành gắn theo ngày từ tháng 4/2025, với 2.168 sao GitHub, 95 issue đang mở và lần đẩy mã gần nhất vào tháng 10/2025.
Tham chiếu chính thức: kho lưu trữ chính thức của html2text.
import html2text
h = html2text.HTML2Text()
h.body_width = 0 # xem bên dưới; giá trị mặc định sẽ khiến bạn bất ngờ
md = h.handle(html)
pip install html2text kéo về 1 gói và 0,2 MiB, với thời gian import lạnh là 0,077 s. Không có phụ thuộc nào. Trong image container hoặc Lambda layer, đây là khác biệt rất đáng kể so với markdownify (1,8 MiB) và turndown (8,8 MiB).
Mặc định làm thay đổi mọi con số

body_width mặc định là 78. html2text sẽ tự ngắt dòng mọi dòng đầu ra ở mốc 78 ký tự trừ khi bạn tắt tính năng này.
Đây là một mặc định hợp lý nếu thư viện ban đầu được dùng để tạo văn bản dễ đọc cho terminal và email. Nhưng nó là lựa chọn không phù hợp nếu đầu ra được đưa vào mô hình hoặc so sánh diff, vì các dòng xuống mới sẽ làm thay đổi token hóa, cắt đôi URL dài và khiến việc đối chiếu kết quả trở nên vô nghĩa.
Tôi đặt body_width = 0 cho toàn bộ phần dưới đây và nói rõ điều này thay vì giấu đi: nếu bật ngắt dòng, mọi con số đếm ký tự và token trong bài viết này sẽ khác. Nếu bạn tự benchmark các bộ chuyển đổi, đây chính là thiết lập có thể âm thầm làm cho số liệu của bạn không còn so sánh được nữa.
Cách đo lường
Tôi chạy html2text trên một bộ chuyển đổi bốn trang có tên cụ thể, cũng được dùng trong bài so sánh markitdown, với chuỗi probe được đăng ký trước — những chuỗi body được chọn mà phải còn sống, và các chuỗi boilerplate mà nếu còn xuất hiện thì chứng tỏ phần khung trang đã được giữ lại. Cùng bốn tệp, cùng probe, một bộ chấm điểm cho cả bốn bộ chuyển đổi. Việc probe còn hay mất chỉ đo sự hiện diện chuỗi đã đăng ký, không đo độ đúng về cấu trúc; cột bảng và liên kết được tách riêng chính vì lý do đó.
| Bộ chuyển đổi | Probe body | Số ký tự đầu ra | Token (o200k) | Số dòng bảng Markdown | Liên kết |
|---|---|---|---|---|---|
| html2text | 16/16 | 76.452 | 21.176 | 32 | 545 |
| markdownify | 16/16 | 76.868 | 21.062 | 36 | 599 |
| markitdown | 16/16 | 76.995 | 21.336 | 36 | 598 |
| turndown | 16/16 | 95.188 | 26.236 | 0 | 611 |
fourway-scores.json. Bốn fixture, token được tính bằng o200k_base.
Đầu ra nhỏ nhất trong bốn công cụ với 76.452 ký tự, và gần như ngang bằng về token với markdownify và markitdown — 21.176 so với 21.062 và 21.336, chênh lệch 1,3% nên tôi sẽ không gọi đó là khác biệt đáng kể.
32 dòng bảng so với 36 của markdownify và markitdown trong bộ bốn trang. Khoảng cách bốn dòng xuất hiện ở fixture Wikipedia bất quy tắc, chứ không phải ở khác biệt định dạng outer-pipe được nói đến ngay sau đây.
Ít liên kết nhất, 545, so với 598 đến 611 ở các công cụ còn lại. Nếu việc giữ lại liên kết quan trọng, hãy kiểm tra trên chính các trang của bạn — đây là cột mà html2text nằm thấp hơn nhóm còn lại một cách rõ ràng.
Những bảng mà regex của tôi không nhìn thấy được

Phần này đáng kể lại vì tôi suýt nữa đã công bố sai kết luận.
Bộ đếm số dòng bảng đầu tiên của tôi yêu cầu có dấu | ở đầu và cuối — ^\|.*\|$. Theo quy tắc đó, html2text chỉ đạt 1 dòng bảng trên năm tệp: bốn tệp trong bộ chuyển đổi bốn trang cộng thêm một fixture bảng phức hợp tổng hợp riêng. Bộ đếm đó đang đo một kiểu Markdown chứ không đo bảng.

Nó có tạo bảng. Nó xuất ra kiểu như sau:
Team Name | Year | Wins | Losses | Win %
---|---|---|---|---
Boston Bruins | 1990 | 44 | 24 | 0.55
Không có dấu | bên ngoài. Đây là cú pháp pipe-table thông dụng, nhưng harness của tôi không kiểm tra tương thích qua các Markdown renderer. Regex chỉ tìm kiểu có outer-pipe sẽ không thấy nó. Khi viết lại bộ đếm để tìm một cụm dòng có dấu | kèm theo một dòng phân cách ở giữa, html2text tăng từ 1 dòng lên 32 trong bộ bốn trang và 91 trên toàn bộ năm tệp.
Vì vậy, kết luận không phải là html2text không hỗ trợ bảng. Mà là hai trong bốn bộ chuyển đổi này xuất outer pipes còn một bộ thì không, điều này rất quan trọng nếu bạn hậu xử lý Markdown bằng pattern matching của riêng mình. Đây là chi tiết rất đáng biết và tôi đã có thể bỏ lỡ hoàn toàn nếu tin vào con số đầu tiên của mình.
Nó loại bỏ gì, và ở đâu thì mất dòng
Hai phát hiện đi theo hai hướng ngược nhau.
Nó loại bỏ <script> và <style>. Khi đếm bằng các marker chỉ xuất hiện bên trong những phần tử này, đầu ra của html2text trên toàn bộ fixture có 0 marker script và 0 marker style. Đầu ra của turndown thì có 10 và 84 — ở fixture Wikipedia, tám dòng cấu hình JavaScript nội tuyến của MediaWiki và CSS chiếm 14.644 ký tự (script-style-stripping.json). Với đầu ra ràng buộc bởi mô hình, đây là nguồn text thừa lớn nhất quan sát được trên fixture này. Không có mô hình chi phí phát sinh nào ở phía sau được đo lường.
Nó làm rơi dòng bảng ở trang khó. Bộ bốn trang cho ra kết quả như sau:
| Fixture | html2text | markdownify |
|---|---|---|
| Books to Scrape | 0 dòng | 0 dòng |
| Quotes to Scrape | 0 dòng | 0 dòng |
| Hockey statistics | 27 dòng | 27 dòng |
| Wikipedia | 5 dòng | 9 dòng |
| Tổng bốn trang | 32 dòng | 36 dòng |
Fixture bảng phức hợp tổng hợp riêng cộng thêm 59 dòng cho html2text và 62 dòng cho markdownify, đưa tổng của năm tệp lên 91 và 98. Nó không tính vào so sánh chính của bốn trang. Hai công cụ này ngang nhau ở bảng hockey sạch sẽ. Trên Wikipedia, nơi các bảng được lồng và không đều, html2text chỉ xuất 5 dòng trong khi markdownify xuất 9.
Mẫu chung là: bảng đơn giản thì giống nhau; bảng rối thì html2text giữ được ít hơn. Nếu trang của bạn có loại bảng như Wikipedia, hãy thử trước khi chốt. Nếu chúng giống bảng của trang thống kê, hai công cụ này thay thế được nhau ở khía cạnh này.
Giấy phép
| Thư viện | Giấy phép | Gói | Dung lượng |
|---|---|---|---|
| html2text | GPL-3.0-or-later | 1 | 0,2 MiB |
| markdownify | MIT | 5 | 1,8 MiB |
| turndown | MIT | 3 (npm) | 8,8 MiB |
Tham chiếu chính thức: html2text trên PyPI.
Đã được xác nhận ở ba nơi: metadata trên PyPI, kho GitHub và file METADATA của gói đã cài, trong đó ghi License-Expression: GPL-3.0-or-later.
Điều đó có ý nghĩa thế nào còn tùy vào cách phần mềm được tích hợp, phân phối và phát hành. Việc sử dụng nội bộ hoặc chỉ qua mạng thường là một bối cảnh GPL khác với việc phát hành phần mềm có bao gồm hoặc kết hợp với gói này, nhưng bài viết này không phải phân tích pháp lý. Các đội ngũ phân phối phần mềm nên nhờ luật sư xem xét mô hình tích hợp và phân phối cụ thể.
Điều khó xử là mối tương quan này. Thư viện có footprint nhỏ nhất, thứ mà bạn sẽ chọn chính vì muốn giữ artifact có thể phân phối ở mức nhỏ, lại là thư viện có giấy phép hạn chế việc phân phối mạnh nhất. Hai lựa chọn thay thế đều là MIT.
Tôi không phải luật sư và đây không phải lời khuyên — chỉ là sự thật, có nguồn dẫn, vì đây là đặc điểm có khả năng quan trọng nhất nhưng lại ít xuất hiện nhất trong bảng so sánh.
Bảo trì
Bản phát hành gần nhất 2025.4.15, lần đẩy mã gần nhất vào tháng 10/2025 — khoảng mười tháng trước thời điểm thử nghiệm, với 41 bản phát hành phía sau nó. requires_python >= 3.9, và thư viện cài đặt cũng như chạy ổn trên Python 3.14.2.
Điều đó yên ắng hơn markdownify (bản phát hành gần nhất là sáu tuần trước khi thử nghiệm) và turndown (bốn tháng), nhưng vẫn hoạt động nhiều hơn là không. Với một thư viện chuyển HTML sang text — một bài toán không thay đổi quá nhanh — khoảng cách mười tháng cho cảm giác ổn định hơn là bị bỏ rơi. 95 issue đang mở là con số đáng chú ý hơn, và bạn nên lướt qua chúng để xem có gì giống use case của mình trước khi quyết định.
Bộ nhớ và HTML lỗi làm nó ra sao
Hai câu hỏi vận hành được đo riêng ở đây.
Bối cảnh stress-test rộng hơn nằm trong bài so sánh bộ nhớ và HTML lỗi của mười thư viện.
Bộ nhớ cư trú cực đại, đo bằng /usr/bin/time -l, mỗi ô là một tiến trình mới — mức import floor là chi phí của thư viện khi đã nạp nhưng đang chờ, còn mức peak bao gồm cả tài liệu.
| Thư viện | Runtime | Import floor | Peak 226 KB | Peak 10 MB |
|---|---|---|---|---|
| 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 và Node không thể so sánh trực tiếp với nhau; bản thân interpreter đã nằm trong cả hai.
html2text là mục nhẹ nhất ở cả hai trục đo lường này. Mức import floor 18,7 MiB và peak 71,2 MiB trên fixture 10 MiB cho ra RSS tăng thêm 52,5 MiB: (71,2 - 18,7) / 10 = 5,25× kích thước fixture. Hãy so sánh điều đó với các dòng tuyệt đối và gia tăng trong bảng, đồng thời nhớ đến lưu ý về baseline Python/Node đã nêu.
HTML lỗi. Mười hai tài liệu, mỗi tài liệu hỏng đúng một thứ — thẻ chưa đóng, phần tử inline lồng sai, thuộc tính không đặt ngoặc kép nhưng có khoảng trắng, thẻ đóng dư, không có <html>, thuộc tính trùng lặp, tài liệu bị cắt cụt giữa thẻ, entity sai, một <script> chưa đóng, khai báo charset nói dối, một comment chứa markup, và độ sâu lồng tới 600 lớp — cộng thêm hai tài liệu chuẩn làm đối chứng ở kích thước tương ứng, vì “nó không trả về gì” chỉ có ý nghĩa về mức độ lỗi nếu thư viện cũng im lặng trên một tài liệu sạch có cùng kích thước.
html2text báo lỗi trên 0/14 và không trả về gì trên 0, đồng thời khôi phục 33/33 sentinel trên các fixture bị hỏng (malformed-results.json). Một fixture bị loại khỏi phép đếm này: theo HTML5, mọi thứ sau một <script> chưa đóng thực sự là nội dung script, nên việc mất chúng ở đó là đúng, còn khôi phục lại mới là lệch chuẩn.
Ưu và nhược điểm
Điểm mạnh. Một gói, 0,2 MiB, không phụ thuộc — nhỏ nhất áp đảo trong so sánh này. Đầu ra nhỏ nhất trong bốn công cụ và gần như ngang token với markdownify và markitdown. Xuất được cú pháp pipe-table dễ nhận biết. Chạy trên Python 3.14. Dòng phát triển lâu đời và ổn định.
Điểm yếu. GPL-3.0-or-later, trong khi các lựa chọn thay thế thì không. body_width=78 theo mặc định, nên đầu ra sẽ bị xuống dòng cứng và làm thay đổi số liệu hoặc diff nếu không tắt. Giữ lại ít liên kết nhất (545 so với 598–611). Bảng dùng kiểu không có outer-pipe, dễ làm hỏng regex hậu xử lý đơn giản. 95 issue đang mở và nhịp phát hành chậm hơn markdownify.
Ai nên dùng và ai không nên dùng
Nên dùng html2text khi ngân sách phụ thuộc thực sự chặt và mô hình tích hợp/phân phối dự kiến đã được xem xét giấy phép. Một gói với zero dependencies là lợi thế vận hành thật sự: bề mặt phụ thuộc nhỏ hơn để kiểm tra và triển khai.
Đặt body_width = 0 ở dòng đầu tiên, trừ khi bạn cố tình muốn văn bản thô có ngắt dòng.
Không nên dùng nếu bạn phân phối phần mềm và copyleft là vấn đề — markdownify là MIT, có token gần như tương đương ở đây, và khớp với markitdown về bảng với dung lượng đĩa nhiều hơn 1,6 MiB. Cũng nên bỏ qua nếu việc giữ liên kết quan trọng với bạn, vì đây là công cụ giữ ít liên kết nhất. Và bỏ qua nếu công cụ downstream của bạn giả định mỗi dòng bảng đều có outer pipes.
API quản lý phù hợp ở đâu
html2text chuyển HTML mà bạn đã có sẵn. Nó không tự fetch, không render JavaScript, và cũng không xử lý lớp anti-bot — cả bốn bộ chuyển đổi đều không làm các việc này, và trên nhiều mục tiêu thực tế, đó mới là nửa khó hơn của bài toán.
Với cùng bộ fixture cho cả năm công cụ, hãy xem so sánh HTML-to-Markdown năm chiều.
Một dịch vụ fetch/render/extract dạng hosted, bao gồm cả Thunderbit của chúng tôi, hoạt động ở một tầng khác. Thunderbit không được benchmark trong bài này. Ranh giới liên quan ở đây là chuyển đổi từ HTML được cung cấp sẵn so với một dịch vụ tự lấy và xử lý URL; bài viết này không đưa ra so sánh cùng thước đo về chất lượng, độ trễ hay chi phí.
Cách nhìn công bằng là: nếu bạn đã có HTML, muốn Markdown, và GPL không phải vấn đề cho cách bạn phát hành, html2text là miễn phí và cực kỳ nhỏ gọn. Nếu bạn đang đi lấy trang, hoặc muốn dữ liệu dạng hàng hơn là văn xuôi, đó là một bài toán khác.
Để xem rộng hơn, tổng hợp API web scraping của chúng tôi bao quát các lựa chọn hosted, còn trang trụ cột open-source scraper nói về các công cụ tự host. Chuyển HTML sang Markdown trong Python là hướng dẫn thực hành.
Thử Thunderbit để trích xuất dữ liệu web
Có nên dùng html2text không?
Đây là lựa chọn rất đáng cân nhắc khi footprint quan trọng, bạn chủ động tắt wrapping, và mô hình phân phối đã vượt qua kiểm tra giấy phép.
Số token của nó lệch trong vòng 1,3% so với markdownify và markitdown trong bộ bốn trang. Điều đó không có nghĩa chất lượng tổng thể là tương đương: html2text giữ lại ít liên kết hơn và ít dòng hơn ở fixture Wikipedia bất quy tắc. Hai chi tiết vận hành cần nhớ ngay: body_width = 0, và kiểu bảng không có outer-pipe.
Nếu kiểm tra GPL loại nó ra, markdownify là MIT, có kích thước đầu ra và token tương tự ở đây, giữ lại nhiều liên kết hơn và nhiều dòng bảng bất quy tắc hơn, đồng thời dùng nhiều hơn 1,6 MiB dung lượng đĩa trong môi trường này.
Thử Thunderbit để trích xuất dữ liệu web Get Started Free
Câu hỏi thường gặp
html2text có chuyển đổi bảng không?
Có. Bộ đếm đầu tiên của tôi nói rằng nó chỉ tạo ra 1 dòng bảng trên năm tệp, và con số đó là sai — vì nó yêu cầu phải có dấu | đầu và cuối, trong khi html2text xuất Team Name | Year | Wins mà không có chúng. Đây là Markdown pipe-table thông thường, dù harness này không chạy kiểm tra tương thích giữa các renderer. Với bộ đếm đã sửa, html2text tạo ra 32 dòng so với 36 của markdownify trong bộ bốn trang, và 91 so với 98 khi tính thêm fixture bảng phức hợp riêng.
body_width làm gì, và vì sao phải đổi nó?
Nó tự ngắt dòng đầu ra ở 78 ký tự theo mặc định — một lựa chọn hợp lý cho văn bản đọc trên terminal và không hợp lý cho hầu hết các trường hợp khác. Việc ngắt dòng sẽ chèn xuống hàng giữa câu, tách URL dài và làm thay đổi token hóa. Mọi con số trong bài đánh giá này đều dùng body_width = 0; nếu giữ mặc định, toàn bộ số liệu sẽ khác.
Giấy phép GPL có phải là ràng buộc thật không?
Điều đó phụ thuộc vào mô hình tích hợp và phân phối cụ thể. Việc dùng nội bộ hoặc chỉ qua mạng và việc phát hành phần mềm là hai bối cảnh kiểm tra khác nhau, nhưng bài viết này không quyết định kết quả pháp lý của chúng. Các đội ngũ phát hành phần mềm nên nhờ luật sư xem xét điều khoản GPL-3.0-or-later; markdownify và turndown là MIT. Biểu thức giấy phép của html2text đã được xác nhận trong metadata PyPI, GitHub và file METADATA của gói đã cài.
Bản phát hành từ tháng 4/2025 có phải vấn đề không? Có lẽ là không, xét riêng nó. Chuyển HTML sang text là một bài toán ổn định, thư viện cài đặt và chạy ổn trên Python 3.14.2, và phía sau nó còn 41 bản phát hành. 95 issue đang mở mới là con số tôi sẽ thực sự kiểm tra — hãy rà xem có gì giống đầu vào của bạn trước khi chốt, vì một repo yên ắng có thể đồng nghĩa với việc người sửa nó sau cùng chính là bạn.
Ở đây chưa kiểm tra những gì?
Bốn fixture chuyển đổi cộng thêm một fixture bảng phức hợp riêng vẫn là một bộ thử nhỏ. Bộ test có bao gồm mười hai tài liệu synthetic bị lỗi cùng hai đối chứng: html2text báo lỗi trên 0/14, không trả về rỗng trên 0/14, và khôi phục toàn bộ 33 sentinel được chấm điểm. Nó không bao gồm các trang hỏng trong thế giới thực, các dạng lỗi phổ biến rộng hơn, danh sách lồng, danh sách định nghĩa, footnote hay công thức toán. Toàn bộ các tùy chọn — ignore_links, ignore_images, unicode_snob, single_line_break và các tùy chọn khác — đều giữ mặc định ngoài body_width. Khoảng cách về liên kết được quan sát nhưng chưa được phân tích nguyên nhân, và việc round-trip Markdown cũng chưa được kiểm tra.


