gzip và Brotli khi web scraping và cách đo byte
gzip và Brotli khi web scraping có thể làm giảm byte truyền nhưng cũng tạo lỗi khi giải nén sai tầng. Nội dung đọc được trong response không luôn là byte chạy trên mạng. Bài này so sánh ba biểu diễn của một HTML, kiểm hash sau giải nén và tách rõ charset tiếng Việt. Cùng ProxyVN kiểm tra đầu vào, đối chiếu kết quả và nhận biết giới hạn trước khi áp dụng.
gzip và Brotli khi web scraping nằm trước giải mã văn bản
Một response HTML cần đi qua các bước khác nhau trước khi parser đọc thẻ. Đầu tiên là nhận byte thông điệp, sau đó xử lý mã hóa nội dung nếu có, rồi mới giải mã byte thành chuỗi ký tự. Đảo thứ tự hai bước cuối dễ tạo ký tự lạ hoặc lỗi decoder.
gzip và Brotli thuộc bước nén nội dung. UTF-8 và Windows-1258 thuộc bước chuyển giữa byte và ký tự. Một HTML UTF-8 có thể được truyền không nén, nén gzip hoặc nén Brotli mà vẫn chứa cùng văn bản sau khi khôi phục.
Trong tài liệu Content-Encoding, MDN giải thích header mô tả phép mã hóa đã áp dụng lên biểu diễn. Bài này chỉ dùng nguyên tắc đó để thiết kế bộ so byte. Các số đo bên dưới phải lấy từ tệp lab, không thay cho số liệu băng thông của một dịch vụ.
Ba loại kích thước cần gọi đúng tên
Kích thước payload nén là số byte của body đang được truyền theo codec đã chọn. Kích thước sau giải nén là số byte HTML gốc. Độ dài chuỗi Python lại là số phần tử ký tự theo cách biểu diễn của runtime, không phải một trong hai kích thước byte kia.
Ví dụ chữ có dấu thường chiếm nhiều byte hơn chữ ASCII khi mã hóa UTF-8. Vì vậy len(text) và len(text.encode('utf-8')) có thể khác nhau ngay cả khi không có nén. Nếu báo cáo hai đại lượng dưới cùng nhãn “dung lượng”, kết luận tiết kiệm sẽ khó kiểm lại.
Tổng byte trên dây còn bao gồm header và chi phí giao thức theo tầng quan sát. Lab dùng tệp chỉ đo body. Không lấy độ dài tệp gzip rồi gọi là toàn bộ lưu lượng TCP hay lưu lượng bị tính phí của proxy; các hệ thống có thể đo ở những ranh giới khác nhau.
gzip và Brotli khi web scraping với HTML đối chứng
Bộ thử cần cố định HTML trước khi nén. Nếu mỗi lần gọi sinh timestamp hoặc mã ngẫu nhiên, body đã thay đổi từ nguồn. Khi đó hash khác không chứng minh codec làm hỏng dữ liệu.

