Używanie proxy w R: Przewodnik po httr2, rvest i ProxyHat

Kompletny przewodnik po konfiguracji proxy w R z httr2 i rvest — od req_proxy, przez geo-targeting i sesje sticky, po pobieranie tabel i renderowanie JS. Kod, błędy i dobre praktyki.

Using Proxies in R: A Code-First Guide with httr2 and rvest
W tym artykule

Dlaczego używanie proxy w R ma znaczenie

Kiedy pobierasz dane z zewnętrznych źródeł w R — czy to ceny z e-commerce, wyniki SERP, czy tabele z portali publicznych — twój adres IP jest jedyną tożsamością, jaką widzi serwer docelowy. Po kilkudziesięciu żądaniach z tego samego IP pojawiają się kody 403, 429 lub strony CAPTCHA. Używanie proxy w R rozwiązuje ten problem, kierując ruch przez pośrednie adresy, które wyglądają jak zwykli użytkownicy.

Pakiet httr2 zastąpił starszy httr, oferując nowoczesny interfejs oparty na request() i potokach. W połączeniu z rvest do parsowania HTML daje to czysty, idiomatyczny sposób na web scraping w R z pełną kontrolą nad proxy, nagłówkami i strategią ponawiania.

W tym przewodniku pokazuję krok po kroku, jak skonfigurować R proxy z ProxyHat, jak korzystać z httr2 req_proxy, jak parsować wyniki rvest i jak zbudować odporny pipeline pobierania danych.

Kontekst techniczny: dlaczego blokady występują

Większość nowoczesnych stron stosuje warstwy ochrony przed botami — od prostego limitu żądań po IP, po zaawansowane systemy jak Cloudflare czy Akamai. Te systemy analizują sygnatury: adres IP, nagłówki User-Agent, wzorce czasowe i odcisk TLS. Według dokumentacji Cloudflare Bot Management, każdy ruch otrzymuje wynik bota od 1 do 99, a progi są konfigurowane przez operatora witryny.

Adresy z centrów danych (datacenter) mają bardzo wysokie prawdopodobieństwo bycia oflagowanym, ponieważ należą do bloków ASN przypisanych do hosting providerów. Z kolei adresy rezydencjalne pochodzą od dostawców ISP i wyglądają jak ruch realnych użytkowników domowych. To kluczowa różnica, gdy twój skrypt w R musi pobrać tysiące stron bez blokad.

Rezydencjalne vs datacenter vs mobilne

CechaRezydencjalneDatacenterMobilne
Pochodzenie IPISP domowyBlok hostingowySieć komórkowa
Prawdopodobieństwo blokadyNiskieWysokieBardzo niskie
Prędkość~200–500 ms~50–100 ms~300–800 ms
KosztŚredniNiskiWysoki
Idealne doScraping, SERPWewnętrzne APISocial media

Szczegóły lokalizacji ProxyHat znajdziesz na stronie lokalizacji proxy, a porównanie planów na stronie cennika.

Nowoczesny stack: httr2 + rvest proxy

Zacznijmy od podstawowego żądania przez ProxyHat. Format połączenia to http://USERNAME:PASSWORD@gate.proxyhat.com:8080. W httr2 używamy req_proxy(), które przyjmuje URL, nazwę użytkownika i hasło osobno.

# install.packages(c("httr2", "rvest", "purrr", "dplyr", "tibble"))
library(httr2)
library(rvest)

# Podstawowe żądanie przez ProxyHat HTTP proxy
req <- request("https://httpbin.org/ip") |>
  req_proxy("http://gate.proxyhat.com", 8080,
           username = "user-country-DE",
           password = "twoje_haslo") |>
  req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")

resp <- req |> req_perform()
body <- resp |> resp_body_string()
cat(body)
# { "origin": "91.x.x.x" }  — IP rezydencjalne z Niemiec

