Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ members = [

[patch.crates-io]
h2 = { git = "https://github.com/apify/h2", rev = "7f393a728a8db07cabb1b78d2094772b33943b9a" }
rustls = { git = "https://github.com/apify/rustls", rev = "c5338dd72cdccbfdb717aeb218fd05c60e3dd139" }
rustls = { git = "https://github.com/apify/rustls", rev="8c46c4744be711e87946d967301c8dac648f4049" }

[profile.release]
strip = true # Automatically strip symbols from the binary.
Expand Down
39 changes: 20 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@ impit is a `rust` library that allows you to impersonate a browser and make requ
The library provides a simple API for making requests to websites, and it also allows you to customize the request headers, use proxies, custom timeouts and more.

```rust
use impit::impit::Impit;
use impit::emulation::Browser;
use reqwest::cookie::Jar;
use impit::cookie::Jar;
use impit::{impit::Impit, fingerprint::database as fingerprints};

#[tokio::main]
async fn main() {
let impit = Impit::<Jar>::builder()
.with_browser(Browser::Firefox)
.with_http3()
.build()
.unwrap();

let response = impit.get(String::from("https://example.com"), None, None).await;

match response {
Ok(response) => {
println!("{}", response.text().await.unwrap());
}
Err(e) => {
println!("{:#?}", e);
}
}
let impit = Impit::<Jar>::builder()
.with_fingerprint(fingerprints::firefox_128::fingerprint())
.with_http3()
.build()
.unwrap();

let response = impit
.get(String::from("https://example.com"), None, None)
.await;

match response {
Ok(response) => {
println!("{}", response.text().await.unwrap());
}
Err(e) => {
println!("{:#?}", e);
}
}
}
```

Expand Down
9 changes: 6 additions & 3 deletions impit-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::ffi::OsString;

use clap::{Parser, ValueEnum};
use impit::{
emulation::Browser as ImpitBrowser,
impit::{Impit, RedirectBehavior},
request::RequestOptions,
};
Expand Down Expand Up @@ -94,8 +93,12 @@ async fn main() {
.with_fallback_to_vanilla(args.fallback);

client = match args.impersonate {
Browser::Chrome => client.with_browser(ImpitBrowser::Chrome),
Browser::Firefox => client.with_browser(ImpitBrowser::Firefox),
Browser::Chrome => {
client.with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint())
}
Browser::Firefox => {
client.with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint())
}
Browser::Impit => client,
};

Expand Down
22 changes: 11 additions & 11 deletions impit-node/src/impit_builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::Duration;

use impit::{
emulation::Browser as ImpitBrowser,
fingerprint::BrowserFingerprint,
impit::{ImpitBuilder, RedirectBehavior},
};
use napi::{bindgen_prelude::Object, Env};
Expand All @@ -18,15 +18,6 @@ pub enum Browser {
Firefox,
}

impl From<Browser> for ImpitBrowser {
fn from(val: Browser) -> Self {
match val {
Browser::Chrome => ImpitBrowser::Chrome,
Browser::Firefox => ImpitBrowser::Firefox,
}
}
}

/// Options for configuring an {@link Impit} instance.
///
/// These options allow you to customize the behavior of the Impit instance, including browser emulation, TLS settings, proxy configuration, timeouts, and more.
Expand Down Expand Up @@ -96,11 +87,20 @@ pub struct ImpitOptions<'a> {
pub local_address: Option<String>,
}

impl From<Browser> for BrowserFingerprint {
fn from(val: Browser) -> Self {
match val {
Browser::Chrome => impit::fingerprint::database::chrome_125::fingerprint(),
Browser::Firefox => impit::fingerprint::database::firefox_128::fingerprint(),
}
}
}

