Chuyển HTML sang JSON: schema, URL nguồn và kiểm tra lỗi
Chuyển HTML sang JSON giúp anh em đưa dữ liệu trang web vào API, kho lưu trữ hoặc bước phân tích tiếp theo. Cùng ProxyVN, bài viết xây dựng một pipeline có schema rõ ràng, loại menu và footer khỏi vùng lấy dữ liệu, giữ URL nguồn và phát hiện trường thiếu bằng ví dụ JavaScript có kiểm thử cục bộ.
Chuyển HTML sang JSON bắt đầu từ hợp đồng dữ liệu
HTML mô tả tài liệu để trình duyệt hiển thị, còn JSON biểu diễn các giá trị mà chương trình xử lý. Vì vậy, thao tác cần làm thường không phải đổi từng thẻ thành một thuộc tính tương ứng. Với trang danh mục, đầu ra hữu ích là danh sách sản phẩm có mã, tên và đường dẫn. Với bài báo, đầu ra có thể là tiêu đề, tác giả và các đoạn nội dung. Chọn mục tiêu trước sẽ tránh một cây JSON rất lớn nhưng khó dùng.
Trong ví dụ này, đầu vào là HTML của danh mục giả lập, không phải dữ liệu khách hàng hoặc kết quả crawl một website thương mại. Vùng chính mang mã catalog; mỗi thẻ article có thuộc tính data-id, một liên kết mang lớp title và phần giá tùy chọn. Đầu ra giữ nguyên chuỗi giá để không suy đoán đơn vị tiền tệ. Bản ghi thiếu tên, thiếu mã hoặc có đường dẫn không hợp lệ phải làm bước chuyển đổi báo lỗi, thay vì âm thầm tạo dữ liệu trông có vẻ đầy đủ.
Điều cần thống nhất với bên nhận dữ liệu là ý nghĩa từng trường. Chẳng hạn id là chuỗi định danh lấy từ trang, không phải số thứ tự trong lần chạy. title là văn bản đã thu gọn khoảng trắng. url là đường dẫn HTTP hoặc HTTPS đã giải quyết tương đối theo URL tài liệu. price_text nhận một chuỗi hoặc null. source_url thuộc tài liệu bao ngoài, giúp truy lại trang đã sinh danh sách. Cách đặt tên này phân biệt nguồn danh mục với đường dẫn của từng mặt hàng.
Đừng trộn hợp đồng dữ liệu với cách lấy trang. Cùng một hàm chuyển đổi có thể nhận HTML tải trực tiếp, HTML tải qua proxy hoặc một fixture trong bộ kiểm thử. Nếu đầu vào như nhau, kết quả phải giữ cùng cấu trúc. Tách hai phần giúp anh em biết lỗi đang nằm ở kết nối, nội dung trả về hay selector. Nó cũng cho phép chạy lại bản HTML đã lưu khi website tạm thời không truy cập được mà không gửi thêm request.
JSON hợp lệ về cú pháp chưa đồng nghĩa dữ liệu đã đúng với hợp đồng mà ứng dụng cần.
Một cấu trúc có thể phân tích bằng JSON.parse nhưng vẫn thiếu source_url hoặc chứa danh sách rỗng do chọn sai vùng. Hợp đồng cần nói rõ trường nào bắt buộc, giá trị nào được để trống và tình huống nào phải ngừng. Với danh mục được kỳ vọng có sản phẩm, không tìm thấy bản ghi là một lỗi cần điều tra. Với trang tìm kiếm có thể không có kết quả, danh sách rỗng lại là đầu ra hợp lệ nếu đi kèm trạng thái phù hợp.
Chuyển HTML sang JSON với schema và quy tắc thiếu trường
Schema của bài cố ý nhỏ để dễ kiểm tra. Cấp tài liệu có schema_version, source_url và items. Mỗi phần tử items phải có đúng bốn trường đã định nghĩa. Quy tắc additionalProperties bằng false giúp phát hiện lỗi chính tả khi lập trình, chẳng hạn ghi nhầm priceText thành price_text. Đây là lựa chọn của hợp đồng ví dụ, không phải yêu cầu chung cho mọi hệ thống. Nếu bên nhận cần mở rộng, anh em phải thống nhất phiên bản và cách tiếp nhận trường mới.
Thiếu giá khác với giá bằng không. Không có phần tử giá thì price_text là null; có phần tử nhưng văn bản chỉ gồm khoảng trắng cũng được quy về null theo chính sách mẫu. Chuỗi “0 đ” vẫn là chuỗi có nội dung. Còn tên sản phẩm rỗng sẽ bị từ chối vì tên là bắt buộc. Không nên điền “chưa cập nhật” vào mọi trường thiếu: ứng dụng sau đó khó phân biệt thông tin thật với nhãn do bộ chuyển đổi tự thêm.
Trường hợp trong HTML |
Đầu ra hoặc cách xử lý |
Lý do |
|---|---|---|
Không có phần tử giá |
price_text bằng null |
Giá là tùy chọn |
Tên chỉ có khoảng trắng |
Báo lỗi |
Không đủ dữ liệu bắt buộc |
Hai thẻ dùng cùng data-id |
Báo lỗi |
Tránh nhập trùng âm thầm |
href là đường dẫn tương đối |
Giải quyết theo source_url |
Giữ liên kết sử dụng được |
href bắt đầu bằng javascript: |
Báo lỗi |
Chỉ chấp nhận HTTP và HTTPS |
Trong hướng dẫn khởi đầu của Ajv, schema được biên dịch thành hàm xác thực có thể tái sử dụng. Ví dụ dưới đây biên dịch một lần ở cấp module rồi kiểm tra mỗi bản ghi. Ajv xác nhận kiểu dữ liệu và trường bắt buộc; tập Set riêng xác nhận mã không lặp trong trang. Đó là hai trách nhiệm khác nhau. Một schema kiểm tra từng đối tượng riêng lẻ sẽ không tự biết id đã xuất hiện ở bản ghi trước.
Schema mẫu không tự xác nhận nội dung giá là chính xác hay sản phẩm còn bán. Đây là ranh giới cần giữ khi nghiệm thu. Nếu về sau cần price_amount, currency và trạng thái tồn kho, hãy thêm quy tắc chuyển đổi được mô tả rõ, rồi kiểm thử trên các cách hiển thị liên quan. Một chuỗi “1.299” có thể mang ý nghĩa khác nhau theo khu vực. Việc xóa mọi ký tự không phải chữ số trước khi hiểu định dạng dễ làm mất dấu thập phân hoặc khoảng giá.