Po pobraniu HTML przekazujemy go do rvest. Funkcja read_html() akceptuje zarówno ścieżkę URL, jak i ciąg znaków lub obiekt odpowiedzi.

library(httr2)
library(rvest)
library(dplyr)

# Pobierz stronę i wyciągnij nagłówki artykułów
req <- request("https://example.com/news") |>
  req_proxy("http://gate.proxyhat.com", 8080,
           username = "user-country-US",
           password = "twoje_haslo") |>
  req_user_agent("Mozilla/5.0 (compatible; ResearchBot/1.0)") |>
  req_retry(max_tries = 3, max_seconds = 30) |>
  req_throttle(2)  # max 2 żądania na sekundę

resp <- req |> req_perform()
html <- resp |> resp_body_string() |> read_html()

titles <- html |>
  html_elements("h2.article-title") |>
  html_text2()

tibble(title = titles)

Geo-targeting i sesje sticky w nazwie użytkownika

ProxyHat koduje parametry geo i sesji bezpośrednio w nazwie użytkownika. To oznacza, że nie potrzebujesz dodatkowych nagłówków ani parametrów URL — cała konfiguracja mieści się w username.

# Geo-targeting: Wielka Brytania, Londyn
req_uk <- request("https://httpbin.org/ip") |>
  req_proxy("http://gate.proxyhat.com", 8080,
           username = "user-country-GB-city-london",
           password = "twoje_haslo")

# Sticky session — ten sam IP dla wielu żądań
req_sticky <- request("https://httpbin.org/ip") |>
  req_proxy("http://gate.proxyhat.com", 8080,
           username = "user-session-abc123",
           password = "twoje_haslo")

# SOCKS5 na porcie 1080
req_socks <- request("https://httpbin.org/ip") |>
  req_proxy("socks5://gate.proxyhat.com", 1080,
           username = "user-country-FR",
           password = "twoje_haslo")

# Wykonaj wszystkie trzy
purrr::walk(list(req_uk, req_sticky, req_socks), function(r) {
  resp <- r |> req_perform()
  cat(resp |> resp_body_string(), "\n")
})

Kluczowa zasada: używaj sesji sticky (user-session-XYZ) gdy musisz utrzymać stan logowania lub koszyka. Używaj rotacji per-żądanie (brak flagi session) gdy pobierasz niezależne strony i chcesz maksymalną diversyfikację IP.

Praktyczny przykład: paginowana tabela do data frame

Typowy scenariusz rvest proxy: strona z tabelą wielostronicową. Pobieramy każdą stronę z inną sesją proxy, parsujemy tabelę i łączymy wyniki w jeden tidy data frame.

library(httr2)
library(rvest)
library(purrr)
library(dplyr)
library(tibble)

build_req <- function(page, session_id) {
  request("https://example.com/products") |>
    req_url_query(page = page) |>
    req_proxy("http://gate.proxyhat.com", 8080,
             username = paste0("user-country-US-session-", session_id),
             password = "twoje_haslo") |>
    req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |>
    req_headers("Accept-Language" = "en-US,en;q=0.9") |>
    req_retry(max_tries = 4, max_seconds = 60) |>
    req_throttle(1.5)  # 1.5 żądania/s — bezpieczny limit
}

fetch_table <- function(page) {
  session_id <- paste0("pg", page, "-", sample(1000:9999, 1))
  tryCatch({
    resp <- build_req(page, session_id) |> req_perform()
    html <- resp |> resp_body_string() |> read_html()
    tbl <- html |>
      html_elements("table.data-table") |>
      html_table(convert = TRUE)
    if (length(tbl) > 0) {
      tbl[[1]] |> mutate(page = page)
    } else {
      tibble()
    }
  }, error = function(e) {
    message("Błąd na stronie ", page, ": ", conditionMessage(e))
    tibble(page = page, error = conditionMessage(e))
  })
}