impl ImpitOptions<'_> {
pub fn into_builder(self, env: &Env) -> Result<ImpitBuilder<NodeCookieJar>, napi::Error> {
let mut config = ImpitBuilder::default();
if let Some(browser) = self.browser {
config = config.with_browser(browser.into());
config = config.with_fingerprint(browser.into());
}
if let Some(ignore_tls_errors) = self.ignore_tls_errors {
config = config.with_ignore_tls_errors(ignore_tls_errors);
Expand Down
16 changes: 14 additions & 2 deletions impit-node/test/fingerprints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ describe.each([
[Browser.Chrome, "t13d1516h2_8daaf6152771_02713d6af862"],
[Browser.Firefox, "t13d1715h2_5b57614c22b0_5c2c66f702b0"],
])(`Browser emulation [%s]`, (browser, ja4) => {
const impit = new Impit({ browser });

test('emulates JA4 fingerprint', async () => {
test(`[${browser}] emulates JA4 fingerprint`, async () => {
const impit = new Impit({ browser });
const response = await impit.fetch("https://headers.superuser.one/");
const text = await response.text();

const ja4Line = text.split('\n').find(line => line.startsWith('cf-ja4 => '));
expect(ja4Line).toBeDefined();
if (ja4Line) {
expect(ja4Line.split('=> ')[1]).toBe(ja4);
}
});

test(`[${browser}] without TLS verifier emulates JA4 fingerprint`, async () => {
const impit = new Impit({ browser, ignoreTlsErrors: false });
const response = await impit.fetch("https://headers.superuser.one/");
const text = await response.text();

Expand Down
7 changes: 4 additions & 3 deletions impit-python/src/async_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{collections::HashMap, sync::Arc, time::Duration};

use impit::{
emulation::Browser,
errors::ImpitError,
impit::{Impit, ImpitBuilder},
request::RequestOptions,
Expand Down Expand Up @@ -59,8 +58,10 @@ impl AsyncClient {

let builder = match browser {
Some(browser) => match browser.to_lowercase().as_str() {
"chrome" => builder.with_browser(Browser::Chrome),
"firefox" => builder.with_browser(Browser::Firefox),
"chrome" => builder
.with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()),
"firefox" => builder
.with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint()),
_ => {
return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
"Unsupported browser",
Expand Down
7 changes: 4 additions & 3 deletions impit-python/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{collections::HashMap, time::Duration};

use impit::{
emulation::Browser,
errors::ImpitError,
impit::{Impit, ImpitBuilder},
request::RequestOptions,
Expand Down Expand Up @@ -56,8 +55,10 @@ impl Client {

let builder = match browser {
Some(browser) => match browser.to_lowercase().as_str() {
"chrome" => builder.with_browser(Browser::Chrome),
"firefox" => builder.with_browser(Browser::Firefox),
"chrome" => builder
.with_fingerprint(impit::fingerprint::database::chrome_125::fingerprint()),
"firefox" => builder
.with_fingerprint(impit::fingerprint::database::firefox_128::fingerprint()),
_ => panic!("Unsupported browser"),
},
None => builder,
Expand Down
1 change: 0 additions & 1 deletion impit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ hickory-client = "0.25.1"
hickory-proto = "0.25.1"
log = "0.4.22"
mime = "0.3.17"
num-bigint = "0.4.6"
reqwest = { version="0.13.1", features = ["json", "gzip", "brotli", "zstd", "deflate", "http3", "cookies", "stream", "socks"] }
rustls = { version="0.23.36", features=["impit"] }
scraper = "0.25.0"
Expand Down
5 changes: 2 additions & 3 deletions impit/examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use impit::cookie::Jar;
use impit::emulation::Browser;
use impit::impit::Impit;
use impit::{fingerprint::database as fingerprints, impit::Impit};

#[tokio::main]
async fn main() {
let impit = Impit::<Jar>::builder()
.with_browser(Browser::Firefox)
.with_fingerprint(fingerprints::firefox_128::fingerprint())
.with_http3()
.build()
.unwrap();
Expand Down
9 changes: 9 additions & 0 deletions impit/src/fingerprint/database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Pre-defined browser fingerprints
//!
//! This module contains fingerprint definitions for various browsers.

mod chrome;
mod firefox;

pub use chrome::chrome_125;
pub use firefox::firefox_128;
Loading