Schema và cách xử lý trường thiếu
Chuyển HTML sang JSON với vùng nội dung và URL nguồn
Chọn đúng phạm vi DOM giúp giảm dữ liệu lẫn từ giao diện. Mẫu chọn chính xác một main có id catalog, sau đó chỉ duyệt article trực tiếp bên trong. Một thẻ sản phẩm nằm trong menu ngoài main sẽ không được lấy. Một article lồng trong footer bên trong vùng chính cũng không được tính sau khi footer bị loại. Quy tắc này cụ thể hơn việc tìm mọi phần tử mang lớp title trong toàn trang, vốn có thể lấy tên bài liên quan hoặc liên kết ở cuối trang.
Danh sách loại bỏ trong bài gồm nav, footer, script và style bên trong vùng đã chọn. Không nên áp dụng danh sách ấy như công thức chung cho mọi website. Một trang tài liệu có thể đặt thông tin quan trọng trong aside; một bản tin có thể đặt tên tác giả trong footer của article. Trước khi xóa nút, anh em cần đối chiếu với hợp đồng dữ liệu của chính trang đó. Xóa quá rộng cũng là một dạng mất dữ liệu, dù JSON cuối cùng vẫn đẹp và hợp lệ.
Theo tài liệu nạp HTML của Cheerio, thư viện cung cấp các cách nạp chuỗi, buffer hoặc stream để làm việc với tài liệu. Ví dụ sử dụng load trên chuỗi HTML đã có. Nó không mở giao diện trình duyệt để thực hiện các tương tác của người dùng. Nếu phần sản phẩm chỉ được tạo sau một request JavaScript, hãy kiểm tra nguồn dữ liệu được phép sử dụng hoặc lấy bản HTML đã render bằng công cụ phù hợp trước khi chạy bước chuyển đổi.
URL nguồn phải là URL tài liệu thực nhận sau chuyển hướng, chứ không mặc định là địa chỉ nhập ban đầu. Nếu request chuyển từ đường dẫn danh mục cũ sang một thư mục mới, đường dẫn tương đối có thể được giải quyết khác. Ví dụ products/a và /products/a không giống nhau khi URL nền nằm dưới /shop/. Phải lưu cùng bản HTML địa chỉ hiệu lực và thông tin lần tải, để có thể tái hiện cách tạo url cho từng bản ghi về sau.
Hàm URL với tham số base xử lý quan hệ này mà không cần tự nối chuỗi bằng dấu gạch chéo. Mẫu dùng URL hiệu lực làm base và từ chối giao thức ngoài HTTP, HTTPS. Nó cũng từ chối thông tin người dùng hoặc mật khẩu gắn trong URL, tránh mang thông tin nhạy cảm sang JSON. Kiểm tra này không thay thế chính sách cho phép tên miền: nếu chỉ chấp nhận liên kết cùng website, cần bổ sung so sánh origin trước khi nhập dữ liệu.
Trang có thẻ base là một trường hợp cần quyết định riêng. Hàm mẫu không đọc thẻ này mà dùng source_url làm nền theo hợp đồng đã nêu. Nếu website dựa vào base để định nghĩa các liên kết, anh em phải đọc, xác thực và sử dụng URL nền ấy một cách có chủ đích. Không nên âm thầm tin một base trỏ sang miền khác. Bộ kiểm thử cũng cần có ví dụ thể hiện chính sách đã chọn, để người sửa selector không vô tình thay đổi ý nghĩa đường dẫn.
Chuyển HTML sang JSON bằng JavaScript và fixture nhỏ
Ví dụ dưới đây được kiểm thử với Cheerio 1.2.0 và Ajv 8.20.0 trong môi trường Node.js cục bộ. Anh em có thể cài hai phiên bản này vào một thư mục thử riêng và lưu package lock để tái lập. Phiên bản được nêu là phiên bản đã dùng cho bài, không phải cam kết rằng mọi bản mới đều có cùng hành vi. Khi nâng gói, hãy chạy lại fixture trước khi áp dụng vào job thu thập đang hoạt động.
npm install cheerio@1.2.0 ajv@8.20.0
Lưu đoạn HTML sau thành page.html với mã hóa UTF-8. Sản phẩm trong nav là dữ liệu nhiễu để kiểm tra phạm vi chọn. Danh mục có một mặt hàng có giá và một mặt hàng thiếu giá. Dấu ngoặc kép cùng ký tự tiếng Việt ở tên giúp kiểm tra bước xuất chuỗi. Những giá trị này là dữ liệu giả do bài viết tạo, không phải báo cáo từ một cửa hàng hay một lần thu thập thực tế.
<nav><article data-id="noise"><a class="title">Menu</a></article></nav>
<main id="catalog">
<article data-id="p01">
<a class="title" href="/san-pham/a">Bộ lọc "A"</a>
<span class="price">129.000 đ</span>
</article>
<article data-id="p02">
<a class="title" href="b">Bộ lọc B</a>
</article>
</main>
<footer>Thông tin liên hệ</footer>
Lưu module thành convert.mjs. Hàm nhận chuỗi HTML và URL nguồn, trả về một đối tượng JavaScript chưa ghi ra đĩa. Nó báo lỗi khi nguồn không hợp lệ, vùng chính thiếu hoặc lặp, danh mục rỗng, trường bắt buộc thiếu hay mã trùng. Cách dừng cả trang phù hợp mẫu nhỏ này. Trong job lớn, có thể chuyển sang khu vực cách ly bản ghi lỗi, nhưng phải giữ nguyên lý do và số lượng, không loại bỏ mà không để lại dấu vết.
import { load } from 'cheerio';
import Ajv from 'ajv';
const validate = new Ajv({ allErrors: true }).compile({
type: 'object', additionalProperties: false,
required: ['id', 'title', 'url', 'price_text'],
properties: {
id: { type: 'string', minLength: 1 },
title: { type: 'string', minLength: 1 },
url: { type: 'string', minLength: 1 },
price_text: { type: ['string', 'null'] }
}
});
const clean = value => value.replace(/\s+/gu, ' ').trim();
function webURL(value, base) {
const u = new URL(value, base);
if (!['http:', 'https:'].includes(u.protocol) ||
u.username || u.password) throw new Error('URL bị từ chối');
return u.href;
}
export function convert(html, source) {
const source_url = webURL(source);
const $ = load(html);
const root = $('main#catalog');
if (root.length !== 1) throw new Error('Cần đúng một catalog');
root.find('nav,footer,script,style').remove();
const seen = new Set();
const items = root.children('article').map((i, el) => {
const card = $(el), link = card.find('a.title');
if (link.length !== 1) throw new Error(`Sai title tại ${i}`);
const href = link.attr('href')?.trim();
if (!href) throw new Error(`Thiếu href tại ${i}`);
const price = clean(card.find('.price').text());
const item = {
id: clean(card.attr('data-id') ?? ''),
title: clean(link.text()), url: webURL(href, source_url),
price_text: price || null
};
if (!validate(item)) {
throw new Error(`Bản ghi ${i}: ${JSON.stringify(validate.errors)}`);
}
if (seen.has(item.id)) throw new Error(`Trùng id: ${item.id}`);
seen.add(item.id);
return item;
}).get();
if (!items.length) throw new Error('Catalog rỗng');
return { schema_version: 1, source_url, items };
}
Hàm clean chỉ chuẩn hóa khoảng trắng; nó không viết lại tên hoặc đoán nội dung. Chính sách này phù hợp tiêu đề sản phẩm nhưng không nên dùng cho đoạn mã nguồn, thơ hoặc văn bản cần giữ nguyên xuống dòng. Tương tự, phần giá hiện lấy văn bản của vùng .price. Nếu giao diện có cả giá gốc và giá giảm trong các phần tử con, cần chọn rõ trường mong muốn. Không được xem chuỗi ghép cả hai giá là số tiền cuối cùng.
Tạo run.mjs như dưới đây để đọc file và ghi đầu ra. Dùng tên tạm trước khi đổi sang tên cuối trong hệ thống sản xuất, hoặc cơ chế ghi nguyên tử phù hợp môi trường, để bên đọc không mở trúng file đang viết dở. Đoạn chạy tối thiểu ở đây chỉ ghi một file đơn giản phục vụ fixture. Lỗi từ convert sẽ làm tiến trình thất bại trước bước ghi, vì thế không tạo một danh sách rỗng như thể quá trình đã thành công.
import { readFile, writeFile } from 'node:fs/promises';
import { convert } from './convert.mjs';
const html = await readFile('page.html', 'utf8');
const data = convert(html, process.argv[2]);
await writeFile('result.json', JSON.stringify(data, null, 2), 'utf8');
node run.mjs https://example.com/catalog/
Kết quả mong đợi của fixture là hai phần tử trong items, không có Menu. Mã p01 giữ tên Bộ lọc có dấu ngoặc kép và giá dạng văn bản; mã p02 nhận giá null. Liên kết của p01 bắt đầu từ gốc miền, còn b của p02 nằm dưới /catalog/. Đây là các tiêu chí kiểm tra cụ thể. Nếu chỉ đếm có hai phần tử mà không xem URL và giá, bộ kiểm thử có thể bỏ sót lỗi chuyển đổi quan trọng.