# Pobierz strony 1–10 z rotacją sesji
pages <- 1:10
results <- purrr::map(pages, fetch_table)
df <- purrr::list_rbind(results)

# Wynik: tidy data frame z wszystkimi wierszami
glimpse(df)

Ten wzorzec — purrr::map + req_retry + req_throttle + rotacja sesji — jest podstawą odpornego pipeline'u. req_retry automatycznie ponawia przy błędach 5xx i 429, a req_throttle ogranicza częstotliwość, chroniąc przed rate-limitami.

Strony renderowane przez JavaScript

Niektóre strony ładują dane dynamicznie przez JS. Pakiet rvest oferuje read_html_live(), który używa chromote — sterownika Chrome DevTools Protocol — do renderowania stron. Możesz skonfigurować proxy na poziomie przeglądarki.

library(rvest)
library(httr2)

# read_html_live() używa chromote — ustaw proxy przez zmienne środowiskowe
Sys.setenv(
  "CHROMOTE_HEADLESS" = "true"
)

# Chromote czyta proxy z Chrome flags
# Przekaż flagę --proxy-server przy uruchomieniu
page <- read_html_live(
  "https://example.com/js-app",
  timeout = 30000  # 30 sekund na render
)

# Wyciągnij dane po załadowaniu JS
cards <- page |>
  html_elements(".product-card") |>
  html_text2()

length(cards)

Dla read_html_live() proxy ustawia się przez flagę Chrome --proxy-server=http://gate.proxyhat.com:8080 w konfiguracji chromote. Pełną dokumentację znajdziesz w dokumentacji ProxyHat.

Realistyczne nagłówki

Blokady często reagują na brak lub nieprawidłowe nagłówki. Ustaw realistyczny User-Agent i Accept-Language:

req <- request("https://example.com") |>
  req_proxy("http://gate.proxyhat.com", 8080,
           username = "user-country-PL",
           password = "twoje_haslo") |>
  req_user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") |>
  req_headers(
    "Accept" = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language" = "pl-PL,pl;q=0.9,en;q=0.8",
    "Accept-Encoding" = "gzip, deflate, br",
    "Connection" = "keep-alive",
    "Upgrade-Insecure-Requests" = "1"
  )

Najczęstsze błędy i przypadki brzegowe

  • Zapominanie req_user_agent() — httr2 wysyła domyślny nagłówek httr2/1.0.0, który jest natychmiast oflagowany. Zawsze ustawiaj realistyczny UA.
  • Zbyt agresywne req_throttle() — wartość 0 (brak limitu) powoduje 429. Dla większości celów 1–3 żądania/s jest bezpieczne.
  • Kodowanie znakówresp_body_string() automatycznie dekoduje UTF-8, ale starsze strony mogą używać ISO-8859-2. Użyj resp_body_raw() + rawToChar() z iconv() gdy potrzebne.
  • Sesje sticky zbyt długie — jeśli sesja trwa dłużej niż 10–15 minut, IP może zostać wygaszone. Generuj nowy session_id co partię.
  • Brak tryCatch — jedno żądanie 403 przerywa cały map. Zawsze owijaj req_perform() w tryCatch.
  • Mieszanie HTTP i SOCKS5 — port 8080 to HTTP, port 1080 to SOCKS5. Nie zamieniaj ich miejscami.

Etyka i zgodność z przepisami

Pobieranie danych publicznych jest legalne, ale wymaga ostrożności. Zawsze sprawdzaj robots.txt i warunki korzystania (ToS) witryny. Zgodnie z Art. 6 RODO, przetwarzanie danych osobowych osób w UE wymaga podstawy prawnej — zgody, umowy lub prawnie uzasadnionego interesu. Jeśli pobierasz dane dotyczące osób (np. profile publiczne), skonsultuj się z DPO.

