🎯 Trình duyệt đám mây tùy chỉnh, chống phát hiện được hỗ trợ bởi Chromium tự phát triển, thiết kế dành cho trình thu thập dữ liệu webtác nhân AI. 👉Dùng thử ngay
Quay lại blog

Lập chỉ mục theo sơ đồ trang: Tìm URL trước khi bạn lấy chúng.

James Thompson
James Thompson

Scraping and Proxy Management Expert

22-Jul-2026

Tóm tắt:

  • Hầu hết các trình thu thập thông tin phát hiện URL bằng cách theo dõi các liên kết, điều này có nghĩa là tải xuống các trang bạn không muốn để tìm các trang bạn muốn.
  • Một sitemap cung cấp danh sách ngay từ đầu: một yêu cầu HTTP trả về mọi URL mà trang web muốn lập chỉ mục, đã được loại bỏ trùng lặp bởi nhà xuất bản.
  • Lọc một sitemap thực trong hướng dẫn này đã cắt giảm 7,577 mục xuống còn 597 mục phù hợp với phần mục tiêu, trước khi tải xuống một trang nào.
  • Đặt ngân sách thu thập rõ ràng từ danh sách đó thay vì thu thập cho đến khi có điều gì đó ngăn bạn — giới hạn thuộc về mã, không phải ý định của bạn.
  • Chỉ kết xuất JavaScript khi dữ liệu cần nó; các trang trong hướng dẫn này phục vụ tiêu đề của chúng ở phía máy chủ, vì vậy việc lấy dữ liệu không được kết xuất nhanh hơn và trả về cùng một trường.
  • Bắt đầu với gói miễn phí Scrapeless và chỉ vào bước phát hiện vào một sitemap mà bạn được phép thu thập.

Các trình thu thập theo liên kết hoạt động và chúng rất lãng phí. Để tiếp cận các trang bài viết của một trang web, bạn tải xuống trang chính, danh sách danh mục, phân trang, trang thẻ và bất kỳ thứ gì khác ngăn cách giữa điểm vào và nội dung — sau đó vứt bỏ hầu hết chúng đi.

Một sitemap bỏ qua điều đó. Nó là một danh sách các URL mà nhà xuất bản muốn phát hiện rõ ràng, điều này khiến nó trở thành cơ chế phát hiện rẻ nhất có sẵn và ít có khả năng làm phiền ai nhất.

Những gì một Sitemap cung cấp cho bạn

Một sitemap là một tệp XML liệt kê các URL của một trang web, được định nghĩa bởi giao thức Sitemaps. Có hai hình thái và bạn cần xử lý cả hai:

  • Một urlset chứa các mục <url><loc> trỏ đến các trang.
  • Một sitemapindex chứa các mục <sitemap><loc> trỏ đến các sitemap khác, được sử dụng khi một trang web vượt quá giới hạn 50,000 URL hoặc 50 MB mỗi tệp của giao thức.

Cả hai đều sử dụng phần tử <loc> giống nhau, vì vậy bộ phân tích bên dưới đọc <loc> và sau đó quyết định xem nó đang xem gì. Các sitemap cũng thường được phục vụ dưới định dạng gzipped, vì vậy một trình thu thập nên xử lý điều đó một cách minh bạch.

Nơi tìm một cái: kiểm tra /sitemap.xml trước, sau đó là chỉ thị Sitemap: bên trong robots.txt, mà giao thức loại trừ robot định nghĩa là nơi tiêu chuẩn để quảng cáo nó.

Các yêu cầu trước

  • Python 3.9 trở lên. Bước phát hiện chỉ sử dụng thư viện tiêu chuẩn.
  • Một khóa API Scrapeless cho bước lấy dữ liệu:
bash Copy
export SCRAPELESS_API_KEY="your_api_key_here"

Các ví dụ dưới đây chỉ vào sitemap của Scrapeless, vì vậy hướng dẫn an toàn khi chạy chính xác như đã viết. Đổi sang một sitemap mà bạn được phép thu thập khi bạn điều chỉnh nó.

Khám phá và Lọc