Kết quả từ fixture HTML
Chuyển HTML sang JSON và kiểm tra chuỗi đầu ra
Hãy để JSON.stringify tạo chuỗi JSON thay vì tự ghép dấu ngoặc và dấu phẩy. Hàm xử lý cách biểu diễn chuỗi, gồm dấu ngoặc kép và xuống dòng. Tham số khoảng trắng trong ví dụ chỉ phục vụ việc đọc file. Nó không thay đổi hợp đồng dữ liệu. Sau khi ghi, một bài kiểm tra có thể đọc file trở lại bằng JSON.parse rồi đối chiếu với đối tượng trước khi ghi để phát hiện hỏng mã hóa hoặc sai đường dẫn lưu.
Nên sử dụng null một cách tường minh cho trường tùy chọn. Với thuộc tính đối tượng mang giá trị undefined, bước tuần tự hóa có thể bỏ thuộc tính ấy khỏi JSON, làm đầu ra khác hợp đồng dự kiến. Hàm mẫu đã chuyển trường thiếu về chuỗi rỗng để schema bắt lỗi hoặc về null đối với giá. Nếu bổ sung số, cần kiểm tra giá trị hữu hạn trước khi xuất. Đừng để một phép tính thất bại âm thầm trở thành null rồi được hiểu như trường không có dữ liệu.
Việc phân tích HTML có entity cũng cần kiểm thử. Chẳng hạn văn bản hiển thị chứa ký tự và hoặc khoảng trắng không ngắt có thể có cách viết khác trong mã nguồn. Hãy so sánh giá trị văn bản sau phân tích với ý nghĩa người đọc thấy, thay vì đòi chuỗi HTML thô giữ nguyên. Ngược lại, nếu yêu cầu lưu đoạn HTML cho mục đích biên tập, cần một trường riêng có tên rõ và chính sách làm sạch khi hiển thị lại, không nhét vào title.
Một bộ kiểm thử nhỏ hữu ích hơn nhiều lần mở file nhìn bằng mắt. Với fixture của bài, các ca kiểm tra gồm đúng hai sản phẩm, bỏ dữ liệu menu, giữ chữ tiếng Việt và dấu ngoặc kép, giải quyết hai kiểu URL tương đối, giá thiếu thành null, giá bằng không không bị mất, tên thiếu bị chặn và mã trùng bị chặn. Thêm các ca thiếu root, nhiều root, root rỗng, giao thức javascript và nguồn chứa thông tin đăng nhập để kiểm tra đường lỗi.
Các kiểm thử cục bộ xác nhận logic biến đổi trên dữ liệu giả đã định nghĩa. Chúng không chứng minh selector còn đúng trên website khác hoặc dữ liệu thật của website đã đầy đủ. Khi áp dụng, hãy tạo fixture từ một trang được phép truy cập, xóa thông tin nhạy cảm nếu có, rồi ghi rõ điều kiện thu thập. Một fixture của danh mục đầu tiên cũng chưa đại diện cho trang phân trang cuối, trang hết hàng hay giao diện dành cho thiết bị di động.
Chuyển HTML sang JSON trong pipeline tải qua proxy
Proxy thuộc bước lấy HTML, không sửa schema hoặc làm tên sản phẩm tự xuất hiện. Để hiểu luồng request trước khi cấu hình, anh em có thể xem bài web scraping proxy hoạt động thế nào. Pipeline nên giữ ba kết quả riêng: thông tin lần tải, file HTML và JSON đã xác thực. Nhờ vậy, lỗi đăng nhập proxy có thể được xử lý ở lớp kết nối, còn lỗi thiếu selector được xử lý ở lớp chuyển đổi.
Mẫu cURL dưới đây thể hiện vị trí proxy HTTP và các giới hạn thời gian. Địa chỉ proxy là ví dụ thay thế, không phải endpoint đang cung cấp dịch vụ. Tài liệu cURL về các tùy chọn dòng lệnh mô tả proxy, chuyển hướng, mã thoát và thông tin write-out. Anh em cần dùng curl.exe trong PowerShell để gọi chương trình cURL rõ ràng, kiểm tra mã thoát trước khi đưa page.html vào bước chuyển đổi, đồng thời lưu URL hiệu lực được trả ra.
$effective = curl.exe --proxy http://proxy.example:8080 `
--fail --location --max-redirs 3 --connect-timeout 5 `
--max-time 20 --output page.html --write-out '%{url_effective}' `
https://example.com/catalog/
if ($LASTEXITCODE -ne 0) { throw 'Tải HTML thất bại' }
node run.mjs $effective
if ($LASTEXITCODE -ne 0) { throw 'Chuyển đổi thất bại' }
Trước khi chạy lên nguồn thật, bổ sung kiểm tra status, Content-Type, dung lượng và dấu hiệu nội dung mong đợi. HTTP 200 có thể là trang đăng nhập hoặc thông báo bảo trì. Ngược lại, một response có Content-Type HTML chưa bảo đảm nó là trang danh mục. Lưu các thông tin này theo cùng mã lần chạy giúp phát hiện một file HTML cũ bị dùng lại sau lỗi tải. Không bỏ qua mã thoát chỉ vì thấy file page.html đã tồn tại từ lần trước.
Giới hạn thời gian trong ví dụ không phải khuyến nghị cố định cho mọi nguồn. Hãy căn vào độ trễ quan sát được trong hệ thống của anh em, kích thước trang và lịch thu thập được cho phép. Khi timeout hoặc bị giới hạn tần suất, cần giảm nhịp, áp dụng khoảng chờ phù hợp và xem lại điều kiện truy cập. Đổi IP liên tục không phải cách sửa selector hoặc thay thế việc kiểm tra quyền sử dụng dữ liệu. Mọi lần thử lại phải có giới hạn để tránh tạo vòng request kéo dài.
Khi đã xác định job cần đường ra riêng, anh em có thể mua proxy sau khi kiểm tra giao thức, cách xác thực và phạm vi sử dụng với bên cung cấp. Ví dụ trong bài không xác nhận tính tương thích của một gói ProxyVN cụ thể, cũng không thử endpoint thương mại. Thông tin đăng nhập nên được cấp qua cơ chế cấu hình phù hợp môi trường và che khỏi log, đặc biệt khi ghi lại dòng lệnh hoặc chia sẻ báo cáo lỗi cho người khác.