Ba biểu diễn cùng HTML
Sinh ba biểu diễn từ một nguồn byte
Ví dụ dưới đây dùng nội dung tự tạo và thư viện Brotli cài trong môi trường lab riêng. Mỗi codec được giải lại rồi so với cùng một nguồn byte. Đây là kiểm tra chức năng round-trip, không phải phép benchmark tốc độ của runtime hoặc máy chủ.
import gzip, hashlib, brotli
html = ('<p>Dữ liệu tiếng Việt để kiểm giải nén.</p>\n' * 100).encode('utf-8')
variants = {'identity': html,
'gzip': gzip.compress(html, mtime=0),
'br': brotli.compress(html)}
for name, data in variants.items():
raw = gzip.decompress(data) if name == 'gzip' else (
brotli.decompress(data) if name == 'br' else data)
assert raw == html
print(name, len(data), len(raw), hashlib.sha256(raw).hexdigest())
Đặt mtime bằng không giúp phần timestamp của tệp gzip không đổi giữa các lần tạo theo cùng điều kiện. Tuy nhiên, hash payload nén còn có thể thay khi thay phiên bản codec hoặc mức nén. Hash sau giải nén mới là phép so phù hợp cho nội dung gốc trong bộ thử này.
Anh em nên lưu phiên bản Python và Brotli cùng kết quả. Nếu cần đối chiếu hiệu suất, thêm kích thước HTML và mức nén cụ thể vào manifest. Việc chỉ ghi “dùng Brotli” bỏ sót các lựa chọn ảnh hưởng CPU và tỷ lệ nén.
Giải thích kết quả trước khi tính tỷ lệ
Ba hash sau khôi phục phải trùng nhau và khớp nguồn. Nếu một codec cho body ngắn hơn nhưng không giải lại được, kết quả đó không hợp lệ để so tiết kiệm. Đo tính đúng trước rồi mới đo kích thước là cách tránh tối ưu một tệp bị cắt.
Tỷ lệ nén có thể tính bằng byte payload chia byte nguồn. Phần giảm tương đối bằng một trừ tỷ lệ đó, nhưng cần nêu rõ cùng mẫu HTML. Một đoạn lặp lại nhiều lần thường nén tốt hơn dữ liệu có entropy cao; không suy rộng kết quả ra mọi website.
Tệp nhỏ còn có thể tăng kích thước vì phần phụ trợ của định dạng. Đó không phải bằng chứng thư viện bị lỗi. Vì thế nên thử thêm một HTML ngắn và một tài liệu dài có cấu trúc khác, thay vì chỉ chọn mẫu cho kết quả giảm nhiều nhất.
gzip và Brotli khi web scraping với HTTP client tự giải nén
Một số thư viện tự giải nén trước khi đưa body cho người gọi. Khi response.content là byte HTML đã khôi phục nhưng header gốc còn mô tả payload nén, gọi gzip.decompress lần nữa sẽ thất bại. Cần đọc đúng tài liệu và cách lấy raw stream của phiên bản client đang dùng.
Đặt câu hỏi ở ranh giới API
Trước khi thêm lệnh giải nén, kiểm body bắt đầu bằng byte gì và đã được truy cập qua API nào. Đừng dùng việc nội dung trông có vẻ lạ để suy đoán. Byte nén vốn không phải chuỗi tiếng Việt; thử decode UTF-8 lên nó chỉ tạo thêm một lỗi ngoài nguyên nhân ban đầu.
Với Requests, khả năng xử lý Brotli còn gắn với bộ giải được cài. Một môi trường có gói hỗ trợ và một môi trường thiếu gói có thể cho hành vi khác nhau dù mã gọi giống nhau. Khóa dependency giúp bộ thử có giá trị khi bàn giao.
Nếu dùng HTTPX, cũng phải phân biệt iterator byte đã giải mã với iterator raw theo tài liệu phiên bản. Không chuyển cách đọc raw của thư viện này sang thư viện khác chỉ vì tên đối tượng response tương tự.
Chỉ quảng bá những codec có thể nhận
Accept-Encoding do client gửi là lời công bố khả năng xử lý biểu diễn. Gửi br trong khi môi trường chưa có bộ giải có thể khiến origin chọn một body mà pipeline không đọc được. Đừng sao chép một header trình duyệt dài vào crawler mà không kiểm dependency.
Trong giai đoạn chẩn đoán, request identity là đối chứng hữu ích. Nếu identity đọc được còn br không đọc được, điều tra đường giải nén và bộ hỗ trợ codec. Nếu cả hai sau khôi phục cùng tạo ký tự sai, chuyển sang kiểm charset thay vì tiếp tục đổi Accept-Encoding.
Origin có thể không chọn codec mà client ưu tiên. Vì vậy lấy Content-Encoding thực nhận làm căn cứ xử lý, đồng thời kiểm chính sách fallback của client. Không gán codec theo header đã gửi hoặc theo phần mở rộng tên tệp tải về.
gzip và Brotli khi web scraping qua nhiều tầng trung gian
Proxy trung gian có thể chuyển tiếp nguyên byte, giải nén rồi nén lại, hoặc chỉ chuyển đường hầm mã hóa tùy loại triển khai. Không có một hành vi duy nhất cho mọi proxy. Cần xác định tầng nào nhìn được HTTP body trước khi quy trách nhiệm cho nó.

