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
| Cecha | Rezydencjalne | Datacenter | Mobilne |
|---|---|---|---|
| Pochodzenie IP | ISP domowy | Blok hostingowy | Sieć komórkowa |
| Prawdopodobieństwo blokady | Niskie | Wysokie | Bardzo niskie |
| Prędkość | ~200–500 ms | ~50–100 ms | ~300–800 ms |
| Koszt | Średni | Niski | Wysoki |
| Idealne do | Scraping, SERP | Wewnętrzne API | Social 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łówekhttr2/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ów —
resp_body_string()automatycznie dekoduje UTF-8, ale starsze strony mogą używać ISO-8859-2. Użyjresp_body_raw()+rawToChar()ziconv()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_idco partię. - Brak
tryCatch— jedno żądanie 403 przerywa całymap. Zawsze owijajreq_perform()wtryCatch. - Mieszanie HTTP i SOCKS5 — port
8080to HTTP, port1080to 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 pakieturobotstxtw 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.






