Jak skonfigurować proxy w LangChain

Proxy w LangChain: parametr proxies w WebBaseLoader, requests_kwargs dla limitu czasu, zmienne HTTP_PROXY i trust_env przy asynchronicznym pobieraniu stron.

Zaktualizowano · Redakcja Prokso

Dane do połączenia
Host
gw.prokso.com
Port
823 HTTP · 824 SOCKS5 — nowy IP przy każdym żądaniu · 10000–20000 stały IP na całą sesję, HTTP(S) i SOCKS5
Login i hasło
w panelu klienta, na stronie planu

Gotowe wiersze w potrzebnym formacie wygenerujesz w panelu klienta: wybierz kraj, typ IP i protokół.

W skrócie
  • Host gw.prokso.com, porty 823 (HTTP), 824 (SOCKS5), 10000–20000 (stały IP, HTTP lub SOCKS5)
  • Login i hasło znajdziesz w panelu klienta na stronie planu
  • Sprawdzaj IP w odpowiedzi na samo żądanie wysłane przez proxy: strona Mój IP w przeglądarce nie testuje Twojego skryptu

Instrukcja krok po kroku, jak podłączyć proxy Prokso w LangChain. Zajmie Ci to kilka minut.

Krok 1. Pobierz dane proxy z panelu klienta

Otwórz swój plan i skopiuj host gw.prokso.com, port, login i hasło. Port 823 to HTTP, a 824 to SOCKS5 (oba dają nowy IP przy każdym żądaniu); porty 10000–20000 utrzymują jeden IP (stały IP) do 120 minut i działają zarówno jako HTTP, jak i SOCKS5 (każdy port to osobny adres). Kraj ustawisz w loginie: username__cr.ua.

Krok 2. Zainstaluj pakiety

pip install -U langchain-community beautifulsoup4. Loader stron WebBaseLoader znajduje się w pakiecie langchain-community, a do parsowania HTML potrzebuje beautifulsoup4. Zwykłe pobieranie idzie przez bibliotekę requests, a asynchroniczne przez aiohttp – dla każdego z nich proxy ustawia się inaczej.

Krok 3. Przekaż proxy do loadera

Dla load() i lazy_load() przekaż parametr proxies: słownik z adresem URL proxy dla http i https. Login i hasło wpisz bezpośrednio w adres URL. Parametr requests_kwargs przekazuje dodatkowe ustawienia do każdego żądania, np. timeout, żeby skrypt nie zawiesił się na wolnej stronie.

from langchain_community.document_loaders import WebBaseLoader

PROXY = "http://USERNAME:PASSWORD@gw.prokso.com:823"

loader = WebBaseLoader(
    "https://api.ipify.org?format=json",
    proxies={"http": PROXY, "https": PROXY},
    requests_kwargs={"timeout": 30},
)
docs = loader.load()
print(docs[0].page_content)

Krok 4. Pobieranie asynchroniczne korzysta ze zmiennych środowiskowych

alazy_load() i fetch_all() (a także przestarzała aload()) działają na aiohttp i ignorują parametr proxies. Dla nich ustaw zmienne HTTP_PROXY i HTTPS_PROXY i utwórz loader z trust_env=True: bez tego aiohttp pomija zmienne. AsyncHtmlLoader konfiguruje się tak samo.

import asyncio
import os

os.environ["HTTP_PROXY"] = "http://USERNAME:PASSWORD@gw.prokso.com:823"
os.environ["HTTPS_PROXY"] = "http://USERNAME:PASSWORD@gw.prokso.com:823"

from langchain_community.document_loaders import WebBaseLoader


async def main():
    loader = WebBaseLoader(
        web_paths=["https://api.ipify.org?format=json"] * 3,
        trust_env=True,
        requests_per_second=2,
    )
    async for doc in loader.alazy_load():
        print(doc.page_content)


asyncio.run(main())

Krok 5. Zmienne środowiskowe dla innych loaderów