Điểm đo byte trên từng tầng
Điểm đo |
Dữ liệu quan sát |
Cách đối chiếu |
|---|---|---|
Origin lab |
Byte nguồn và byte đã nén |
Lưu cả hai hash |
Kết nối HTTP raw |
Payload trước bộ giải của client |
So Content-Encoding |
API response đã xử lý |
Body sau tự giải nén |
So hash byte nguồn |
Parser HTML |
Chuỗi sau charset decode |
Kiểm câu tiếng Việt |
So hash ở cùng một tầng
Hai payload gzip khác hash vẫn có thể chứa cùng HTML. Thay đổi mức nén hoặc metadata tạo tệp là đủ làm byte bên ngoài khác. Muốn biết nội dung thay đổi, giải nén theo header rồi so hash byte nguồn ở cùng ranh giới.
Ngược lại, body cùng độ dài không có nghĩa cùng nội dung. Một ký tự thay đổi có thể giữ số byte gần như cũ. Kết hợp hash và mẫu văn bản có nhãn giúp phát hiện cả thay đổi toàn bộ lẫn lỗi đọc sai một vùng cụ thể.
Nếu luồng dùng HTTPS qua CONNECT không bị giải mã ở proxy, điểm trung gian không có cùng khả năng quan sát HTTP như reverse proxy kết thúc TLS. Nêu rõ mô hình mạng trong báo cáo. Không suy từ kết quả với reverse proxy sang mọi dịch vụ forward proxy thương mại.
Giữ header khi lưu snapshot
Kho snapshot nên ghi rõ body đang ở dạng raw hay decoded. Nếu lưu raw.bin nhưng parser lại coi đó là HTML, lỗi sẽ lặp lại sau khi tải lại từ ổ đĩa. Một trường representation trong manifest giúp bước sau chọn đúng cách đọc.
Khi body đã được giải nén, lưu thông tin codec gốc dưới dạng metadata xuất xứ thay vì giả làm header hiện hành của tệp mới. Tách hai bộ thông tin này tránh việc công cụ phát lại giữ Content-Encoding cũ trên byte không nén.
Trước khi mua proxy tốc độ cao, anh em có thể dùng bộ đo này để xác định tải mạng hay CPU giải nén đang chiếm thời gian. Nhu cầu tuyến truyền và chi phí parser là hai mục cần kiểm bằng dữ liệu của chính pipeline.
gzip và Brotli khi web scraping với lỗi thường gặp
Lỗi giải nén cần phân loại theo byte và header. Một thông báo chung như “HTML không đọc được” không chỉ ra body bị cắt, sai codec hay sai charset. Giữ tệp lỗi nhỏ nhất còn tái hiện sự cố sẽ giúp kiểm lại nhanh hơn.
Body bị cắt giữa chừng
Kết nối có thể đóng trước khi client nhận đủ thông điệp. Với nội dung nén, thiếu một phần cuối đôi khi chỉ bộc lộ lúc decoder hoàn tất. Đừng đưa văn bản một phần vào kho thành công chỉ vì parser tìm được vài thẻ đầu tài liệu.
Ca thử nên cố ý bỏ vài byte cuối của payload và yêu cầu bộ xử lý đánh dấu thất bại. Ghi số byte đã nhận, lỗi decoder và trạng thái tệp tạm. Không cố cứu một bản ghi sản phẩm bằng cách bỏ qua mọi lỗi giải nén rồi nhận nó như dữ liệu đầy đủ.
Tệp tải chưa hoàn tất cần có tên hoặc trạng thái riêng. Khi tải thành công và kiểm toàn vẹn xong mới đổi tên atomically theo khả năng hệ thống tệp. Cách này ngăn worker khác đọc một tệp gzip đang được ghi dở.
Header và body không khớp
Response có nhãn gzip nhưng body là HTML thường có thể do một lớp trung gian đã giải nén mà chưa chỉnh metadata. Trường hợp ngược lại là byte vẫn nén nhưng nhãn bị mất. Hai ca đều cần log ở trước và sau điểm nghi ngờ để xác định nơi biến đổi.
Không viết cơ chế đoán codec rộng rồi xem đó là sửa tận gốc. Bộ đoán có thể che lỗi phát lại response và tạo hành vi khác nhau giữa client. Nếu phải hỗ trợ dữ liệu lịch sử sai header, đánh dấu nhánh phục hồi riêng và không trộn với đường xử lý chuẩn.
Khi có nhiều lớp Content-Encoding, thứ tự giải mã phải đảo ngược thứ tự mã hóa theo định nghĩa của header. Lab chính chỉ có một codec mỗi body. Nếu hệ thống thật dùng nhiều lớp, thêm bộ thử riêng với payload và kỳ vọng tương ứng, không nhận pass từ ca đơn.
Giải nén hai lần và decode hai lần
Giải nén hai lần xảy ra khi API client đã xử lý nhưng mã người dùng tiếp tục gọi decoder codec. Decode ký tự hai lần thường xuất hiện khi một chuỗi đã đúng lại bị encode theo một charset rồi decode theo charset khác. Hai lỗi có tên gần nhau nhưng phép kiểm khác nhau.
Với lỗi đầu, lưu loại dữ liệu và byte đầu body trước lệnh giải nén. Với lỗi sau, giữ chuỗi Unicode và nguồn byte gốc để kiểm round-trip. Tránh dùng replace hoặc ignore làm mặc định vì chúng có thể xóa bằng chứng về byte gây lỗi.
Một ca tiếng Việt chuẩn trong bộ thử nên chứa nhiều dấu và ký tự đ. So nguyên chuỗi sau khôi phục, không chỉ kiểm có từ HTML hay có thẻ p. Parser chạy không lỗi vẫn có thể tạo nội dung sai chữ.
gzip và Brotli khi web scraping trong pipeline lớn
Đọc toàn bộ tệp vào RAM là cách đơn giản cho lab nhỏ. Với tài liệu lớn hoặc nhiều worker, cần giới hạn cả byte nhận và byte sau giải nén. Kích thước nén nhỏ không dự báo được lượng RAM dành cho nội dung khôi phục.

