Phân tích HTML theo phong cách jQuery trong Python với pyquery Web Scraping
Senior Web Scraping Engineer
Tóm tắt:
- pyquery cung cấp API của jQuery trong Python. Nếu bạn biết
$("div.quote").find("small.author").text(), bạn đã biết pyquery. - Điều pyquery không làm là lấy dữ liệu. Nó bọc
lxmlđể phân tích và chọn lọc; nó không có trình khách HTTP và không chạy JavaScript. - Sự khác biệt thể hiện trong một script. Một GET đơn giản trên trang demo render bằng JavaScript cho pyquery 0 node quote; cùng một URL thông qua API Scraping Universal Scraping với
js_rendercho nó tất cả 10. - Quá trình trích xuất là có thật trong hướng dẫn này. Một lần chạy trực tiếp đã sử dụng
.items(),.find(), và.text()để kéo tất cả 10 trích dẫn cùng với tác giả và thẻ từ HTML đã render. - Hai lớp tách biệt. Scrapeless lấy dữ liệu và render; pyquery chọn lọc. Không bên nào can thiệp vào công việc của bên kia.
- Miễn phí để bắt đầu ở phía lấy dữ liệu. Tạo khóa API Scrapeless của bạn tại app.scrapeless.com.
pyquery là gì, và nó không phải là gì
pyquery là một thư viện Python cung cấp API kiểu jQuery dựa trên lxml. Bạn bọc markup trong một đối tượng PyQuery — thường được gọi là d — và sau đó chọn và duyệt bằng cùng các lệnh mà một nhà phát triển front-end đã sử dụng: d("selector"), .find(), .eq(), .text(), .attr(), .items(). Đối với bất kỳ ai đến từ trình duyệt, đây là con đường ngắn nhất từ "Tôi biết cách truy vấn DOM" đến "Tôi có thể trích xuất điều này trong Python", và vì nó dựa trên lxml, nên việc chọn lọc bên dưới diễn ra nhanh chóng.
Đây là một thư viện phân tích và chọn lọc, không hơn. pyquery không có trình khách HTTP, không giữ phiên và không chạy JavaScript. Đưa cho nó một chuỗi và nó sẽ xây dựng một tài liệu có thể truy vấn; yêu cầu nó lấy một URL và, mặc dù nó có thể kỹ thuật mà nói là lấy được một, nó sử dụng một yêu cầu đơn giản mà không có render, đây là công cụ sai cho bất kỳ trang nào được xây dựng bởi các script. Vì vậy, mỗi thiết lập "web scraping pyquery" là hai lớp: một cái trả về HTML đã render trung thực, và pyquery chọn lọc từ đó. Hướng dẫn này sử dụng API Scraping Universal Scraping cho lớp đầu tiên. Hướng dẫn web scraping Python rộng hơn bàn về hệ sinh thái xung quanh.
Cài đặt
pyquery 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à pyquery 2.0.1:
bash
pip install "pyquery==2.0.1" requests
Giữ khóa của bạn trong môi trường, không bao giờ trong mã nguồn:
bash
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"
Lấy HTML đáng giá để phân tích
Chất lượng chọn lọc bị giới hạn bởi độ trung thực khi lấy dữ liệu, vì vậy hãy bắt đầu từ đó. Trên một trang render bằng JavaScript, markup mà một trình khách HTTP đơn giản nhận được không phải là markup 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 định nghĩa bởi các quy định về kịch bản HTML. Một script tính toán sự khác biệt thông qua chính pyquery:
python
# fidelity.py — những gì pyquery thấy: GET thuần túy so với render phía server
import os
import requests
from pyquery import PyQuery as pq
URL = "https://quotes.toscrape.com/js/"
plain = requests.get(URL, timeout=60).text
print("plain GET chars:", len(plain), "| quote nodes:", pq(plain, parser="html")("div.quote").length)
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("rendered chars:", len(rendered), "| quote nodes:", pq(rendered, parser="html")("div.quote").length)
Chạy chương trình in ra 0 node trích dẫn cho lần lấy dữ liệu thuần túy và 10 cho lần render:
text
plain GET chars: 5806 | quote nodes: 0
rendered chars: 8940 | quote nodes: 10
Việc render, mở khóa và định tuyến proxy đều xảy ra phía server trong một POST — Universal Scraping API là lớp lấy dữ liệu, và markup đã render là những gì pyquery chọn từ đó.
Trích xuất với API jQuery
Với HTML thực trong tay, pyquery thực hiện việc trích xuất theo cách mà jQuery sẽ làm. .items() biến một lựa chọn thành một iterator của các đối tượng PyQuery, .find() giới hạn một selector phụ cho mỗi đối tượng, và .text() đọc văn bản — các selector theo quy định W3C về selector, cùng cú pháp mà jQuery sử dụng:
python
# extract.py — lấy trang đã render, sau đó chọn lọc với API jQuery
import os
import requests
from pyquery import PyQuery as pq
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()
d = pq(resp.json().get("data", ""), parser="html")
records = []
for quote in d("div.quote").items():
records.append({
"text": quote.find("span.text").text(),
"author": quote.find("small.author").text(),
"tags": [pq(tag).text() for tag in quote.find("a.tag").items()],
})
print("records:", len(records))
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, thẻ và tất cả:
```text
records: 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à kết xuất, một đối tượng PyQuery để truy vấn. Bộ lặp .items() là thành ngữ pyquery đáng nhớ — nó biến một lựa chọn thành các đối tượng theo bản ghi mà bạn có thể .find() vào, tương đương trực tiếp với .each() của jQuery.
Nhận khóa API của bạn trên gói miễn phí: app.scrapeless.com
Mẫu nâng cao
- Luôn lặp với
.items(). Việc lặp qua một lựa chọnPyQuerytrực tiếp sẽ cho ra các phần tử lxml thô, không phải đối tượngPyQuery, vì vậy.find()sẽ không hoạt động..items()cung cấp cho bạn các đối tượng được bọc với đầy đủ API trong mỗi đối tượng. - Đọc thuộc tính với
.attr().quote.find("a::attr(href)")không phải là cú pháp pyquery; hãy sử dụngquote.find("a").attr("href"), giống hệt như trong jQuery. - Chuyển
parser="html"cho các trang thực. Nó chọn trình phân tích HTML khoan dung của lxml, xử lý các đánh dấu không hợp lệ mà các trang thực sẽ gửi; mặc định có thể nghiêm ngặt hơn bạn muốn. - Chuỗi, không cần truy vấn lại.
d("div.quote").eq(0).find("small.author")giới hạn mỗi bước đến bước trước đó, nhanh hơn và gần với cách mà jQuery bạn đã biết đọc.
Khắc phục sự cố
- Không có nút nào từ trang bạn có thể thấy trong trình duyệt. Nội dung được kết xuất bằng JavaScript và việc lấy của bạn đã trả về HTML trước khi được kết xuất. Đếm một bộ chọn đã biết theo cách mà script đầu tiên làm; tài liệu gần như rỗng là vấn đề lấy, được sửa bằng
js_render, không phải là vấn đề bộ chọn. .find()gây raAttributeError. Bạn đã lặp qua lựa chọn trực tiếp thay vì với.items(), vì vậy bạn đã nhận được một phần tử lxml trần. Chuyển vòng lặp sangfor x in sel.items():..text()trả về tất cả được nối lại. pyquery nối văn bản con. Giới hạn chặt chẽ hơn với bộ chọn cụ thể hơn, hoặc đọc một nút đơn với.eq(0).text().- Mã hóa trông sai. Chuyển văn bản phản hồi pyquery-người đầu tiên với
parser="html"; lxml đọc mã hóa đã khai báo của tài liệu khi trình phân tích là trình phân tích HTML.
Kết luận
pyquery xứng đáng có vị trí là lớp lựa chọn nói tiếng jQuery: cùng một .find(), .text(), và .items() mà bạn biết từ trình duyệt, trên một cây lxml nhanh. Lớp quyết định liệu điều đó có khả thi hay không là việc lấy — số liệu 0 so với 10 của script đầu tiên quyết định điều đó — và một POST đã được kết xuất từ máy chủ thu hẹp khoảng cách. Kết nối hai lại với nhau và mười trích dẫn từ trang demo đến như các bản ghi sạch, được chọn theo cách mà bạn đã suy nghĩ.
Tạo tài khoản Scrapeless miễn phí để nhận khóa API, và tài liệu phát triển bao gồm các tham số unlocker.webunlocker. Kiểm tra giá 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
Hỏi: pyquery có thể thu thập dữ liệu trang web một mình không?
Không thực sự. pyquery có thể kéo một URL, nhưng nó làm như vậy với một yêu cầu đơn giản và không có kết xuất JavaScript, vì vậy trên một trang hiện đại, nó chọn từ mã đánh dấu rỗng. Hãy coi nó như một trình phân tích: ghép nó với một lớp lấy — ở đây là Scrapeless Universal Scraping API, mà kết xuất trang ở phía máy chủ — và pyquery xử lý việc lựa chọn từ HTML đã trả về.
Hỏi: pyquery có giống với jQuery không?
Nó phản ánh API của jQuery trong Python — d("selector"), .find(), .text(), .attr(), .items() — nhưng nó chạy ở phía máy chủ trên lxml, không trong trình duyệt, vì vậy nó chọn từ mã đánh dấu tĩnh và không thực thi các script hoặc xử lý sự kiện. Cú pháp lựa chọn chuyển giao; runtime thì không.
Hỏi: pyquery hay BeautifulSoup?
Sở thích. pyquery đọc giống như jQuery và là một lựa chọn tự nhiên nếu bạn đến từ công việc front-end; BeautifulSoup có một API Pythonic hơn. Cả hai đều phân tích cùng một HTML, và cả hai đều cần một lớp lấy riêng cho các trang được kết xuất bằng JavaScript.
Hỏi: pyquery có xử lý các trang được kết xuất bằng JavaScript không?
Không phải tự mình - nó không bao giờ thực thi các script. Nếu nội dung được tải sau HTML ban đầu, một lệnh fetch thông thường sẽ giao cho pyquery một tài liệu trống. Hãy 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 thực hiện.
Q: Việc scraping với pyquery 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ỉ dẫn của robots được chuẩn hóa bởi Giao thức loại trừ Robots, giữ cho khối lượng 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.



