Crates.io | rquest |
lib.rs | rquest |
version | |
source | src |
created_at | 2024-07-27 01:09:24.255915 |
updated_at | 2024-12-12 10:09:45.273853 |
description | An ergonomic, all-in-one JA3/JA4/HTTP2 fingerprint HTTP/WebSocket client |
homepage | |
repository | https://github.com/penumbra-x/rquest |
max_upload_size | |
id | 1316932 |
Cargo.toml error: | TOML parse error at line 19, column 1 | 19 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
🚀 Help me work seamlessly with open source sharing by sponsoring me on GitHub
An ergonomic, all-in-one JA3
/JA4
/HTTP2
fingerprint HTTP
/WebSocket
client.
HTTPS
/WebSocket
via BoringSSLTLS
/HTTP2
settingsHTTP
, HTTPS
, SOCKS4
and SOCKS5
proxiesAdditional learning resources include:
⚠ This crate is under active development and the API is not yet stable.
This asynchronous example uses Tokio and enables some
optional features, so your Cargo.toml
could look like this:
HTTP
[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = "0.31.0"
use rquest::tls::Impersonate;
#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
// Build a client to mimic Chrome131
let client = rquest::Client::builder()
.impersonate(Impersonate::Chrome131)
.build()?;
// Use the API you're already familiar with
let resp = client.get("https://tls.peet.ws/api/all").send().await?;
println!("{}", resp.text().await?);
Ok(())
}
WebSocket
[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = { version = "0.31.0", features = ["websocket"] }
use futures_util::{SinkExt, StreamExt, TryStreamExt};
use rquest::{tls::Impersonate, Client, Message};
#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
// Build a client to mimic Chrome131
let client = Client::builder()
.impersonate(Impersonate::Chrome131)
.build()?;
// Use the API you're already familiar with
let websocket = client
.websocket("wss://echo.websocket.org")
.send()
.await?
.into_websocket()
.await?;
let (mut tx, mut rx) = websocket.split();
tokio::spawn(async move {
for i in 1..11 {
tx.send(Message::Text(format!("Hello, World! #{i}")))
.await
.unwrap();
}
});
while let Some(message) = rx.try_next().await? {
match message {
Message::Text(text) => println!("received: {text}"),
_ => {}
}
}
Ok(())
}
Preconfigured TLS
/HTTP2
[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = "0.31.0"
use http::{header, HeaderMap, HeaderName, HeaderValue};
use rquest::{
tls::{Http2Settings, ImpersonateSettings, TlsSettings, TlsVersion},
HttpVersionPref,
};
use rquest::{PseudoOrder::*, SettingsOrder::*};
use std::borrow::Cow;
static HEADER_ORDER: &[HeaderName] = &[
header::USER_AGENT,
header::ACCEPT_LANGUAGE,
header::ACCEPT_ENCODING,
header::COOKIE,
header::HOST,
];
#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
// TLS settings
let tls_settings = TlsSettings::builder()
.tls_sni(true)
.alpn_protos(HttpVersionPref::All)
.application_settings(true)
.pre_shared_key(true)
.enable_ech_grease(true)
.permute_extensions(true)
.min_tls_version(TlsVersion::TLS_1_0)
.max_tls_version(TlsVersion::TLS_1_3)
.build();
// HTTP/2 settings
let http2_settings = Http2Settings::builder()
.initial_stream_window_size(6291456)
.initial_connection_window_size(15728640)
.max_concurrent_streams(1000)
.max_header_list_size(262144)
.header_table_size(65536)
.enable_push(false)
.headers_priority((0, 255, true))
.headers_pseudo_order([Method, Scheme, Authority, Path])
.settings_order([
HeaderTableSize,
EnablePush,
MaxConcurrentStreams,
InitialWindowSize,
MaxFrameSize,
MaxHeaderListSize,
UnknownSetting8,
UnknownSetting9,
])
.build();
// Headers
let headers = {
{
let mut headers = HeaderMap::new();
headers.insert(header::USER_AGENT, HeaderValue::from_static("rquest"));
headers.insert(
header::ACCEPT_LANGUAGE,
HeaderValue::from_static("en-US,en;q=0.9"),
);
headers.insert(
header::ACCEPT_ENCODING,
HeaderValue::from_static("gzip, deflate, br"),
);
headers.insert(header::HOST, HeaderValue::from_static("tls.peet.ws"));
headers.insert(header::COOKIE, HeaderValue::from_static("foo=bar"));
Cow::Owned(headers)
}
};
// Create impersonate settings
let settings = ImpersonateSettings::builder()
.tls(tls_settings)
.http2(http2_settings)
.headers(headers)
.headers_order(Cow::Borrowed(HEADER_ORDER))
.build();
// Build a client with impersonate settings
let client = rquest::Client::builder()
.impersonate_settings(settings)
.build()?;
// Use the API you're already familiar with
let resp = client.get("https://tls.peet.ws/api/all").send().await?;
println!("{}", resp.text().await?);
Ok(())
}
Modify Client
settings
[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = { version = "0.31.0", features = ["full"] }
use http::{header, HeaderName, HeaderValue};
use rquest::{tls::Impersonate, Client};
use std::net::Ipv4Addr;
static HEADER_ORDER: [HeaderName; 6] = [
header::ACCEPT_LANGUAGE,
header::USER_AGENT,
header::ACCEPT_ENCODING,
header::HOST,
header::COOKIE
];
#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
// Build a client to mimic Chrome131
let mut client = Client::builder()
.impersonate(Impersonate::Chrome131)
.build()?;
// Set the headers order
{
client.set_headers_order(&HEADER_ORDER);
let resp = client.get("https://tls.peet.ws/api/all").send().await?;
println!("{}", resp.text().await?);
}
// Change the impersonate to Safari18
{
client.set_impersonate(Impersonate::Safari18)?;
let resp = client.get("https://tls.peet.ws/api/all").send().await?;
println!("{}", resp.text().await?);
}
// Change the impersonate to Edge127 without setting the headers
{
client.set_impersonate_skip_headers(Impersonate::Edge127)?;
// Set a header
client
.headers_mut()
.insert(header::ACCEPT, HeaderValue::from_static("application/json"));
// Set a cookie
client.set_cookies(
vec![HeaderValue::from_static("foo=bar; Domain=tls.peet.ws")],
"https://tls.peet.ws/api/all",
)?;
let resp = client.get("https://tls.peet.ws/api/all").send().await?;
println!("{}", resp.text().await?);
}
// Set the local address
{
client.set_local_address(Some(Ipv4Addr::new(172, 20, 10, 2).into()));
let resp = client.get("https://api.ip.sb/ip").send().await?;
println!("{}", resp.text().await?);
}
// Set the interface
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
{
client.set_interface("eth0");
let resp = client.get("https://api.ip.sb/ip").send().await?;
println!("{}", resp.text().await?);
}
// ⚠️ Note: Methods like `set_impersonate` and `set_impersonate_without_headers` will reset all client settings,
// including proxies, header information, and more. Use them carefully.
// When using methods such as `set_headers_order`, `headers_mut`, `set_impersonate`, `set_impersonate_without_headers`,
// `set_interface`, `set_local_address`, `set_local_addresses`, or `set_proxies`,
// changes will only affect the current `Client` instance.
// If you need to preserve the original settings, you can clone the `Client`.
// Cloning a `Client` is cheap, and while modifications won't affect the original `Client` instance,
// they will share the same connection pool.
let mut client2 = client.clone();
// Set the impersonate to Chrome131
// Expected: Chrome131
{
client2.set_impersonate(Impersonate::Chrome131)?;
let resp = client2.get("https://api.ip.sb/ip").send().await?;
println!("{}", resp.text().await?);
}
// But not change the original client
// Expected: Edge127
let resp = client.get("https://api.ip.sb/ip").send().await?;
println!("{}", resp.text().await?);
Ok(())
}
You can customize the TLS
/HTTP2
fingerprint parameters of the device. In addition, the basic device impersonation types are provided as follows:
Chrome100
,Chrome101
,Chrome104
,Chrome105
,Chrome106
,Chrome107
,Chrome108
,Chrome109
,Chrome114
,Chrome116
,Chrome117
,Chrome118
,Chrome119
,Chrome120
,Chrome123
,Chrome124
,Chrome126
,Chrome127
,Chrome128
,Chrome129
,Chrome130
,Chrome131
Edge101
,Edge122
,Edge127
SafariIos17_2
,SafariIos17_4_1
,SafariIos16_5
,Safari15_3
,Safari15_5
,Safari15_6_1
,Safari16
,Safari16_5
,Safari17_0
,Safari17_2_1
,Safari17_4_1
,Safari17_5
,Safari18
,SafariIPad18
, Safari18_2
OkHttp3_9
,OkHttp3_11
,OkHttp3_13
,OkHttp3_14
,OkHttp4_9
,OkHttp4_10
,OkHttp5
Install the environment required to build BoringSSL
Do not compile with crates that depend on OpenSSL
; their prefixing symbols are the same and may cause linking failures.
If both OpenSSL
and BoringSSL
are used as dependencies simultaneously, even if the compilation succeeds, strange issues may still arise.
sudo apt-get install build-essential cmake perl pkg-config libclang-dev musl-tools -y
cargo build --release
You can also use this GitHub Actions workflow to compile your project on Linux, Windows, and macOS.
The predecessor of rquest is reqwest. rquest is a specialized adaptation based on the reqwest project, supporting BoringSSL and related HTTP/2 fingerprints in requests.
It also optimizes commonly used APIs and enhances compatibility with connection pools, making it easier to switch proxies, IP addresses, and interfaces. You can directly migrate from a project using reqwest to rquest.
Due to limited time for maintaining the synchronous APIs, only asynchronous APIs are supported. I may have to give up maintenance; if possible, please consider sponsoring me.
If you would like to submit your contribution, please open a Pull Request.
Your question might already be answered on the issues
Apache-2.0 LICENSE
The project is based on a fork of reqwest.