Giới hạn giải nén và bộ nhớ
Thiết lập ngân sách tài nguyên theo công việc
Chọn giới hạn theo kích thước tài liệu dự kiến của nguồn được phép thu. Một trang danh mục và một tệp báo cáo dài có nhu cầu khác nhau. Không lấy ngưỡng của ví dụ ngắn làm mặc định cho mọi nhóm dữ liệu.
Khi vượt giới hạn, đưa bản ghi vào trạng thái cần xem xét cùng lý do. Nếu tự cắt body để parser chạy tiếp, sản phẩm đầu ra có thể thiếu phần cuối mà không ai nhận biết. Việc từ chối có dấu vết thường dễ sửa hơn một dữ liệu âm thầm bị cắt.
Với xử lý stream, cần kiểm thời điểm decoder xác nhận kết thúc hợp lệ. Một số dữ liệu đầu có thể được xuất ra trước khi lỗi cuối phát sinh. Pipeline downstream cần biết trạng thái toàn vẹn của cả tài liệu thay vì nhận từng chunk như dữ liệu đã nghiệm thu.
Đo thời gian riêng từng bước
Tách thời gian chờ response, nhận body, giải nén, giải mã ký tự và parse HTML. Một tổng thời gian duy nhất không giúp biết Brotli đang giảm mạng nhưng tăng CPU hay ngược lại. Chỉ so các lần chạy có cùng nguồn dữ liệu và điều kiện máy.
Không chạy benchmark bằng cách gửi dồn request đến website công khai. Dùng origin lab hoặc tệp đã được phép lưu để đo codec. Nếu cần đánh giá đường truyền thật, thiết kế tốc độ và phạm vi theo chính sách nguồn, giữ số lần gọi ở mức phù hợp.
Lưu cả phân phối thời gian thay vì một con số đẹp nhất. Các lượt đầu có thể chịu chi phí khởi tạo hoặc cache ổ đĩa khác lượt sau. Báo rõ mẫu đo, số lần và cách làm nóng nếu muốn dùng kết quả để ra quyết định hạ tầng.
gzip và Brotli khi web scraping và bộ nghiệm thu
Bộ nghiệm thu nên kết hợp tệp tốt, tệp hỏng và môi trường thiếu bộ giải. Chỉ chạy round-trip thành công sẽ bỏ sót nhiều lỗi thường xuất hiện khi triển khai sang máy khác. Mỗi ca phải có trạng thái đầu ra mong đợi trước khi chạy.

