🎯 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

parsel Web Scraping: Bộ chọn CSS và XPath trong Python

Alex Johnson
Alex Johnson

Senior Web Scraping Engineer

23-Jul-2026

Tóm tắt:

  • parsel chọn dữ liệu từ HTML bằng cả CSS và XPath, trên cùng một tài liệu — đó là bộ chọn mà Scrapy sử dụng, có sẵn như một thư viện độc lập.
  • Điều mà parsel không làm là lấy dữ liệu. Nó không có khách hàng HTTP và không chạy JavaScript; bạn đưa cho nó mã nguồn và nó xây dựng một cây truy vấn.
  • Khoảng cách xuất hiện trong một kịch bản. Một GET thông thường trên một trang demo được render bằng JavaScript cho parsel 0 nút quote; cùng URL được lấy qua API Scraping Universal của Scrapeless với js_render cho nó tất cả 10.
  • CSS và XPath, bên cạnh nhau. Một lần chạy trực tiếp kéo 10 tác giả theo hai cách — sel.css("small.author::text")sel.xpath("//small[@class='author']/text()") — từ HTML đã được render.
  • Hai lớp vẫn tách biệt. Scrapeless lấy dữ liệu và render; parsel chọn lựa. Không bên nào can thiệp vào công việc của bên kia.
  • Tự do khởi đầu ở phía lấy dữ liệu. Tạo khóa API Scrapeless của bạn tại app.scrapeless.com.

Điều gì là parsel, và điều gì không phải

parsel là một thư viện Python để trích xuất dữ liệu từ HTML và XML bằng cách sử dụng bộ chọn CSS và biểu thức XPath. Nó là lớp chọn mà Scrapy được xây dựng trên, được đóng gói để bạn có thể sử dụng ở bất kỳ đâu, và nó bọc lxml bên dưới, vì vậy cả hai ngôn ngữ chọn đều chạy trên cùng một cây phân tích nhanh. Lý do để chọn nó thay vì một bộ phân tích chỉ CSS là XPath: khi một trường được xác định bởi vị trí của nó, văn bản của nó, hoặc mối quan hệ của nó với một anh chị em thay vì một lớp, XPath biểu đạt điều đó và CSS không thể.

Nó là một thư viện chọn và không hơn thế. parsel không có khách hàng HTTP, không giữ phiên làm việc, và không chạy JavaScript. Đưa cho nó một chuỗi và nó xây dựng một Selector mà bạn có thể truy vấn; yêu cầu nó lấy một URL và không có phương thức cho điều đó. Vì vậy, mỗi thiết lập "parsel web scraping" có hai lớp: một cái trả về HTML trung thực, và parsel chọn từ nó. Hướng dẫn này sử dụng API Scraping Universal của Scrapeless cho lớp đầu tiên, vì một khách hàng HTTP thông thường trả về mã nguồn đã được render trên bất kỳ trang nào xây dựng nội dung của nó bằng JavaScript. Hướng dẫn tư liệu về web scraping Python rộng hơn đề cập đến hệ sinh thái xung quanh.

Cài đặt

parsel và requests là toàn bộ chuỗi công cụ. Phiên bản mà hướng dẫn này được viết dựa trên là parsel 1.11.0:

bash Copy
pip install "parsel==1.11.0" requests

Giữ khóa của bạn trong môi trường, không bao giờ ở trong mã nguồn:

bash Copy
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"

Lấy HTML đáng để phân tích

Chất lượng lựa chọn bị giới hạn bởi độ chính xác của việc lấy dữ liệu, vì vậy bắt đầu từ đó. Trên một trang được render bằng JavaScript, mã mà một khách hàng HTTP thông thường nhận được không phải là mã mà một người đọc thấy: nội dung chỉ đến sau khi các script xây dựng DOM, một vòng đời được xác định bởi tiêu chuẩn lập trình HTML. Một kịch bản tính toán sự khác biệt qua parsel chính nó:

python Copy
# fidelity.py — những gì parsel thấy: GET thông thường so với render phía server
import os

import requests
from parsel import Selector

URL = "https://quotes.toscrape.com/js/"

plain = requests.get(URL, timeout=60).text
print("kí tự GET thông thường:", len(plain), "| nút quote:", len(Selector(text=plain).css("div.quote")))