Một yêu cầu, sau đó lọc trong bộ nhớ. Chưa có gì được lấy từ trang web:

python Copy
import gzip, re, urllib.request

SITEMAP = "https://www.scrapeless.com/sitemap.xml"
LOC_RE = re.compile(r"<loc>\s*([^<\s]+)\s*</loc>", re.I)

def fetch_xml(url: str) -> str:
    req = urllib.request.Request(url, headers={"User-Agent": "sitemap-demo/1.0"})
    with urllib.request.urlopen(req, timeout=60) as r:
        raw = r.read()
    if url.endswith(".gz") or raw[:2] == b"\x1f\x8b":
        raw = gzip.decompress(raw)
    return raw.decode("utf-8", errors="replace")

xml = fetch_xml(SITEMAP)
is_index = "<sitemapindex" in xml.lower()
urls = LOC_RE.findall(xml)

print(f"document type: {'sitemap index' if is_index else 'url set'}")
print(f"total <loc> entries: {len(urls)}")

blog = sorted({u for u in urls if "/en/blog/" in u})
print(f"filtered to /en/blog/: {len(blog)}")
print(f"first: {blog[0]}")
text Copy
document type: url set
total <loc> entries: 7,577
filtered to /en/blog/: 597
first: https://www.scrapeless.com/vi/blog/10-best-no-code-web-scrapers

Đó là toàn bộ lập luận cho cách tiếp cận này: 7,577 URL được liệt kê và giảm xuống còn 597 URL liên quan, với chi phí chỉ một yêu cầu. Một trình thu thập theo liên kết sẽ lấy hàng trăm trang để đạt được cùng danh sách đó và vẫn sẽ bỏ lỡ bất cứ điều gì không được liên kết từ một đường dẫn mà nó tình cờ đi qua.

Ba chi tiết trong mã đó có trọng lượng.

Kiểm tra gzip kiểm tra các byte ma thuật thay vì tin tưởng vào phần mở rộng tệp, vì nhiều máy chủ trả về nội dung gzipped từ một URL .xml. Chữ ký hai byte \x1f\x8b mà nó tìm kiếm là tiêu đề định nghĩa trong đặc tả định dạng tệp GZIP.

sorted({...}) là một phép tạo tập hợp, vì vậy các URL trùng lặp sẽ bị loại bỏ trước khi bạn đếm chúng. Các sitemap thường chứa các mục trùng lặp, đặc biệt là khi một trang web được ghép lại từ nhiều trình tạo khác nhau.

Việc phát hiện <sitemapindex> quan trọng vì một chỉ mục có nghĩa là các giá trị <loc> mà bạn vừa thu thập là các sitemap khác, không phải các trang. Nếu is_index là true, hãy lấy từng cái trong số đó và lặp lại trước khi coi bất kỳ điều gì là một URL trang.

Đặt ngân sách rõ ràng, sau đó lấy dữ liệu

Khám phá thì rẻ, nhưng việc lấy dữ liệu lại không. Số lượng trang mà bạn sẽ nhận được nên là một hằng số trong mã, chứ không phải là một thuộc tính nổi lên từ việc vòng lặp chạy lâu hay không:

python Copy
import json, os, re, urllib.request

SITEMAP = "https://www.scrapeless.com/sitemap.xml"
API = "https://api.scrapeless.com/api/v2/unlocker/request"
LOC_RE = re.compile(r"<loc>\s*([^<\s]+)\s*</loc>", re.I)
TITLE_RE = re.compile(r"<title[^>]*>(.*?)</title>", re.S | re.I)

def fetch_sitemap(url: str) -> str:
    req = urllib.request.Request(url, headers={"User-Agent": "sitemap-demo/1.0"})
    with urllib.request.urlopen(req, timeout=60) as r:
        return r.read().decode("utf-8", errors="replace")

def fetch_page(url: str) -> str:
    body = json.dumps({
        "actor": "unlocker.webunlocker",
        "input": {"url": url, "js_render": False},
    }).encode()
    req = urllib.request.Request(API, data=body, headers={
        "x-api-token": os.environ["SCRAPELESS_API_KEY"],
        "Content-Type": "application/json",
    })
    with urllib.request.urlopen(req, timeout=180) as r:
        return json.loads(r.read())["data"]