Bộ tệp tốt và tệp hỏng
Các ca tối thiểu nên lưu trong kho kiểm
Ca identity cần trả cùng hash byte gốc và đúng câu tiếng Việt. Ca gzip cần khôi phục cùng byte dù payload ngắn hơn hoặc dài hơn tùy mẫu. Ca br cũng cần cùng hash sau khôi phục với phiên bản thư viện đã ghi.
Ca payload cắt cần bị đánh dấu lỗi toàn vẹn. Ca header sai phải đi vào nhánh lỗi metadata thay vì được tính là codec chậm. Ca thiếu Brotli cần thể hiện dependency hoặc khả năng nhận codec, không được tự đổi sang kết luận proxy trả sai HTML.
Ca charset sai giữ riêng byte HTML sau giải nén nhưng cố ý decode sai để chứng minh lỗi nằm ở bước ký tự. Khi sửa đúng charset, chuỗi phải khớp nhãn. Cách chia ca giúp người bảo trì biết phải sửa lớp nào mà không thử ngẫu nhiên mọi cấu hình mạng.
Giữ kết luận trong phạm vi đã đo
Trong đợt soạn, phép round-trip được dùng để kiểm nội dung tự tạo với gzip và Brotli. Nó chứng minh dữ liệu mẫu khôi phục đúng trong môi trường ghi nhận. Không coi đây là chứng nhận mọi HTTP client đều tự giải br hoặc mọi gateway đều giữ nguyên header.
Nếu dự án cần HTTP/2, giải nén stream hoặc đo byte tính phí, bổ sung lab tại đúng tầng đó. Ghi rõ công cụ quan sát và ranh giới đếm byte. Một Content-Length trên response không đủ thay cho báo cáo của nhà cung cấp về cách tính lưu lượng.
Khi nâng phiên bản client hoặc codec, chạy lại bộ tệp và so cả hash lẫn trạng thái lỗi. Nội dung đọc đúng ở ca thành công là điều kiện cần, nhưng hành vi với tệp hỏng cũng phải giữ theo hợp đồng. Đây là phần giúp việc nâng cấp có thể kiểm chứng.
Lưu ý khi tải lại theo dải byte
Tải tiếp cần giữ đúng biểu diễn đang nối. Offset của tệp gzip đang tải dở thuộc byte nén, không phải vị trí ký tự trong HTML sau khôi phục. Nếu lần đầu nhận gzip còn lần sau nhận identity, nối hai phần sẽ tạo một tệp không có ý nghĩa.
Khi công việc yêu cầu Range, nên quyết định biểu diễn ngay từ đầu và giữ validator cùng độ dài đã nhận. Client không được âm thầm tự giải nén một phần rồi dùng số byte giải nén làm offset của request tiếp theo. Đây là lỗi ranh giới thường khó thấy khi API chỉ trả chunk đã xử lý.
Đối với HTML nhỏ, tải lại từ đầu có thể đơn giản hơn thiết kế resume cho biểu diễn nén. Với tệp lớn, cần một hợp đồng riêng về Range, Content-Range và If-Range. Không áp dụng cơ chế nối tệp chỉ dựa vào việc status lần sau là 206.
Tránh nhầm nén HTTP với định dạng tệp
Một URL kết thúc bằng .gz có thể trả chính tệp gzip như tài nguyên, chứ không phải HTML được mã hóa bằng Content-Encoding. Hai trường hợp có thể cần cách lưu và xử lý khác nhau. Đọc Content-Type, Content-Encoding và mục tiêu công việc trước khi quyết định tự mở tệp.
Nếu nhiệm vụ là lưu bản nguyên gốc để phân phối lại, giữ byte tài nguyên có thể là yêu cầu đúng. Nếu nhiệm vụ là trích HTML, cần xác định lớp nào được giải trước parser. Không xóa phần mở rộng .gz rồi cho rằng nội dung bên trong đã đổi thành văn bản thường.
Tương tự, một gói ZIP chứa nhiều HTML không được giải bằng bộ Content-Encoding chỉ vì response là dữ liệu nén. Đó là định dạng ứng dụng với danh sách tệp riêng. Kiểm đường dẫn và kích thước khi mở archive thuộc quy trình khác, ngoài phép round-trip một body của bài này.
Đọc báo cáo dung lượng trước khi chọn cấu hình
Biên bản nên có cột tên codec, byte payload, byte khôi phục và hash nguồn. Thêm thời gian codec nếu đã đo, giữ trống nếu chưa chạy benchmark. Một ô chưa có dữ liệu tốt hơn con số suy ra từ cảm giác tải nhanh trong một lượt gọi.
Khi chia sẻ kết quả, gửi luôn mẫu HTML tự tạo hoặc công thức sinh mẫu. Người nhận có thể chạy lại trên runtime khác để biết sai lệch do input hay dependency. Không đưa body của tài khoản thật vào gói thử chỉ để giữ tính tái lập.
Thiết kế thử nghiệm thiếu codec trên máy mới
Một môi trường kiểm riêng nên chỉ có dependency tối thiểu trước khi thêm Brotli. Gửi request identity trước để chứng minh đường HTTP và charset đang hoạt động. Sau đó kiểm cách client phản ứng khi nhận br trong điều kiện chưa có bộ giải, rồi bổ sung dependency và chạy lại cùng payload.
Không tháo thư viện khỏi môi trường dùng chung để thử ca này. Tạo môi trường cô lập hoặc dùng cấu hình client cho phép điều khiển khả năng giải mã theo tài liệu. Cách thử phải giữ những công việc khác trên máy tiếp tục hoạt động và có thể xóa riêng sau nghiệm thu.
Nếu client không quảng bá br khi thiếu bộ giải, đó có thể là hành vi phù hợp. Bộ kiểm không nên buộc mọi môi trường phải gửi cùng Accept-Encoding. Tiêu chí là client không nhận thành công một dữ liệu nó chưa xử lý được và không đẩy byte nén vào parser văn bản.
Sau khi thêm dependency, ghi lại bộ header thực gửi và codec thực nhận. Chỉ nhìn danh sách gói đã cài không chứng minh tiến trình đang dùng chúng. Worker chạy lâu có thể cần khởi động lại để nạp môi trường mới theo cách triển khai của ứng dụng.
Đối chiếu lỗi trong một bản ghi có provenance
Một bản ghi kiểm nên giữ URL lab, thời điểm lấy, hash payload và hash byte sau khôi phục. Thêm tên API đã dùng để đọc body, charset được chọn và phiên bản bộ giải. Khi những trường này đầy đủ, người nhận có thể xác định bước đầu tiên có sai lệch.
Nếu hash sau giải nén trùng nguồn nhưng văn bản sai dấu, giữ kết luận ở tầng charset. Nếu hash khôi phục khác nguồn, chưa nên điều tra selector vì parser đang nhận dữ liệu khác. Nếu payload raw không đọc đủ, ưu tiên kiểm đường tải và trạng thái tệp tạm.
Trong báo cáo lỗi, đính kèm đoạn byte hoặc tệp nhỏ đã loại thông tin nhạy cảm thay vì toàn bộ phiên đăng nhập. Ghi cách sinh lại tệp tự tạo nếu có. Với dữ liệu lab của bài, không cần token, Cookie hoặc thông tin khách hàng để tái hiện bất kỳ phép so nào.
Kết quả có thể đọc được cần đi kèm trạng thái toàn vẹn. Khi thêm bước lưu kho, anh em nên giữ hai thuộc tính này riêng để một chuỗi trích tạm không bị hiểu là tài liệu đã tải đủ.
Hãy so byte ở cùng một tầng trước khi so tốc độ; nén nội dung và mã hóa ký tự là hai bước riêng.
Anh em hãy lưu dữ liệu mẫu cùng cấu hình và kết quả đối chiếu để lần cập nhật sau có cơ sở kiểm lại. Tham khảo thêm tại Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam. Bắt đầu từ phạm vi nhỏ và tiêu chí rõ ràng khi triển khai gzip và Brotli khi web scraping.