Biblioteka requests domyślnie odczytuje HTTP_PROXY i HTTPS_PROXY, więc zmienne ustawione przed uruchomieniem skryptu działają też w loaderach opartych na requests, które nie mają własnego parametru proxy. Pamiętaj, że według dokumentacji requests zmienne środowiskowe nadpisują proxy ustawione na poziomie sesji, a właśnie tak działa parametr proxies w WebBaseLoader. W jednym skrypcie wybierz jeden sposób.

Krok 6. Wybierz port i tempo

Port 823 daje nowy IP dla każdej strony, co sprawdza się przy pobieraniu wielu stron. Żeby wczytać serię stron z jednego IP, użyj portu ze stałym IP z zakresu 10000-20000. W trybie asynchronicznym parametr requests_per_second ogranicza liczbę stron pobieranych jednocześnie; domyślnie to 2.

Krok 7. Sprawdź wynik

Uruchom przykład: loader otwiera https://api.ipify.org i wypisuje zawartość strony, czyli IP, który widzi strona. Powinien to być adres proxy, a nie Twój; w przykładzie asynchronicznym na porcie 823 trzy linie pokazują różne adresy. Błąd 407 oznacza nieprawidłowy login lub hasło albo wyczerpany transfer w planie. Strona Mój IP w przeglądarce tu nie pomoże: przeglądarka łączy się bezpośrednio.

Osobny loader dla każdego kraju i sesja na źródło

Gdy baza wiedzy potrzebuje lokalnych wersji stron (ceny, dostępność, lokalne wiadomości), utwórz osobny WebBaseLoader dla każdego kraju. Kraj trafia do loginu, hasło pochodzi ze zmiennej środowiskowej, a oba przechodzą przez urllib.parse.quote(..., safe=""), żeby znak ; i znaki specjalne nie zepsuły adresu proxy. Przed wysłaniem requests sama je dekoduje.

import os
from urllib.parse import quote
from langchain_community.document_loaders import WebBaseLoader

USER = "USERNAME"
PASSWORD = os.environ["PROKSO_PASSWORD"]  # hasło nie trafia do kodu


def proxy_url(country, session=None, port=823):
    login = f"{USER}__cr.{country}"
    if session:
        login += f";sessid.{session}"  # jeden IP na około 30 minut
    return f"http://{quote(login, safe='')}:{quote(PASSWORD, safe='')}@gw.prokso.com:{port}"


SOURCES = {
    "de": ["https://example.de/catalog?page=1", "https://example.de/catalog?page=2"],
    "pl": ["https://example.pl/catalog?page=1", "https://example.pl/catalog?page=2"],
}

docs = []
for country, urls in SOURCES.items():
    proxy = proxy_url(country, session=f"src{country}")
    loader = WebBaseLoader(
        web_paths=urls,
        proxies={"http": proxy, "https": proxy},
        requests_kwargs={"timeout": 30},
        raise_for_status=True,
    )
    for doc in loader.lazy_load():  # po jednej stronie, bez całej listy w pamięci
        doc.metadata["country"] = country
        docs.append(doc)

print(len(docs))

Numer sesji w loginie (;sessid.srcde) trzyma jeden IP przez około 30 minut na porcie 823, więc wszystkie strony jednego źródła, na przykład paginacja katalogu, idą z tego samego adresu. Każdy kraj dostaje własną sesję. lazy_load() zwraca dokumenty po jednym: przy długiej liście możesz od razu zapisywać każdy do bazy wektorowej, a pole country w metadanych pomoże później filtrować odpowiedzi.