urls = sorted({u for u in LOC_RE.findall(fetch_sitemap(SITEMAP)) if "/en/blog/" in u})
print(f"số ứng cử viên sau khi lọc và loại bỏ trùng: {len(urls)}")

BUDGET = 3
print(f"ngân sách crawl: {BUDGET}")

for url in urls[:BUDGET]:
    html = fetch_page(url)
    m = TITLE_RE.search(html)
    title = re.sub(r"<[^>]+>", "", m.group(1)).strip() if m else "(không có tiêu đề)"
    print(f"  {url.rsplit('/', 1)[-1]} -> {title}")
text Copy
số ứng cử viên sau khi lọc và loại bỏ trùng: 597
ngân sách crawl: 3
  10-best-no-code-web-scrapers -> 10 Công Cụ Web Scraper Không Cần Code Tốt Nhất cho Việc Trích Xuất Dữ Liệu Một Cách Dễ Dàng vào Năm 2025
  20-ways-for-web-scraping-without-getting-blocked -> 20 Cách Lấy Dữ Liệu Web Mà Không Bị Chặn
  403-web-scraping -> Lỗi 403 Trong Web Scraping: 10 Giải Pháp Dễ Dàng Để Sửa Các Yêu Cầu Bị Cấm

BUDGET là một hằng số được áp dụng với một phép cắt. Điều này là có chủ ý: một crawler có điều kiện dừng là "danh sách đã hết" sẽ hoạt động rất khác biệt trên một phần vài trăm URL so với một phần với hàng chục nghìn URL, và sự khác biệt chỉ hiển thị trong sản xuất.

Lưu ý rằng js_render được đặt thành False. Những trang này phục vụ <title> của chúng trong HTML ban đầu, vì vậy việc render sẽ thêm chi phí và độ trễ cho một trường đã có sẵn. Chỉ render khi dữ liệu bạn cần được ghi vào DOM bởi một script - không phải theo mặc định. Scrapeless Universal Scraping API xử lý cả hai, và hướng dẫn render JS hướng dẫn cách xác định bạn đang ở trong trường hợp nào.

Số lượng URL là một bức tranh tạm thời. Một sitemap là một tài liệu sống, vì vậy việc chạy lại khám phá vào một ngày khác sẽ trả về một số lượng khác - đó chính là lý do bạn cần đọc nó mỗi lần chạy thay vì mã cứng một danh sách.

Điểm sửa lỗi

/sitemap.xml trả về 404. Đọc robots.txt và tìm một dòng Sitemap:, có thể dẫn đến một nơi khác hoàn toàn. Một số trang web chỉ xuất bản ở đó; một số không xuất bản gì cả, trong trường hợp đó, việc theo liên kết là lựa chọn còn lại của bạn.

Bộ phân tích trả về không có URL từ một tệp trông hợp lệ. Kiểm tra xem phản hồi có được nén gz và không được giải nén không - kiểm tra byte phép màu ở trên xử lý trường hợp thông dụng. Cũng xác nhận rằng bạn đã lấy XML chứ không phải trang lỗi HTML, điều mà một chuyển hướng đến trang 404 thân thiện tạo ra.

Số lượng có vẻ quá thấp. Tài liệu có thể là một chỉ mục sitemap. Mỗi <loc> trong đó là một sitemap khác để lấy, và các URL trang là một cấp dưới.

Các mục chỉ vào các URL không còn tồn tại. Sitemaps được tạo ra và các trình tạo thường chậm trễ. Coi danh sách như những ứng cử viên thay vì là sự đảm bảo, và mong đợi một số mục sẽ trả về 404.

Kiểm tra các điều khoản của trang web và robots.txt trước khi crawl bất cứ điều gì, giữ việc thu thập chỉ trên các trang công cộng, và giữ ngân sách tương xứng với những gì trang web có thể phục vụ một cách thoải mái. Một sitemap cho bạn biết những gì một nhà xuất bản sẵn sàng cho chỉ mục; nó không phải là một giấy phép để lấy tất cả một cách nhanh chóng.