resp = requests.post(
    "https://api.scrapeless.com/api/v2/unlocker/request",
    headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
    json={"actor": "unlocker.webunlocker", "input": {"url": URL, "js_render": True}},
    timeout=120,
)
resp.raise_for_status()
rendered = resp.json().get("data", "")
print("kí tự đã render:", len(rendered), "| nút quote:", len(Selector(text=rendered).css("div.quote")))

Chạy lệnh in ra 0 nút quote cho việc lấy thông thường và 10 cho việc được render:

text Copy
kí tự GET thông thường: 5806 | nút quote: 0
kí tự đã render: 8940 | nút quote: 10

Việc render, mở khóa và định tuyến proxy đều xảy ra bên phía máy chủ trong một POST duy nhất — Universal Scraping API là lớp lấy dữ liệu, và mã đã được render là những gì parsel nên chọn từ đó.

Trích xuất với CSS và XPath

Với HTML thực tế trong tay, parsel thực hiện việc trích xuất. cssxpath đều trả về một SelectorList; get trả về kết quả đầu tiên và getall trả về mọi kết quả. Phần tử giả ::text và nút text() đều kéo văn bản, vì vậy bạn có thể đọc cùng một trường theo cả hai cách — CSS tuân theo tiêu chuẩn W3C Selectors và XPath tuân theo tiêu chuẩn W3C XPath:

python Copy
# extract.py — lấy trang đã được render, sau đó chọn bằng CSS và XPath
import os

import requests

from parsel import Selector

resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
timeout=120,
)
resp.raise_for_status()
sel = Selector(text=resp.json().get("data", ""))

css_nodes = sel.css("div.quote")
xpath_authors = sel.xpath("//div[@class='quote']//small[@class='author']/text()").getall()
print("css quote nodes:", len(css_nodes))
print("xpath authors:", len(xpath_authors))

records = []
for quote in css_nodes:
records.append({
"text": quote.css("span.text::text").get(),
"author": quote.xpath(".//small[@class='author']/text()").get(),
"tags": quote.css("a.tag::text").getall(),
})
print("first author:", records[0]["author"])
print("first tags:", records[0]["tags"])

Chạy trực tiếp đã chọn tất cả 10 bản ghi, với CSS và XPath trả về cùng một tác giả:

text Copy
css quote nodes: 10
xpath authors: 10
first author: Albert Einstein
first tags: ['change', 'deep-thoughts', 'thinking', 'world']

Đó là toàn bộ trình thu thập dữ liệu: một POST để lấy và xử lý, một Selector để truy vấn. Kết hợp CSS cho các trường dễ và XPath cho các trường vị trí — quote.xpath("...") chạy theo từng nút — là mẫu giữ cho một trình thu thập dữ liệu dễ đọc khi các trang trở nên phức tạp.

Nhận khóa API của bạn trên gói miễn phí: app.scrapeless.com