Luồng tải qua proxy và chuyển đổi
Chuyển HTML sang JSON khi selector hoặc nội dung thay đổi
Một dấu hiệu thường gặp là pipeline vẫn xuất JSON nhưng số bản ghi giảm bất thường. Hãy đối chiếu số thẻ trong HTML đã lưu với số phần tử sau chuyển đổi. Nếu HTML cũng thiếu thẻ, điều tra bước tải, phân trang hoặc cách website tạo nội dung. Nếu HTML có đủ thẻ nhưng đầu ra thiếu, điều tra selector và quy tắc lọc. Tách hai phép so sánh này giúp tránh sửa proxy trong khi lỗi thật nằm ở thay đổi lớp CSS.
Mẫu dùng lỗi dừng cả trang để người vận hành nhìn thấy sai lệch sớm. Khi dữ liệu lớn hơn, có thể ghi riêng các bản ghi bị từ chối cùng mã nguồn, vị trí và lý do. Bản ghi được chấp nhận đi vào luồng chính; bản ghi bị từ chối chờ xem xét. Báo cáo phải chỉ ra tổng số đã gặp, số chấp nhận và số từ chối. Nếu tổng này không cân bằng, có thể còn một bước lọc hoặc bắt ngoại lệ đang che mất dữ liệu.
Không nên tự động dùng selector dự phòng quá rộng mỗi khi selector chính thất bại. Chuyển từ main#catalog article sang mọi article có thể kéo thêm quảng cáo và bài liên quan, khiến số lượng nhìn có vẻ trở lại bình thường. Cách sửa tốt hơn là lưu một fixture thể hiện bố cục mới, xác định lại vùng dữ liệu và bổ sung kiểm thử cho phần nhiễu. Chỉ mở rộng selector khi đã hiểu ảnh hưởng của thay đổi lên các trường trong hợp đồng.
Trang có nhiều phiên bản ngôn ngữ cũng cần chính sách rõ. Nếu cùng id xuất hiện với tên theo hai ngôn ngữ, quy tắc duy nhất theo id có thể không còn phù hợp khi gộp nhiều trang. Có thể dùng khóa ghép nguồn, id và ngôn ngữ, nhưng không nên đổi khóa ngay trong một lần sửa lỗi nhỏ. Cần ghi nhận phiên bản schema, điều kiện khử trùng và cách cập nhật dữ liệu cũ để bên nhận không hiểu hai bản ghi là hai mặt hàng khác nhau.
Với job nhiều trang, đừng dùng vị trí phần tử trong trang làm khóa lưu trữ lâu dài. Một mặt hàng chuyển từ trang hai sang trang một sau khi sắp xếp sẽ có vị trí khác. Thông tin trang và vị trí vẫn hữu ích để truy lỗi, nhưng nên tách khỏi mã định danh nghiệp vụ. Bài cách chia proxy pool cho crawling có thể hỗ trợ phần tổ chức luồng tải khi quy mô tăng, trong khi khóa dữ liệu vẫn phải được thiết kế riêng.
Chuyển HTML sang JSON với checklist nghiệm thu
Trước hết, kiểm tra đầu vào có thể truy lại: URL hiệu lực, thời điểm tải, trạng thái và mã phiên bản bộ chuyển đổi cùng trỏ tới đúng file HTML. Tiếp theo, kiểm tra các quy tắc nội dung: trường bắt buộc không rỗng, trường tùy chọn có cách biểu diễn thống nhất, URL đúng nền và mã không trùng theo phạm vi đã chọn. Cuối cùng, đọc lại JSON đã ghi và xác nhận bên nhận có thể sử dụng các trường mà không cần đoán ý nghĩa.
Trong vận hành, nên phân loại lỗi để cảnh báo có hành động cụ thể. Lỗi kết nối cần xem endpoint và thời gian chờ; lỗi phản hồi cần xem status cùng nội dung; lỗi schema cần xem bản ghi và selector; lỗi ghi file cần xem quyền và dung lượng lưu trữ. Một thông báo chung “chuyển đổi thất bại” ở giao diện có thể chấp nhận cho người dùng cuối, nhưng log kỹ thuật phải đủ chi tiết để người bảo trì xử lý đúng lớp.
Giữ một bộ fixture nhỏ gồm trang bình thường, thiếu giá, thiếu tên và thay đổi bố cục sẽ giảm công kiểm tra sau mỗi lần sửa. Khi thêm trường mới, hãy cập nhật cả schema lẫn mong đợi của fixture. Nếu chỉ sửa code để đi qua một trang đang lỗi mà không cập nhật kiểm thử, lần thay đổi tiếp theo có thể đưa lỗi cũ quay lại. Bộ kiểm thử này đo tính đúng của hợp đồng, không phải tốc độ mạng hay khả năng vượt cơ chế kiểm soát truy cập.

Checklist nghiệm thu bộ chuyển đổi
Một tiêu chí bàn giao hữu ích là người khác có thể chạy lại fixture mà không cần tài khoản website, mật khẩu proxy hoặc lời giải thích miệng. Tài liệu cần nêu phiên bản gói, lệnh chạy, đầu ra mong đợi và phạm vi chưa thử. Khi chuyển sang nguồn thật, bổ sung fixture đại diện và chính sách thu thập trước. Nhờ đó, bộ chuyển đổi trở thành một thành phần kiểm tra được trong pipeline, thay vì một đoạn script chỉ người viết ban đầu hiểu.
Chuyển HTML sang JSON cần schema rõ, vùng DOM đúng và kiểm tra đầu ra trước khi nhập dữ liệu. Hãy chạy fixture, giữ URL nguồn và tách lỗi tải khỏi lỗi chuyển đổi. Theo dõi Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam để tham khảo hướng dẫn tiếp theo về chuyển HTML sang JSON.