Kết luận

Crawl dựa trên sitemap thay thế phần lãng phí nhất của một crawler - khám phá - bằng một yêu cầu duy nhất. Trong hướng dẫn này, điều đó có nghĩa là liệt kê 7,577 URL, thu hẹp xuống 597 cái quan trọng, và chỉ lấy 3 cái, với giới hạn được viết vào mã thay vì để ngẫu nhiên.

Thói quen mà tổng quát vượt ra ngoài sitemaps là thứ tự: liệt kê trước, lọc và loại bỏ trùng khi nó vẫn miễn phí, quyết định rõ ràng số lượng bạn sẽ lấy, và chỉ sau đó bắt đầu gửi yêu cầu. Hầu hết các crawler gặp rắc rối thực hiện các bước theo thứ tự ngược lại.
Bắt đầu với gói miễn phí Scrapeless để thực hiện bước lấy dữ liệu từ một nguồn mà bạn được phép thu thập, và xem xét giá cả của Scrapeless khi bạn xác định một công việc định kỳ.

Câu hỏi thường gặp

H: Làm thế nào để tôi tìm thấy sơ đồ trang web của một trang?

Hãy thử /sitemap.xml trước, sau đó đọc robots.txt để tìm chỉ dẫn Sitemap:, mà RFC 9309 định nghĩa là nơi chính để quảng bá. Các trang web lớn thường xuất bản một chỉ mục tại đường dẫn đó trỏ tới nhiều sơ đồ phần thay vì một tệp phẳng duy nhất.

H: Sự khác biệt giữa chỉ mục sơ đồ và tập hợp URL là gì?

Một tập hợp URL liệt kê các URL trang; một chỉ mục sơ đồ liệt kê các tệp sơ đồ khác. Cả hai đều sử dụng các phần tử <loc>, vì vậy một trình phân tích chỉ nhìn vào <loc> sẽ vui vẻ trả về các URL sơ đồ trong khi bạn nghĩ rằng bạn có các trang. Kiểm tra một phần tử gốc <sitemapindex> và truy hồi khi bạn tìm thấy một — sự phân chia tồn tại bởi vì giao thức giới hạn một tệp đơn lẻ ở 50.000 URL hoặc 50 MB.

H: Việc thu thập dữ liệu từ một sơ đồ có tốt hơn việc theo dõi các liên kết không?

Thường thì có: một yêu cầu trả về các URL mà nhà xuất bản đã liệt kê rõ ràng, thay vì lấy dữ liệu từ các trang trung gian để tìm chúng. Sự đánh đổi là độ bao phủ — một sơ đồ chỉ chứa những gì người tạo quyết định bao gồm, vì vậy các trang tồn tại nhưng bị bỏ qua sẽ vẫn vô hình. Việc theo dõi các liên kết vẫn thắng khi bạn cần tất cả mọi thứ có thể tiếp cận thay vì chỉ những gì được quảng cáo.

H: Tôi có nên xử lý JavaScript khi thu thập dữ liệu từ một sơ đồ không?

Chỉ khi trường bạn muốn không có trong HTML ban đầu. Các trang trong hướng dẫn này phục vụ <title> ở phía máy chủ, vì vậy js_render được đặt là False và việc lấy dữ liệu trở nên rẻ hơn và nhanh hơn. Kiểm tra một trang trước: nếu dữ liệu xuất hiện trong mã nguồn, bạn không cần xử lý.

H: Tôi nên lấy bao nhiêu trang mỗi lần chạy?

Đặt một con số rõ ràng và cắt danh sách ứng cử viên tới con số đó, như BUDGET đã làm ở trên. Giá trị đúng phụ thuộc vào khả năng của trang web và nhu cầu của bạn, nhưng điều quan trọng là đó là một quyết định được ghi lại trong mã chứ không phải là tác dụng phụ của chiều dài danh sách — điều này biến một công việc phần nhỏ và một công việc toàn bộ trang thành những sự kiện rất khác nhau.

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.

Bài viết phổ biến nhất

Danh mục