Błędy loaderów LangChain przez proxy i jak je naprawić

  • Strona 403 lub 429 trafia do bazy wiedzy. Domyślnie WebBaseLoader nie sprawdza kodu odpowiedzi, więc strona Access denied jest parsowana jak zwykły dokument. Ustaw raise_for_status=True: wtedy load() i lazy_load() zgłaszają requests.HTTPError i możesz pominąć stronę zamiast ją indeksować.
  • InvalidProxyURL: Please check proxy URL. It is malformed and could be missing the host. requests nie znalazła hosta w adresie proxy. Zwykle niezakodowany @ lub / w haśle przesunął granicę między częściami adresu. Buduj adres przez quote(), jak w przykładzie wyżej.
  • aiohttp.ClientHttpProxyError ze statusem 407 w alazy_load() lub fetch_all(). Proxy nie przyjęło loginu lub hasła z HTTPS_PROXY. Loader asynchroniczny nie ponawia tego błędu, tylko od razu się zatrzymuje. Zakodowane znaki działają i tutaj: aiohttp dekoduje je samo.
  • aiohttp.ClientProxyConnectionError. aiohttp w ogóle nie dotarło do gw.prokso.com: sprawdź port i to, czy połączenia wychodzące na niego są dozwolone na twoim serwerze. Loader robi 3 próby z rosnącą przerwą, a potem się poddaje.
  • Jedna nieudana strona zatrzymuje całe pobieranie asynchroniczne. Domyślnie błąd na jednym adresie przerywa pracę. Z continue_on_failure=True loader zapisuje ostrzeżenie i zwraca dla tej strony pusty dokument: odfiltruj puste dokumenty przed indeksowaniem.

Tempo i transfer w pipeline LangChain

W trybie asynchronicznym requests_per_second nie oznacza liczby na sekundę: w kodzie biblioteki to rozmiar semafora, czyli ile stron pobiera się jednocześnie. Na porcie 823 każda z nich wychodzi z własnego IP, ale limity samej strony nadal obowiązują. Dla jednej strony trzymaj niską wartość i podnoś ją tylko dla list różnych stron.

Transfer liczy się w obie strony. WebBaseLoader pobiera tylko HTML strony, bez obrazków i skryptów, więc kosztuje mniej niż loader oparty na przeglądarce, jeśli strona nie potrzebuje JavaScriptu. Usuń duplikaty adresów przed pobieraniem i zapisuj już pobrane URL, żeby kolejne uruchomienie je pomijało. Kupione gigabajty nie wygasają, więc przerwa między uruchomieniami nic nie kosztuje. Zbieraj tylko to, na co pozwalają zasady strony, i w granicach naszych zasad korzystania.

Jeśli proxy nie działa

Pytania i odpowiedzi (FAQ)

Czy mogę użyć SOCKS5?

W przypadku load() tak: zainstaluj pip install "requests[socks]" i ustaw w proxies adres socks5h://USERNAME:PASSWORD@gw.prokso.com:824 – wtedy przez proxy idą też zapytania DNS. Metody asynchroniczne działają na aiohttp, które obsługuje tylko proxy HTTP.

Proxy jest ustawione, ale strona widzi mój IP. Dlaczego?

Zwykle z jednego z dwóch powodów. Albo wywołujesz metodę asynchroniczną, która nie widzi parametru proxies – wtedy ustaw zmienne środowiskowe i trust_env=True. Albo w systemie są ustawione HTTP_PROXY lub HTTPS_PROXY z innym adresem i nadpisują one parametr.

Co oznacza ProxyError: 407?

Proxy odrzuciło login lub hasło. Skopiuj linię z generatora w panelu klienta jeszcze raz i sprawdź, czy w planie został jeszcze transfer.

Dlaczego loader asynchroniczny nie ponawia 403 ani 429?

Ponawia tylko błędy połączenia aiohttp. Kody od strony wracają jako tekst strony albo od razu jako błąd, jeśli ustawisz raise_for_status=True. Natychmiastowe ponowienie 429 i tak nie pomoże: zmniejsz requests_per_second i wróć później.

Czy mogę trzymać jeden IP dla wielostronicowego źródła bez portu ze stałym IP?

Tak. Dodaj ;sessid.<nazwa> do loginu na porcie 823, a adres utrzyma się przez około 30 minut. Do dłuższych zadań weź port ze stałym IP z zakresu 10000-20000: tam czas utrzymania ustawiasz w panelu, do 120 minut.

Czy wybór kraju w loginie kosztuje dodatkowo?

Nie, kraj jest bezpłatny. Podwójnie liczy się tylko transfer z dokładną geolokalizacją: region, miasto, kod pocztowy lub operator. Ceny za GB znajdziesz w <a href="/pl/pricing">cenniku</a>.