Lập trình Web Scraping Với Rust
API Scraping Đa Năng Không Tính Phí cung cấp HTML đã được lấy hoặc render cho các khách hàng Rust thông qua yêu cầu HTTP xác thực thông thường.
TL;DR
- Rust biến các đường dẫn lỗi thành một phần của hình dạng chương trình. Thất bại HTTP, thiếu trường, bộ chọn không hợp lệ, và chuyển đổi đầu ra có thể được biểu diễn dưới dạng kết quả rõ ràng thay vì giá trị rỗng im lặng.
- reqwest xử lý vận chuyển và scraper xử lý HTML. Các crate có nhiệm vụ riêng biệt, điều này giữ cho việc thu nhận có thể thay thế khi một trang yêu cầu rendering.
- Tokio hỗ trợ yêu cầu đồng thời có giới hạn. Các khách hàng chia sẻ và tập hợp nhiệm vụ được kiểm soát cải thiện thông lượng mà không biến việc phát hiện thành fan-out không giới hạn.
- Các bộ chọn nên được biên dịch một lần. Phân tích các bộ chọn CSS trước vòng lặp ghi và trả về lỗi khởi động khi một bộ chọn không hợp lệ.
- Không có sự trùng khớp nào yêu cầu chẩn đoán. Một shell được render bởi khách hàng, danh tính trang sai, hoặc markup thay đổi có thể tạo ra HTML hợp lệ mà không có bản ghi nào.
Nơi Rust Thêm Giá Trị
Web scraping với Rust phù hợp cho những người thu thập không giám sát, nơi việc sử dụng bộ nhớ có thể dự đoán được, lỗi rõ ràng, và tính đồng thời có kiểm soát quan trọng hơn việc thử nghiệm tương tác nhanh chóng. Rust không làm cho các bộ chọn chính xác hơn tự nó. Nó làm cho các ranh giới xung quanh mạng, phân tích, và lưu trữ khó bị bỏ qua hơn.
Ngăn xếp chung là reqwest cho HTTP, scraper cho phân tích HTML và lựa chọn CSS, và Tokio cho thời gian chạy bất đồng bộ. Ngăn xếp này tài liệu reqwest khuyên tái sử dụng một khách hàng khi thực hiện nhiều yêu cầu để chương trình được hưởng lợi từ việc phân phối kết nối. Điều đó tự nhiên dẫn đến một dịch vụ thu thập với một khách hàng được cấu hình chia sẻ giữa các nhiệm vụ.
Giữ cho bộ phân tích độc lập với vận chuyển. Một hàm chấp nhận &str và trả về các bản ghi có kiểu có thể được kiểm tra với HTML đã lưu. Hàm mạng sau đó có thể trả về HTML của máy chủ, một tài liệu đã được render, hoặc một fixture mà không thay đổi logic trích xuất.
Bản đồ Ngăn Xếp Scraping Rust
| Mối quan tâm | Lựa chọn Rust | Ghi chú thiết kế |
|---|---|---|
| HTTP | khách hàng reqwest | Tái sử dụng khách hàng và kiểm tra trạng thái trước khi đọc dữ liệu |
| HTML | crate scraper | Phân tích một cây tài liệu và truy vấn với các bộ chọn CSS |
| Thời gian chạy bất đồng bộ | Tokio | Thực hiện các nhiệm vụ mạng có giới hạn |
| Bản ghi | Structs cộng với serde | Làm cho các trường bắt buộc và tùy chọn trở nên rõ ràng |
| Xác thực | Kết quả và lỗi tùy chỉnh | Từ chối các trang sai và số lượng trùng khớp không hợp lý |
Crate phân tích xây dựng trên một mô hình phân tích HTML thay vì coi markup như văn bản tùy ý. Quy định phân tích HTML giải thích lý do tại sao một cây tài liệu có thể khác biệt so với chuỗi thẻ nguyên văn: các trình phân tích sửa chữa cấu trúc lồng ghép sai và suy ra các phần tử theo các quy tắc xác định.
Tạo một Bộ Trích Xuất Rust Đã Được Định Kiểu
Mã này là một điều kiện tiên quyết cho môi trường làm việc cục bộ vì Rust không được cài đặt trong không gian làm việc hiện tại. Kết cấu tuân theo các API hiện tại của reqwest và scraper: lấy, chuyển đổi trạng thái không mong đợi thành lỗi, đọc văn bản, phân tích tài liệu, sau đó chọn các trường. Biên dịch nó trong một dự án Cargo với reqwest, scraper, Tokio, serde, và serde_json.
use scraper::{Html, Selector};
use serde::Serialize;
#[derive(Serialize)]
struct Record {
title: String,
href: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(20))
.build()?;
let html = client
.get("https://example.com/")
.send()
.await?
.error_for_status()?
.text()
.await?;
let document = Html::parse_document(&html);
let title_selector = Selector::parse("h1")?;
let link_selector = Selector::parse("a")?;
let title = document
.select(&title_selector)
.next()
.map(|node| node.text().collect::<String>())
.ok_or("missing page heading")?;
let href = document
.select(&link_selector)
.next()
.and_then(|node| node.value().attr("href"))
.map(str::to_owned);
println!("{}", serde_json::to_string_pretty(&Record { title, href })?);
Ok(())
}
Các bộ chọn được phân tích một lần, trước khi trích xuất. Một tiêu đề thiếu trở thành một lỗi vì nó là trường danh tính trang trong ví dụ này. Liên kết là tùy chọn và do đó sử dụng Option<String>. Sự phân biệt đó cho phép hệ thống kiểu mang phần hợp đồng dữ liệu.
Biểu thị Thất Bại Trang Một Cách Rõ Ràng
Một trình thu thập dữ liệu Rust nên phân biệt giữa lỗi vận chuyển, trạng thái HTTP không thành công, loại nội dung không mong đợi, danh tính trang sai và sai sót trong bộ chọn. Việc xóa bỏ những trạng thái đó thành một vector rỗng sẽ loại bỏ thông tin cần thiết để sửa chữa đường dẫn. Một enum lỗi tùy chỉnh có thể giữ các loại đó có thể đọc được bởi máy trong khi vẫn bảo toàn lỗi gốc như bối cảnh.
Cái đặc tả ngữ nghĩa HTTP xác định các lớp trạng thái phản hồi, nhưng một trạng thái thành công không đảm bảo rằng tài liệu kinh doanh mong đợi đã đến. Xác nhận URL cuối cùng và một dấu hiệu cấu trúc trước khi phân tích các hàng lặp lại. Ghi lại số lượng đã chấp nhận và bị từ chối riêng biệt.
- Biên dịch các chuỗi bộ chọn trong quá trình khởi động. Cú pháp không hợp lệ nên ngăn chặn công nhân nhận công việc.
- Xem xét các trường danh tính là bắt buộc. Một bản ghi không có khóa nguồn ổn định của nó không nên đến được lưu trữ.
- Giữ các giá trị tùy chọn như các tùy chọn. Một giá cả, tác giả, hoặc dấu thời gian vắng mặt nên vẫn khác biệt với một chuỗi rỗng.
- Cố ý giới hạn kích thước tài liệu. Các phản hồi lớn cần một giới hạn tiếp nhận liên quan đến lớp trang mong đợi.
Kiểm soát Đối xứng Tokio
Tokio làm cho việc chờ mạng chồng chéo có thể xảy ra, nhưng một công việc thu thập dữ liệu vẫn cần một ngân sách cố định. Một semaphore, luồng đệm, hoặc hàng đợi công nhân có thể giới hạn số yêu cầu đang hoạt động trên mỗi máy chủ. Khách hàng nên được sao chép một cách rẻ rúng trong khi chia sẻ quỹ nội bộ của nó; tập hợp nhiệm vụ nên vẫn được giới hạn theo thiết kế.
Mỗi nhiệm vụ trả về một kết quả có cấu trúc chứa URL nguồn và hoặc là các bản ghi hoặc một lỗi được phân loại. Việc thu thập kết quả đó qua một điều phối viên giữ cho việc ghi lưu trữ và các chỉ số được sắp xếp. Nó cũng ngăn cản một nhiệm vụ tách biệt không bị thất bại ngoài con đường kế toán.
Giữ cho việc khám phá có giới hạn. Một trình thu thập dữ liệu theo mọi liên kết mà không có quy tắc phạm vi có thể rời khỏi trang web định trước, thăm lại các dạng URL thay thế, hoặc phát triển mà không có điều kiện dừng lại. Chuẩn hóa các URL được phép, giới hạn các mẫu đường dẫn, và lưu trữ các danh tính đã thăm.
Phát hiện Ranh giới JavaScript
reqwest tải xuống các phản hồi của máy chủ; nó không thực thi các script trang. Gói thu thập dữ liệu phân tích nội dung nó nhận được. Nếu một trình duyệt hiển thị các bản ghi không xuất hiện trong mã nguồn trang, mã Rust có thể thành công ở cả hai công việc và vẫn trả về số kết quả bằng không. Kết quả đó là một sự không tương thích về khả năng, không nhất thiết là lỗi bộ chọn.
Tiếp nhận đã render giải quyết sự không tương thích bằng cách trả về tài liệu sau khi script tới cùng một parser. Giữ cho việc phân tách rõ ràng: một chức năng thu được HTML chính xác, và một chức năng khác biến đổi HTML thành các bản ghi kiểu. Thiết kế này ngăn cản các mối quan tâm của trình duyệt lây lan qua mã chuẩn hóa và lưu trữ.
Hoạt động Trong các Quy tắc Nguồn
Trước khi lên lịch một trình thu thập dữ liệu Rust, hãy xác định các máy chủ, đường dẫn, lớp dữ liệu và ngân sách yêu cầu được phép. Xem xét các điều khoản và luật áp dụng. “ Giao thức Loại trừ Robots cung cấp các chỉ thị thu thập dữ liệu theo tiêu chuẩn, nhưng không phải là một sự thay thế cho sự cho phép, phân tích quyền riêng tư, hoặc xem xét hợp đồng.
Khả năng quan sát nên tập trung vào tính chính xác: lớp phản hồi, danh tính trang, thời gian phân tích, số lượng container, các bản ghi đã chấp nhận, và các lỗi phân loại. Tránh lưu trữ toàn bộ thân phản hồi trong nhật ký bình thường. Các thiết bị nên thuộc dữ liệu thử nghiệm có kiểm soát, và các giá trị nhạy cảm nên thuộc ngoài bề mặt chẩn đoán của trình thu thập dữ liệu.
Giữ cho Nguồn gốc Bên Cạnh Bản Ghi Đã Kiểu
Đầu ra đã kiểu không loại bỏ nhu cầu về nguồn gốc. Lưu trữ URL nguồn chuẩn, thời gian tiếp nhận, phiên bản parser, và một kết quả danh tính trang gọn bên cạnh mỗi bản ghi hoặc lô. Những trường này cho phép các hệ thống phía dưới phân biệt sự thay đổi giá trị thực sự từ sự thay đổi bộ chọn hoặc một trang vùng khác.
Giữ cho văn bản thô có sẵn khi chuẩn hóa có thể mất đi ý nghĩa. Các chuỗi tiền tệ, số địa phương, nhãn khả dụng, và ngày tháng con người thường cần quy tắc cụ thể cho nguồn. Một mô hình Rust tốt mang cả trường đã chuẩn hóa và đủ bối cảnh gốc để kiểm tra việc chuyển đổi. Kiểm tra có thể từ chối các kết hợp không thể trước khi tuần hoàn, chẳng hạn như một số lượng số mà không có tiền tệ khi ứng dụng yêu cầu một.
Sự phát triển của sơ đồ nên được thực hiện một cách có chủ ý. Thêm các trường tùy chọn trước, cập nhật người sử dụng, và chỉ sau đó làm cho một trường trở thành yêu cầu sau khi nguồn và đường dẫn chứng minh rằng nó có mặt một cách nhất quán. Cách tiếp cận này sử dụng hệ thống kiểu của Rust như một hợp đồng dữ liệu mà không giả vờ rằng đánh dấu của bên thứ ba là ổn định.
Kết luận
Việc thu thập dữ liệu web với Rust là một sự lựa chọn tốt khi người thu thập phải chạy trong thời gian dài với việc xử lý lỗi rõ ràng và một ngân sách tài nguyên được kiểm soát. Tái sử dụng một khách hàng reqwest, phân tích bộ chọn một lần, thể hiện sự vắng mặt với các tùy chọn, và giới hạn các nhiệm vụ Tokio. Nếu JavaScript phía khách hàng sở hữu dữ liệu, hãy thay đổi cách HTML được thu thập thay vì viết lại parser đã kiểu.
Sẵn sàng kết nối Rust với Dữ liệu Web Được Render không?
Giữ reqwest và scraper như là biên giới ứng dụng đã kiểu trong khi Scrapeless xử lý việc tiếp nhận cho các trang cần render.
Đăng ký hôm nay và nhận $5 tín dụng miễn phí — không cần thẻ tín dụng.
Nhận Tín Dụng $5 của Bạn →Câu hỏi thường gặp
Các gói Rust nào được sử dụng để thu thập dữ liệu web?
reqwest là một khách hàng HTTP thông dụng, scraper cung cấp phân tích HTML và bộ chọn CSS, và Tokio thực hiện công việc không đồng bộ. Serde thường được thêm vào khi đầu ra hoặc phản hồi tiếp nhận là JSON.
reqwest có thể thực thi JavaScript không?
Không. reqwest gửi các yêu cầu HTTP và trả về các phản hồi từ máy chủ; nó không chạy một vòng lặp sự kiện trình duyệt. Sử dụng tiếp nhận đã render khi các script tạo ra nội dung cần thiết.
Rust có cần thiết cho một trình thu thập nhỏ không?
Không. Một khách hàng chặn có thể phù hợp cho một công việc tuần tự đơn lẻ. Rust không đồng bộ trở nên hữu ích khi thiết kế có nhiều chờ mạng độc lập và ngân sách đối xứng rõ ràng.
Rust nên xử lý các trường thu thập bị thiếu như thế nào?
Rust nên mô hình hóa các trường bắt buộc như là các giá trị cần có và các trường tùy chọn như là. OptionTừ chối các bản ghi thiếu trường danh tính thay vì thay thế bằng một khoảng trống không rõ ràng.
Việc thu thập dữ liệu web với Rust có hợp pháp không?
Ngôn ngữ không thay đổi phân tích pháp lý. Giới hạn công việc vào dữ liệu công khai được ủy quyền, xem xét điều khoản trang web và chỉ thị cho robot, tôn trọng các kiểm soát truy cập và nhận tư vấn pháp lý khi việc thu thập ảnh hưởng đến con người hoặc dữ liệu được quy định.