Mẫu nâng cao

  • Sử dụng XPath khi CSS không đủ. Lựa chọn theo văn bản (//a[contains(text(), "Next")]), theo vị trí ((//tr)[2]), hoặc theo một trục (following-sibling::td) là lĩnh vực của XPath; CSS không có tương đương.
  • Chuỗi các lựa chọn tương đối với một nút. quote.css(...)quote.xpath(".//...") đều thuộc về nút đó — dấu . đầu tiên trong XPath giữ cho nó tương đối, điều này là sự khác biệt giữa "các tác giả trong trích dẫn này" và "tất cả các tác giả trên trang".
  • Sử dụng get(default="") để tránh None. sel.css("span.missing::text").get(default="") trả về một chuỗi rỗng thay vì None, điều này giữ cho một vòng lặp qua các bản ghi không đều không bị hỏng trên trang lẻ.
  • Kéo thuộc tính với ::attr() hoặc @. sel.css("a::attr(href)")sel.xpath("//a/@href") đều đọc một thuộc tính; sử dụng ngôn ngữ nào mà phần còn lại của lựa chọn đã sử dụng.

Khắc phục sự cố

  • Không có nút từ một trang mà bạn có thể thấy trong trình duyệt. Nội dung được tạo bởi JavaScript và việc lấy của bạn đã trả về HTML trước khi xử lý. Đếm một lựa chọn đã biết theo cách mà đoạn mã đầu tiên thực hiện; một cây gần như trống rỗng là một vấn đề lấy không phải là vấn đề chọn.
  • get() trả về None. Trình chọn không khớp với gì cả. Kiểm tra mã nguồn đã được xử lý, xác nhận lớp hoặc đường dẫn, và truyền một default để mã ở phía dưới không bị hỏng khi không tìm thấy.
  • XPath trả về các phần tử khi bạn muốn văn bản. Thêm /text() vào đường dẫn hoặc .get() trên một lựa chọn CSS ::text; một đường dẫn phần tử trống trả về nút, không phải chuỗi của nó.
  • XPath tương đối lấy toàn bộ trang. Một đường dẫn bắt đầu bằng // là tuyệt đối ngay cả khi được gọi trên một nút. Thêm trước nó với ..//small — để giới hạn nó đến phần tử hiện tại.

Kết luận

parsel xứng đáng có vị trí như là lớp lựa chọn có thể nói cả hai phương ngữ: CSS cho các trường hợp thông thường, XPath cho những trường hợp mà CSS không thể tiếp cận, qua một cây được hỗ trợ bởi lxml. Lớp quyết định xem bất kỳ điều gì trong số đó có khả thi hay không là việc lấy — số liệu 0-so với-10 của đoạn mã đầu tiên giải quyết điều đó — và một POST được xử lý trên máy chủ thu hẹp khoảng cách. Kết nối cả hai lại với nhau và mười trích dẫn của trang demo đến như những bản ghi sạch sẽ, được chọn theo cách nào đọc tốt nhất.

Tạo một tài khoản Scrapeless miễn phí để nhận khóa API, và tài liệu dành cho nhà phát triển bao gồm các tham số unlocker.webunlocker. Kiểm tra giá của Scrapeless khi bạn lập kế hoạch cho một công việc định kỳ.

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

Q: Parsel có thể thu thập dữ liệu từ các trang web chỉ bằng chính nó không?

Không. Parsel chọn dữ liệu từ HTML mà bạn đã có; nó không có khách hàng HTTP và không chạy JavaScript. Kết hợp nó với một lớp lấy — ở đây là API Thu thập Dữ liệu Toàn cầu Scrapeless, cái sẽ xử lý trang ở phía máy chủ — và parsel xử lý việc trích xuất từ mã nguồn đã trả về.

Q: Sự khác biệt giữa parsel và trình chọn Scrapy là gì?
Không, trên thực tế — parsel là công cụ chọn lựa mà Scrapy sử dụng, được phát hành dưới dạng thư viện độc lập. Nếu bạn đã sử dụng response.css hoặc response.xpath trong một con nhện Scrapy, đó chính là parsel. Sử dụng nó trực tiếp cho phép bạn duy trì API chọn lựa mà không cần phải thông qua toàn bộ framework.

Hỏi: Tôi nên sử dụng CSS hay XPath với parsel?

Cả hai, tùy theo nhu cầu. CSS ngắn gọn hơn cho việc chọn lựa dựa trên lớp và thẻ; XPath xử lý việc chọn lựa theo văn bản, vị trí hoặc trục, điều mà CSS không thể diễn đạt. Parsel chạy cả hai trên cùng một cây, vì vậy hãy kết hợp chúng theo từng trường.

Hỏi: Parsel có xử lý các trang được render bằng JavaScript không?

Không tự nó — nó không bao giờ thực thi các script. Nếu nội dung tải sau HTML ban đầu, một lần fetch thông thường sẽ đưa cho parsel một cây trống. Fetch trang thông qua API Scrapeless với js_render trước, sau đó chọn từ HTML đã được render, như hướng dẫn này làm.

Hỏi: Việc scraping với parsel có hợp pháp không?

Thư viện chọn lọc không thay đổi quy tắc thu thập. Chỉ fetch các trang công khai, tôn trọng các điều khoản của trang web và các chỉ thị robots đã được tiêu chuẩn hóa bởi Giao thức loại trừ Robots, giữ khối lượng trong giới hạn và xử lý bất kỳ dữ liệu cá nhân nào theo các luật áp dụng cho bạn.

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