Kluczowe zasady:

  • Preferuj oficjalne API, gdy są dostępne — są stabilniejsze i legalne.
  • Ustawiaj rozsądne opóźnienia (req_throttle) — nie przeciążaj serwerów.
  • Nie pobieraj danych objętych płatną subskrypcją bez autoryzacji.
  • Identyfikuj swojego bota w UA, gdy to możliwe — transparentność buduje zaufanie.
  • Przestrzegaj robots.txt — użyj pakietu robotstxt w R.

Więcej o zastosowaniach proxy w scraping znajdziesz na stronie web scraping i śledzenie SERP.

ProxyHat SDK w pipeline'ach mieszanych

Jeśli twój zespół używa obok R również Pythona lub Node.js, ProxyHat oferuje ten sam wzorzec połączenia we wszystkich językach. Format gate.proxyhat.com:8080 z kodowaniem parametrów w nazwie użytkownika jest identyczny — możesz współdzielić konfigurację i logikę rotacji między usługą R (np. w plumber) i backendem Python.

Kluczowe wnioski

  • httr2 req_proxy() to najczystszy sposób na konfigurację proxy w R — URL, port, username i password osobno.
  • Geo-targeting i sesje koduje się w nazwie użytkownika: user-country-GB-city-london, user-session-abc123.
  • Rotacja sesji per-żądanie + req_retry() + req_throttle() to złota trójca odpornego scrapingu.
  • Rezydencjalne proxy drastycznie zmniejszają prawdopodobieństwo blokad vs datacenter.
  • Strony JS wymagają read_html_live() z chromote i proxy na poziomie Chrome.
  • Etyka — sprawdzaj robots.txt, przestrzegaj RODO, preferuj API.

Gotowy, aby zacząć? Skonfiguruj swoje proxy na ProxyHat i uruchom pierwszy skrypt w R w kilka minut.

Często zadawane pytania

Czym jest używanie proxy w R?

Używanie proxy w R to kierowanie żądań HTTP przez pośredni serwer proxy zamiast bezpośrednio z twojego IP. W nowoczesnym R używa się do tego pakietu httr2 i funkcji req_proxy(), która przyjmuje URL bramy, port, nazwę użytkownika i hasło. Proxy rezydencjalne sprawia, że ruch wygląda jak pochodzący od zwykłego użytkownika domowego, co zmniejsza ryzyko blokad.

Dlaczego używanie proxy w R ma znaczenie dla użytkowników proxy?

Bez proxy twój adres IP jest jedyną tożsamością widoczną dla serwera docelowego. Po kilkudziesięciu żądaniach pojawiają się błędy 403 i 429 lub strony CAPTCHA. Proxy rezydencjalne rozwiązuje ten problem, kierując ruch przez adresy ISP, które wyglądają jak realni użytkownicy. To kluczowe dla scraping, śledzenia SERP i monitorowania cen w skali.

Który typ proxy działa najlepiej w R?

Dla większości zadań scraping w R najlepiej sprawdzają się proxy rezydencjalne — mają niskie prawdopodobieństwo blokady i są tańsze niż mobilne. Proxy datacenter są szybsze (~50–100 ms vs ~200–500 ms), ale są łatwo oflagowane przez systemy anti-bot. Proxy mobilne są najbezpieczniejsze, ale najdroższe — używaj ich dla wrażliwych celów jak social media.

Jak unikać blokad przy używaniu proxy w R?

Ustaw realistyczny User-Agent przez req_user_agent(), używaj req_throttle() z limitem 1–3 żądań/s, włącz req_retry() z max_tries=3–4, rotuj sesje per-żądanie generując nowe session_id, i ustawiaj nagłówki Accept-Language zgodne z geo-targetingiem proxy. Dodatkowo sprawdzaj robots.txt i przestrzegaj warunków korzystania witryny.

Sprawdź konfigurację proxy w kilka sekund

Darmowy tester proxy — potwierdź, że Twoje IP są szybkie, anonimowe i nieblokowane.

Sprawdź proxy za darmo
← Powrót do Bloga