JSON-LD Lập trình Web Scraping Bằng Python: Trích Xuất Dữ Liệu Cấu Trúc
Advanced Data Extraction Specialist
Tóm tắt:
- JSON-LD thường là con đường ngắn nhất từ một trang đến một bản ghi có kiểu. Tìm
<script type="application/ld+json">trước khi viết các bộ chọn cho tiêu đề, tác giả, ngày xuất bản, hình ảnh hoặc các trường sản phẩm. - Đọc từng khối JSON-LD. Một trang có thể phân bổ dữ liệu tổ chức, đường dẫn, bài viết, sản phẩm và các câu hỏi thường gặp qua một vài script.
- Chuẩn hóa ba hình dạng cấp cao nhất. Một khối JSON-LD có thể là một đối tượng, một mảng các đối tượng, hoặc một đối tượng có
@graphchứa các nút hữu ích. - Các trường Schema.org là tùy chọn trong thực tế. Chọn nút theo
@type, để các trường vắng mặt làNone, và chỉ xác thực các trường mà quy trình của bạn thực sự yêu cầu. - Beautiful Soup không thực thi JavaScript. Nếu một trang chèn JSON-LD sau khi tải, hãy lấy HTML đã được render trước và chạy cùng một trình phân tích trên phản hồi đó.
- Bạn có thể kiểm tra trình phân tích mà không cần mô hình đám mây. Ví dụ Python hoàn chỉnh dưới đây đọc một nút
Articlethực tế, so sánh tiêu đề của nó với H1 hiển thị, và xác thực đầu ra. - Bắt đầu với các trang công khai, có giới hạn. Tạo một tài khoản miễn phí Scrapeless khi mục tiêu của bạn cần HTML đã được render.
JSON-LD thường chứa các trường mà một trình thu thập thông tin đang chuẩn bị xác dựng từ các yếu tố trang rải rác. Trên một bài viết Scrapeless trực tiếp, một đối tượng Article duy nhất mang theo tiêu đề, tác giả, nhà xuất bản, ngày tháng, URL gốc, hình ảnh chính, mô tả, và từ khóa. Trang được hiển thị vẫn quan trọng, nhưng siêu dữ liệu có cấu trúc cung cấp cho quy trình trích xuất một điểm khởi đầu có kiểu.
JSON-LD tuân theo các thông số kỹ thuật JSON-LD 1.1, trong khi các từ vựng như Article, Product, và BreadcrumbList đến từ mô hình dữ liệu cấu trúc của Schema.org. Không tiêu chuẩn nào đảm bảo rằng mỗi nhà xuất bản sẽ điền vào mọi thuộc tính. Trình phân tích của bạn phải giữ lại sự không chắc chắn đó thay vì sáng tạo ra các giá trị.
JSON-LD Web Scraping Hữu Ích Cho Điều Gì
JSON-LD hữu ích khi một trang xuất bản các sự thật có thể đọc máy cùng với bố cục hướng tới con người của nó. Các nút chung bao gồm:
ArticlevàNewsArticlecho tiêu đề, ngày tháng, tác giả, hình ảnh và nhà xuất bản;Productcho tên, thương hiệu, ưu đãi, đánh giá và định danh;BreadcrumbListcho phân cấp và các đường dẫn loại chính;Organization,Person, vàLocalBusinesscho siêu dữ liệu thực thể;VideoObject,Recipe,Event, và các loại miền cụ thể khác.
Khối script không phải là một điểm cuối riêng tư. Nó là một phần của phản hồi trang và được thiết kế cho các máy như các trình thu thập tìm kiếm. Điều đó khiến nó bền hơn lớp CSS được tạo ra, nhưng không tự động đầy đủ hoặc chính xác. Hãy coi nó như một nguồn để xác thực, không phải là một nhà tiên tri.
Cài Đặt Beautiful Soup
Hướng dẫn này sử dụng Python 3.10 hoặc cao hơn, requests, và beautifulsoup4 4.15.0:
bash
python -m pip install "requests>=2.32,<3" "beautifulsoup4==4.15.0"
API tìm kiếm cây của Beautiful Soup có thể lọc các thẻ theo thuộc tính, điều này đủ để thu thập mọi script trùng khớp. Việc giải mã JSON nằm trong thư viện tiêu chuẩn của Python.
Lấy HTML Nguồn
Bắt đầu với một yêu cầu HTTP bình thường. Mục tiêu được sử dụng ở đây xuất bản JSON-LD của nó trong phản hồi ban đầu, vì vậy việc render JavaScript sẽ thêm chi phí mà không thay đổi kết quả:
python
import requests
URL = "https://www.scrapeless.com/vi/blog/what-is-web-scraping?utm_source=website&utm_medium=blog&utm_campaign=universalscrapingapi&utm_term=json-ld-structured-data-web-scraping"
response = requests.get(
URL,
headers={"User-Agent": "Mozilla/5.0"},
timeout=30,
)
response.raise_for_status()
print("Số byte HTML:", len(response.content))
text
Số byte HTML: 439487
Số byte có thể thay đổi khi gói trang thay đổi. Điểm không thay đổi hữu ích là phản hồi chứa ít nhất một script application/ld+json có thể giải mã.
Phân Tích Từng Khối JSON-LD
Không sử dụng soup.find(...) trừ khi hợp đồng trang rõ ràng hứa hẹn một khối. find_all giữ lại khả năng rằng bài viết, đường dẫn và nhà xuất bản sống trong các script riêng biệt:
python
import json
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, "html.parser")
scripts = soup.find_all("script", type="application/ld+json")
parsed_blocks = []
for script in scripts:
raw = script.get_text(strip=True)
try:
parsed_blocks.append(json.loads(raw))
except json.JSONDecodeError:
continue
print("Số khối JSON-LD:", len(scripts))
print("Số khối đã giải mã:", len(parsed_blocks))
Bỏ qua các khối bị lỗi chỉ an toàn khi bạn cũng ghi lại số lượng đã bị bỏ qua. Một except không có thông báo có thể biến sự suy giảm siêu dữ liệu thành một tập dữ liệu rỗng trông có vẻ thành công.
Chuẩn hóa Đối tượng, Mảng và @graph
Tác giả JSON-LD có nhiều cách hợp lệ để nhóm các nút. Trình tạo này làm phẳng ba hình dạng mà một trình cạo thường gặp:
python
def iter_nodes(value):
if isinstance(value, list):
for item in value:
yield from iter_nodes(item)
elif isinstance(value, dict):
graph = value.get("@graph")
if isinstance(graph, list):
for item in graph:
yield from iter_nodes(item)
else:
yield value
nodes = [node for block in parsed_blocks for node in iter_nodes(block)]
article = next(node for node in nodes if node.get("@type") == "Article")
print("đối tượng đã chuẩn hóa:", len(nodes))
print("loại đã chọn:", article["@type"])
@type cũng có thể là một mảng. Nếu tập dữ liệu của bạn bao gồm các nhà xuất bản phát ra "@type": ["Article", "NewsArticle"], hãy chuẩn hóa trường đó trước khi kiểm tra thành viên.
Xây dựng bản ghi Nullable
Các đối tượng lồng cần được chăm sóc giống như các trường cấp cao. Tác giả có thể là một từ điển, một danh sách, một chuỗi, hoặc vắng mặt. Mục tiêu này sử dụng một từ điển, vì vậy ví dụ đọc nó một cách thận trọng và bảo tồn các trường tùy chọn bị thiếu là None:
python
visible_h1 = soup.find("h1").get_text(" ", strip=True)
author = article.get("author") or {}
publisher = article.get("publisher") or {}
record = {
"type": article.get("@type"),
"headline": article.get("headline"),
"visible_h1": visible_h1,
"author": author.get("name") if isinstance(author, dict) else None,
"publisher": publisher.get("name") if isinstance(publisher, dict) else None,
"published": article.get("datePublished"),
"modified": article.get("dateModified"),
"image": article.get("image"),
"description": article.get("description"),
"keywords": article.get("keywords"),
"source_url": URL,
}
Giữ source_url trong mỗi hàng làm cho các cuộc kiểm toán sau này có thể thực hiện được. Nếu không có nguồn gốc, một trình phân tích đã sửa chữa không thể xác định được các bản ghi nào cần được xây dựng lại.
Xác minh các Trường mà Pipeline của bạn Yêu cầu
Việc xác minh nên phản ánh hợp đồng dòng dưới, không phải mỗi thuộc tính mà Schema.org cho phép:
python
required = ("headline", "author", "published", "source_url")
missing = [field for field in required if not record.get(field)]
if missing:
raise ValueError(f"thiếu các trường bắt buộc: {missing}")
print("tiêu đề:", record["headline"])
print("H1 hiển thị:", record["visible_h1"])
print("các tiêu đề khớp:", record["headline"] == record["visible_h1"])
print("tác giả:", record["author"])
print("nhà xuất bản:", record["publisher"])
print("ngày xuất bản:", record["published"])
text
tiêu đề: Web Scraping là gì? Hướng dẫn chắc chắn 2025
H1 hiển thị: Web Scraping là gì? Hướng dẫn chắc chắn 2025
các tiêu đề khớp: True
tác giả: Emily Chen
nhà xuất bản: Scrapeless
ngày xuất bản: 2025-09-17T08:35:31.224Z
Tiêu đề khớp trên trang này. Đừng tổng quát hóa kết quả đó: biên tập viên đôi khi cập nhật H1 hiển thị mà không cập nhật siêu dữ liệu có cấu trúc, hoặc sử dụng một tiêu đề tìm kiếm ngắn hơn trong JSON-LD. So sánh cả hai bề mặt là một kiểm tra chất lượng hữu ích.
Sẵn sàng chạy cùng một trình phân tích trên một phản hồi được tạo ra? Mở tài khoản Scrapeless và giữ nguyên mã phân tích.
Bộ trích xuất có thể chạy hoàn chỉnh
Kịch bản hoàn chỉnh kết hợp việc phát hiện, chuẩn hóa, lựa chọn, ánh xạ nullable và xác minh:
python
import json
import requests
from bs4 import BeautifulSoup
URL = "https://www.scrapeless.com/vi/blog/what-is-web-scraping?utm_source=website&utm_medium=blog&utm_campaign=universalscrapingapi&utm_term=json-ld-structured-data-web-scraping"
def iter_nodes(value):
if isinstance(value, list):
for item in value:
yield from iter_nodes(item)
elif isinstance(value, dict):
graph = value.get("@graph")
if isinstance(graph, list):
for item in graph:
yield from iter_nodes(item)
else:
yield value
response = requests.get(
URL,
headers={"User-Agent": "Mozilla/5.0"},
timeout=30,
)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
nodes = []
invalid_blocks = 0
scripts = soup.find_all("script", type="application/ld+json")
for script in scripts:
try:
nodes.extend(iter_nodes(json.loads(script.get_text(strip=True))))
except json.JSONDecodeError:
invalid_blocks += 1
article = next(node for node in nodes if node.get("@type") == "Article")
author = article.get("author") or {}
publisher = article.get("publisher") or {}
visible_h1 = soup.find("h1").get_text(" ", strip=True)
record = {
"type": article.get("@type"),
"headline": article.get("headline"),
"visible_h1": visible_h1,
"author": author.get("name") if isinstance(author, dict) else None,
"publisher": publisher.get("name") if isinstance(publisher, dict) else None,
"published": article.get("datePublished"),
"image": article.get("image"),
"keywords": article.get("keywords"),
"source_url": URL,
}
required = ("headline", "author", "published", "source_url")
missing = [field for field in required if not record.get(field)]
if missing:
raise ValueError(f"thiếu các trường cần thiết: {missing}")
print(f"Bytes HTML: {len(response.content)}")
print(f"Các khối JSON-LD: {len(scripts)}")
print(f"Các nút đã chuẩn hóa: {len(nodes)}")
print(f"Các khối không hợp lệ: {invalid_blocks}")
print(f"loại: {record['type']}")
print(f"tiêu đề: {record['headline']}")
print(f"visible H1: {record['visible_h1']}")
print(f"tiêu đề khớp: {record['headline'] == record['visible_h1']}")
print(f"tác giả: {record['author']}")
print(f"nhà xuất bản: {record['publisher']}")
print(f"ngày xuất bản: {record['published']}")
print(f"ký tự từ khóa: {len(record['keywords'] or '')}")
Kết quả chạy trực tiếp trả về một khối hợp lệ, một nút Article đã được chuẩn hóa, không có khối bị lỗi, tiêu đề khớp, tác giả Emily Chen, nhà xuất bản Scrapeless, và 140 ký tự trong chuỗi từ khóa.
Khi JSON-LD Chỉ Xuất Hiện Sau Khi R rendering
Beautiful Soup phân tích các bytes nó nhận được; nó không chạy JavaScript của một trang. Một chẩn đoán nhanh là so sánh phản hồi thô với DOM của trình duyệt. Nếu trình duyệt hiển thị một kịch bản application/ld+json nhưng requests không tìm thấy, hãy lấy HTML đã được render trước khi phân tích.
Lưu ý: Yêu cầu dưới đây cần một tài khoản Scrapeless đã được tài trợ. Tài khoản xác minh đã trả lại phản hồi số dư không đủ trong quá trình kiểm tra cuối cùng, vì vậy cuộc gọi HTTP này là một khoảng trống điều kiện tiên quyết; bộ phân tích trên đã chạy hoàn toàn chống lại trang công khai thực tế.
python
import os
import requests
rendered = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={
"actor": "unlocker.webunlocker",
"input": {
"url": URL,
"method": "GET",
"js_render": True,
},
},
timeout=90,
)
rendered.raise_for_status()
html = rendered.json()["data"]
Chuyển html vào BeautifulSoup và sử dụng lại cùng một bộ chuẩn hóa. API Universal Scraping cung cấp phản hồi đã được render; nó không thay đổi hợp đồng JSON-LD.
Các Vấn Đề Dữ Liệu JSON-LD Thông Thường
Trang có nhiều nút khớp
Chọn theo cả loại và danh tính. Đối với các biến thể sản phẩm, sử dụng @id, URL, SKU, hoặc một trường ổn định khác thay vì lấy nút Product đầu tiên.
@type là một mảng
Chuyển nó thành một tập hợp trước khi kiểm tra thành viên. Một thử nghiệm bình đẳng nghiêm ngặt với một chuỗi sẽ bỏ lỡ một nút đa loại hợp lệ.
Kịch bản chứa các thực thể HTML hoặc chú thích
JSON-LD nên là văn bản JSON hợp lệ. Nếu một nhà xuất bản bọc nó trong cú pháp không hợp lệ, hãy ghi lại khối đó là bị lỗi và sửa bộ phân tích cho nguồn đã biết đó; không áp dụng các thay thế chuỗi rộng có thể làm hỏng các giá trị hợp pháp.
Siêu dữ liệu có cấu trúc không đồng ý với văn bản hiển thị
Lưu trữ cả hai giá trị và xác định ưu tiên cho trường hợp sử dụng của bạn. Kiểm toán tìm kiếm có thể thích tiêu đề JSON-LD; giám sát nội dung có thể thích H1 hiển thị. Một sự không khớp là dữ liệu, không chỉ là một lỗi.
Một trường thay đổi từ đối tượng sang danh sách
Chuẩn hóa ở ranh giới. Tác giả và hình ảnh thường chuyển đổi giữa một đối tượng và một mảng khi CMS của một nhà xuất bản phát triển.
Kết Luận
Một bộ thu thập JSON-LD đáng tin cậy thực hiện bốn điều: thu thập mọi kịch bản khớp, giải mã mà không ẩn các khối bị lỗi, chuẩn hóa từ điển, danh sách và @graph, sau đó xác minh một hợp đồng nhỏ ở hạ nguồn. Con đường đó ngắn hơn và thường ổn định hơn là tái xây dựng cùng một bản ghi từ các bộ chọn bố cục trang. Giữ DOM hiển thị như một kiểm tra chéo, giữ nguồn gốc, và chỉ giới thiệu rendering khi HTML ban đầu chứng minh rằng điều đó là cần thiết.
Bắt đầu với gói miễn phí Scrapeless, xem xét tài liệu dành cho nhà phát triển, và kiểm tra giá của Scrapeless trước khi chuyển một corpus đã được render vào sản xuất.
Câu hỏi thường gặp
Q: Khóa JSON-LD dễ thu thập hơn HTML hiển thị không?
Có, khi nhà xuất bản bao gồm các trường bạn cần. JSON-LD cung cấp cho bạn các thuộc tính và kiểu đã đặt tên, trong khi HTML hiển thị thường yêu cầu các bộ chọn và dọn dẹp văn bản; bạn vẫn nên so sánh các trường quan trọng với trang đã được render.
Q: Tại sao tôi nên phân tích từng script application/ld+json?
Một trang có thể đặt các thực thể khác nhau trong các khối riêng biệt. Đọc chỉ script đầu tiên có thể trả về tổ chức hoặc breadcrumb và bỏ lỡ bài viết hoặc sản phẩm mà bạn muốn.
Q: Điều gì có nghĩa là @graph trong việc chiết xuất?
@graph nhóm một số nút JSON-LD bên trong một đối tượng. Làm phẳng đồ thị, sau đó chọn các nút theo @type, @id, URL hoặc một định danh ổn định khác.
Q: Thì sao nếu một thuộc tính JSON-LD bị thiếu?
Giữ các thuộc tính tùy chọn là None và chỉ thất bại khi một trường yêu cầu theo hợp đồng của bạn bị thiếu. Schema.org mô tả các thuộc tính có thể; nó không buộc các nhà xuất bản phải điền tất cả chúng.
Q: JSON-LD có thể khác với trang hiển thị không?
Có. Siêu dữ liệu và nội dung hiển thị có thể được cập nhật theo các lịch trình khác nhau hoặc tối ưu hóa cho các bề mặt khác nhau. Lưu cả hai giá trị khi sự khác biệt có ý nghĩa và làm cho sự ưu tiên rõ ràng.
Q: Tôi có cần trình duyệt để chiết xuất JSON-LD không?
Không khi script có mặt trong HTML ban đầu. Bạn chỉ cần render khi JavaScript phía khách hàng chèn hoặc sửa đổi dữ liệu có cấu trúc sau khi phản hồi thô đến.
Q: Liệu việc chiết xuất JSON-LD công khai có luôn được phép không?
Không có quy tắc chung nào làm cho mọi việc thu thập hợp pháp hoặc được phép. Xem xét các điều khoản của trang web và chỉ thị robots, giữ khối lượng yêu cầu trong giới hạn, chỉ thu thập các trường bạn cần, và nhận tư vấn pháp lý cho các sử dụng nhạy cảm hoặc thương mại.
Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.



