Rnet Web Scraping: Giả mạo dấu vân tay TLS của trình duyệt
Senior Web Scraping Engineer
Tóm tắt:
- rnet là một khách hàng HTTP bất đồng bộ mô phỏng dấu vân tay TLS của một trình duyệt thực sự, vì vậy một máy chủ định hình bắt tay sẽ thấy Chrome, không phải là mặc định của Python. Nó được xây dựng trên Rust và được cung cấp cho Python.
- Điều mà rnet không làm là hiển thị JavaScript. Một dấu vân tay hoàn hảo giúp yêu cầu được chấp nhận; nó không thực thi các kịch bản xây dựng nội dung của một trang.
- Dấu vân tay là thật trong hướng dẫn này. Một lần chạy trực tiếp giả mạo Chrome đã tạo ra một JA3 hình dạng trình duyệt và một JA4
t13d1516h2qua HTTP/2 - và vẫn không tìm thấy 0 khối trích dẫn trên một trang được xây dựng bằng kịch bản. - rnet cũng là khách hàng gọi Scrapeless. Khách hàng bất đồng bộ tương tự đã gửi POST URL tới API thu thập thông tin toàn cầu Scrapeless, nhận được HTML đã được hiển thị, và lấy tất cả 10 tác giả.
- Hai vấn đề khác nhau, được tách biệt rõ ràng. rnet xử lý lớp dấu vân tay TLS; Scrapeless xử lý việc hiển thị. Không cái nào thay thế cho cái kia.
- Miễn phí để bắt đầu ở phía thu thập. Tạo khóa API Scrapeless của bạn tại app.scrapeless.com.
Rnet là gì, và nó không phải là gì
rnet là một khách hàng HTTP bất đồng bộ cho Python được xây dựng trên ngăn xếp mạng của Rust, và đặc điểm nổi bật của nó là mô phỏng dấu vân tay TLS và HTTP. Khi một khách hàng mở một kết nối TLS, hình dạng chính xác của bắt tay của nó - thứ tự mã hóa, mở rộng, đường cong - tạo thành một dấu vân tay mà các máy chủ có thể định hình; một khách hàng Python tiêu chuẩn có dấu vân tay mà không trình duyệt nào tạo ra, và một số trang từ chối nó trước khi một byte HTML nào được phục vụ. rnet tái tạo bắt tay của một trình duyệt đã chọn, vì vậy kết nối được nhận dạng là Chrome hoặc Firefox, và điều này diễn ra qua HTTP/2 với một API bất đồng bộ.
Điều mà nó không phải là một trình hiển thị. Một dấu vân tay khớp giúp bạn vượt qua định hình cấp bắt tay; nó không liên quan đến JavaScript. Trang vẫn xây dựng nội dung của nó với các kịch bản, và rnet, giống như bất kỳ khách hàng HTTP nào, trả về mã nguồn mà máy chủ gửi - mà trên một trang xây dựng bằng kịch bản thì không có nội dung. Vì vậy, một trình thu thập rnet tách ra hai vấn đề thường bị nhầm lẫn: lớp dấu vân tay, nơi rnet có chỗ đứng của nó, và lớp hiển thị, cần một trình duyệt. Hướng dẫn này sử dụng API thu thập thông tin toàn cầu Scrapeless cho việc hiển thị, với rnet thực hiện cuộc gọi. Để có cái nhìn toàn diện hơn, hướng dẫn thu thập thông tin web Python là bạn đồng hành.
Cài đặt
rnet là toàn bộ chuỗi công cụ cho hướng dẫn này. Phiên bản mà nó được viết dựa trên là rnet 2.4.2:
bash
pip install "rnet==2.4.2"
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"
Giả mạo một trình duyệt và xem nơi nó dừng
Hướng rnet đến một điểm cuối định hình với một cài đặt giả mạo trình duyệt, và bắt tay được đọc như trình duyệt đó. JA3 và JA4 là những tóm tắt tiêu chuẩn của bắt tay TLS - dấu vân tay được thương lượng theo tiêu chuẩn TLS 1.3 - và rnet tạo ra giá trị hình dạng trình duyệt. Tuy nhiên, cùng một khách hàng trên một trang xây dựng bằng kịch bản không tìm thấy gì, vì dấu vân tay không liên quan đến việc hiển thị phía khách hàng làm đầy trang:
python
# fingerprint.py — một bắt tay trình duyệt thực sự, và giới hạn của nó
import asyncio
import json
import re
import rnet
FINGERPRINT_URL = "https://tls.peet.ws/api/all"
PAGE_URL = "https://quotes.toscrape.com/js/"
async def main() -> None:
client = rnet.Client(impersonate=rnet.Impersonate.Chrome131)
resp = await client.get(FINGERPRINT_URL)
fp = json.loads(await resp.text())
ja3 = fp.get("tls", {}).get("ja3_hash", "")
ja4 = fp.get("tls", {}).get("ja4", "")
print("ja3 là 32-hex:", bool(re.fullmatch(r"[0-9a-f]{32}", ja3)))
print("tiền tố ja4:", ja4.split("_")[0])
print("phiên bản http:", fp.get("http_version"))
page_resp = await client.get(PAGE_URL)
page = await page_resp.text()
print("khối trích dẫn trang js:", page.count('class="quote"'))
asyncio.run(main())
Bắt tay có hình dạng trình duyệt; trang vẫn còn trống:
text
ja3 là 32-hex: True
tiền tố ja4: t13d1516h2
phiên bản http: h2
khối trích dẫn trang js: 0
Băm JA3 thay đổi từ lần chạy này sang lần chạy khác theo thiết kế - trình duyệt ngẫu nhiên hóa một mở rộng theo cơ chế GREASE, và rnet tái tạo điều đó - vì vậy một trình thu thập kiểm tra hình dạng, không phải giá trị cố định. Tiền tố JA4 t13d1516h2 là phần ổn định: TLS 1.3, 16 bộ mã hóa, 16 mở rộng, HTTP/2. Điều mà không cái nào trong số đó làm là hiển thị trang.
Hiển thị với Scrapeless, gọi bởi rnet
Giữ nguyên cùng một khách hàng không đồng bộ và thay đổi mục tiêu: POST URL đến Scrapeless Universal Scraping API, nơi render phía máy chủ và trả về HTML đã hoàn thành. rnet xử lý yêu cầu này như bất kỳ yêu cầu nào khác, vì vậy một khách hàng bao phủ cả việc lấy dữ liệu nhạy cảm với dấu vân tay và việc render:
python
# rendered.py — rnet gọi API render, sau đó trích xuất
import asyncio
import json
import os
import re
import rnet
async def main() -> None:
client = rnet.Client(impersonate=rnet.Impersonate.Chrome131)
resp = await client.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"], "Content-Type": "application/json"},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
)
html = json.loads(await resp.text())["data"]
authors = re.findall(r'<small class="author">(.*?)</small>', html)
print("các khối trích dẫn đã render:", html.count('class="quote"'))
print("tác giả đầu tiên:", authors[0])
asyncio.run(main())
Bây giờ nội dung đã có mặt:
text
các khối trích dẫn đã render: 10
tác giả đầu tiên: Albert Einstein
Đó là toàn bộ scraper, và nó đã ở trong rnet suốt hành trình: khách hàng không đồng bộ mang theo một dấu vân tay của trình duyệt cũng thực hiện cuộc gọi render. Universal Scraping API thực hiện việc render; rnet thực hiện HTTP.
Nhận mã API của bạn trên kế hoạch miễn phí: app.scrapeless.com
Mô hình nâng cao
- Khớp sự mạo danh với một trình duyệt hiện tại.
rnet.Impersonatetiết lộ các phiên bản trình duyệt cụ thể; chọn một phiên bản gần đây, vì một dấu vân tay cho một bản build đã nhiều năm tuổi cũng là một tín hiệu. API của khách hàng không thay đổi với mục tiêu. - Sử dụng lại một khách hàng. Một
rnet.Clientkết nối nhóm; tạo nó một lần và chia sẻ nó giữa một nhóm tác vụ không đồng bộ thay vì theo từng yêu cầu, điều này là nơi mà việc vận chuyển không đồng bộ phát huy hiệu quả. - Kiểm tra hình dạng, không phải giá trị. Bởi vì GREASE ngẫu nhiên hóa JA3 theo kết nối, xác nhận mẫu 32-hexa và tiền tố JA4, như kịch bản đầu tiên thực hiện — không bao giờ là một hash mã hóa cứng.
- Thêm một trình phân tích khi hình dạng phát triển. Regex giữ điều này chỉ với một phụ thuộc; đối với các bản ghi lồng, đưa HTML đã render vào một thư viện chọn và chọn các trường ở đó.
Khắc phục sự cố
- Một trang vẫn chặn yêu cầu. Một dấu vân tay TLS là một tín hiệu trong số nhiều tín hiệu khác. Nếu một bắt tay hình dạng trình duyệt không đủ, thì sự chặn này nằm trên tầng vận chuyển — uy tín IP, tiêu đề hoặc một thử thách — và yêu cầu thuộc về đường dẫn Scrapeless, cái mà xử lý điều đó.
- Không có chặn nào từ một trang mà bạn có thể xem trong trình duyệt. Nội dung được render bằng JavaScript; dấu vân tay đã khiến yêu cầu được chấp nhận nhưng các script không bao giờ chạy. Chuyển URL đó qua cuộc gọi Scrapeless với
js_render. - Hash JA3 thay đổi mỗi lần chạy. Đó là đúng — GREASE ngẫu nhiên hóa nó, chính xác như một trình duyệt thực sự làm. Xác nhận mẫu và tiền tố JA4 thay vào đó.
- Lỗi
awaittrên phản hồi. rnet là không đồng bộ: cả yêu cầu và việc đọc.text()đều được await, và mọi thứ đều chạy bên trongasyncio.run, như các ví dụ cho thấy.
Kết luận
rnet xứng đáng với vị trí của nó như lớp làm cho việc bắt tay trông đúng: một khách hàng không đồng bộ, được hỗ trợ bởi Rust, mang theo dấu vân tay TLS của một trình duyệt thực, và cũng thực hiện cuộc gọi render. Vấn đề mà nó không giải quyết được là chính trang — kết quả không có chặn của script dấu vân tay đã giải quyết điều đó — và một POST Scrapeless, được gửi bởi rnet, lấp đầy khoảng trống. Kết nối lớp dấu vân tay và lớp render thành một khách hàng duy nhất và mười tác giả của trang demo quay trở lại từ một kết nối mà máy chủ đọc như Chrome.
Tạo một tài khoản Scrapeless miễn phí để lấy mã API, và tài liệu cho nhà phát triển đề cập đến các tham số của unlocker.webunlocker. Kiểm tra bảng giá Scrapeless khi bạn lên kế hoạch cho một công việc định kỳ.
Câu hỏi thường gặp
Q: rnet có thể thu thập dữ liệu từ các trang được render bằng JavaScript tự nó không?
Không. rnet là một khách hàng HTTP với sự mạo danh dấu vân tay; nó chỉ để yêu cầu được chấp nhận ở lớp TLS nhưng không chạy JavaScript. Trên một trang được xây dựng bằng script, việc lấy dữ liệu sẽ trả về markup với nội dung bị thiếu — kết quả không có chặn của hướng dẫn này. Chuyển những trang đó qua Scrapeless Universal Scraping API, cái mà render chúng, với rnet thực hiện cuộc gọi.
Q: Sự mạo danh dấu vân tay TLS thực sự làm gì?
Nó định hình quá trình bắt tay TLS của rnet để phù hợp với một trình duyệt đã chọn, vì vậy một máy chủ phân tích dấu vân tay JA3 hoặc JA4 sẽ thấy Chrome hoặc Firefox thay vì một client Python chung. Điều này xóa bỏ việc lọc ở cấp độ bắt tay; nó không xóa bỏ các chặn dựa trên IP, các trang thách thức, hoặc sự cần thiết phải xử lý JavaScript.
Q: rnet khác gì so với curl_cffi?
Cả hai đều giả mạo dấu vân tay trình duyệt. rnet được xây dựng trên Rust và là ưu tiên async; curl_cffi bọc curl-impersonate và là đồng bộ. Chọn dựa trên việc trình thu thập dữ liệu của bạn là async và các mục tiêu giả mạo mà bạn cần — mẫu hai lớp với một API xử lý là giống nhau theo cả hai cách.
Q: Tại sao băm JA3 lại thay đổi trong mỗi lần chạy?
Bởi vì các trình duyệt thực tế ngẫu nhiên hóa một phần mở rộng TLS thông qua cơ chế GREASE, và rnet tái tạo hành vi đó. Một JA3 cố định sẽ trông như nhân tạo. Xác minh mẫu 32-hex và tiền tố JA4 thay vì một giá trị cụ thể.
Q: Việc thu thập dữ liệu bằng rnet có hợp pháp không?
Client HTTP không thay đổi các quy tắc thu thập. Chỉ lấy các trang công khai, tôn trọng các điều khoản của trang và các chỉ thị robot được chuẩn hóa bởi Giao thức loại trừ Robot, 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.



