Skrócenie URL-a w Pythonie to jedno żądanie HTTP POST. Wysyłasz swój długi link do API skracacza za pomocą biblioteki requests, przekazujesz klucz API jako token Bearer i odczytujesz krótki link z odpowiedzi JSON. Całość mieści się w około pięciu liniach, a reszta tego przewodnika pokazuje, co dodać, gdy robisz to na poważnie: obsługę błędów, idempotencję, masowe skracanie i async.
To deweloperska wersja ogólnego przewodnika jak skrócić URL - tamten obejmuje przepływ przez panel i przeglądarkę, ten to kod, który możesz wkleić do skryptu. Endpointy i nazwy pól poniżej pochodzą z API Elido, ale kształt (POST z adresem docelowym, w odpowiedzi krótki URL) jest taki sam w większości nowoczesnych skracaczy, więc te wzorce da się przenieść.
Zacznij od przeglądu darmowego API skracacza URL, jeśli nie wybrałeś jeszcze usługi - opisuje kształt żądania, model autoryzacji i limity darmowego planu, które ten artykuł zakłada.
Najszybsza droga: jeden POST z requests
Zainstaluj requests, umieść klucz API w zmiennej środowiskowej i wyślij POST z docelowym URL-em do endpointu links:
import os
import requests
resp = requests.post(
"https://api.elido.app/v1/links",
headers={"Authorization": f"Bearer {os.environ['ELIDO_API_KEY']}"},
json={"destination_url": "https://example.com/a-very-long-path?with=params"},
timeout=10,
)
resp.raise_for_status()
print(resp.json()["short_url"]) # -> https://s.elido.me/ab12cd
Trzy rzeczy sprawiają, że jest to kod produkcyjny, a nie zabawka. Klucz API pochodzi ze zmiennej środowiskowej, nigdy nie jest wartością literalną w kodzie źródłowym. Ustawiony jest timeout, więc zawieszone połączenie zawodzi szybko zamiast blokować w nieskończoność. A raise_for_status() zamienia kod 4xx lub 5xx w wyjątek, który możesz przechwycić, zamiast pozwalać nieudanemu wywołaniu wyglądać jak sukces.
Odpowiedź jest w JSON-ie. Odczytaj short_url, by dostać gotowy link; większość skracaczy zwraca też id, które warto zapisać, jeśli planujesz później edytować lub wygasić link.
Poprawnie obsłuż błędy i limity szybkości
Ścieżka bez błędów to pięć linii. Skrypt uruchamiany bez nadzoru musi przetrwać te nieprzyjemne przypadki: chwilowy błąd 5xx, kod 429 gdy działasz zbyt szybko, chwilowe zerwanie sieci. Owiń wywołanie tak, by ponawiało próbę przy błędach, które warto ponowić, i poddawało się przy tych, które nigdy się nie powiodą.
import os
import time
import requests
def shorten(destination: str, *, retries: int = 3) -> str:
headers = {"Authorization": f"Bearer {os.environ['ELIDO_API_KEY']}"}
for attempt in range(retries):
resp = requests.post(
"https://api.elido.app/v1/links",
headers=headers,
json={"destination_url": destination},
timeout=10,
)
if resp.status_code == 429:
time.sleep(int(resp.headers.get("Retry-After", 2)))
continue
if resp.status_code >= 500:
time.sleep(2 ** attempt) # exponential backoff
continue
resp.raise_for_status() # 4xx other than 429 -> raise
return resp.json()["short_url"]
raise RuntimeError(f"shorten failed after {retries} attempts")
Kod 401 lub 403 nigdy nie naprawi się samoistnie przez ponawianie próby, więc te przypadki trafiają do raise_for_status() i zatrzymują skrypt. Kod 429 respektuje nagłówek Retry-After wysyłany przez API. Kod 5xx wycofuje się wykładniczo. Dogłębny artykuł o limitach szybkości i idempotencji wyjaśnia, dlaczego ślepe ponawianie prób zamienia jedną awarię w dwie.
Wyślij Idempotency-Key, by ponowienia nie tworzyły duplikatów
Oto subtelny błąd w powyższej pętli ponawiania prób. Jeśli POST zakończy się sukcesem na serwerze, ale odpowiedź zgubi się w drodze powrotnej, Twój kod widzi timeout, ponawia próbę i tworzy drugi krótki link dla tego samego URL-a. Klucz idempotencji to naprawia: wyślij stały, unikalny klucz z każdym logicznym żądaniem, a API przy powtórce zwróci oryginalny link zamiast tworzyć nowy.
import uuid
key = str(uuid.uuid4()) # one key per URL you want shortened once
resp = requests.post(
"https://api.elido.app/v1/links",
headers={
"Authorization": f"Bearer {os.environ['ELIDO_API_KEY']}",
"Idempotency-Key": key,
},
json={"destination_url": "https://example.com/launch"},
timeout=10,
)
Wygeneruj klucz raz na URL i używaj go ponownie przy kolejnych próbach dla tego samego URL-a - nie osobno dla każdej próby. Przechowuj go razem z URL-em, jeśli sama partia może zostać uruchomiona ponownie. To pojedynczy, najważniejszy nawyk, gdy przechodzisz od skracania jednego linku do skracania listy, i jest on wbudowany w API i SDK właśnie z tego powodu.
Skracanie adresów URL masowo
Mając bezpieczną funkcję shorten(), partia to pętla - ale pętla, która respektuje limit szybkości i nie gubi mapowania między wejściem a wyjściem:
urls = [
"https://example.com/spring-sale",
"https://example.com/newsletter",
"https://example.com/docs/getting-started",
]
results = {}
for url in urls:
try:
results[url] = shorten(url)
except Exception as err: # log and keep going; one bad URL should not sink the batch
results[url] = f"ERROR: {err}"
for original, short in results.items():
print(f"{short}\t{original}")
Trzymanie wyniku w słowniku kluczowanym oryginalnym URL-em sprawia, że częściowa awaria jest widoczna i można ją ponowić, zamiast być cichą luką. Dla kilkuset linków ta sekwencyjna wersja wystarczy. Dla tysięcy opóźnienie sieciowe zaczyna się kumulować, i to właśnie tam async zdobywa swoje miejsce.
Async na dużą skalę z httpx
Gdy partia jest duża, wąskim gardłem jest oczekiwanie na sieć, a nie Python. Asynchroniczny klient, taki jak httpx, wysyła wiele żądań równolegle, jednocześnie utrzymując pułap tego, ile jest w locie, dzięki czemu wysycasz połączenie bez wpadnięcia w limit szybkości.
import asyncio
import os
import httpx
async def shorten_all(urls: list[str], concurrency: int = 10) -> dict[str, str]:
headers = {"Authorization": f"Bearer {os.environ['ELIDO_API_KEY']}"}
limit = asyncio.Semaphore(concurrency)
out: dict[str, str] = {}
async with httpx.AsyncClient(timeout=10) as client:
async def one(url: str) -> None:
async with limit:
r = await client.post(
"https://api.elido.app/v1/links",
headers=headers,
json={"destination_url": url},
)
out[url] = r.json()["short_url"]
await asyncio.gather(*(one(u) for u in urls))
return out
# asyncio.run(shorten_all(my_urls))
Semaphore(10) to cały trik: ogranicza liczbę równoczesnych żądań do dziesięciu, więc działasz szybko, nie zasypując API kodami 429. Dostosuj tę wartość do udokumentowanego limitu danego planu. Pełny kształt żądania, nazwy pól i aktualne limity znajdziesz w dokumentacji API, a rozwiązania dla deweloperów zawierają SDK, jeśli wolisz nie pisać klienta ręcznie.
Które podejście wybrać
Dopasuj narzędzie do rozmiaru zadania. Jeden link w skrypcie: pięciolinijkowe wywołanie requests. Solidne zadanie uruchamiane cyklicznie: wersja z retry i idempotencją. Jednorazowa partia kilkuset linków: pętla sekwencyjna. Dziesiątki tysięcy na termin: httpx z semaforem.
Bez względu na to, co wybierzesz, trzymaj klucz w zmiennej środowiskowej, ustaw timeout i wysyłaj klucz idempotencji przy wszystkim, co może zostać ponowione. Te trzy nawyki to różnica między fragmentem kodu na pokaz a skryptem, który możesz zostawić działający.
Przeczytaj serię filarową
Ten artykuł należy do klastra engineering. Punktem wyjścia jest przewodnik po darmowym API skracacza URL dla kształtu endpointów i autoryzacji, a następnie artykuł o limitach szybkości i idempotencji, by dobrze zachowywać się pod obciążeniem. Żywym źródłem referencyjnym jest dokumentacja API.
Powiązane wpisy na blogu
Najczęściej zadawane pytania
Jak skrócić URL w Pythonie?
Wyślij żądanie HTTP POST do API skracacza URL za pomocą biblioteki requests, przekazując swój długi URL w treści JSON, a klucz API jako token Bearer, a następnie odczytaj krótki link z odpowiedzi JSON. To około pięciu linii: zbudować nagłówki, wysłać docelowy URL do endpointu links i wypisać response.json()['short_url'].
Czy mogę skrócić URL w Pythonie bez zewnętrznej biblioteki?
Tak. urllib.request z biblioteki standardowej potrafi wysłać POST z treścią JSON bez instalowania czegokolwiek, co przydaje się w środowisku z ograniczeniami. Jest bardziej rozwlekłe niż requests - treść trzeba zakodować samodzielnie, nagłówki ustawić ręcznie, a odpowiedź odczytać samemu - ale nie wymaga żadnego pip install.
Jak skrócić wiele adresów URL naraz w Pythonie?
Przejdź pętlą przez listę i wyślij POST dla każdego z nich, ale dodaj Idempotency-Key dla każdego URL-a, tak by ponowna próba nigdy nie utworzyła duplikatu, i respektuj limit szybkości API, wycofując się przy HTTP 429. Dla dużych partii asynchroniczny klient, taki jak httpx z ograniczonym semaforem, skraca tysiące adresów URL równolegle, zamiast robić to jeden po drugim.
Dlaczego moje żądanie skracacza URL w Pythonie zwraca 401?
Kod 401 oznacza, że klucz API jest brakujący lub błędny w nagłówku Authorization. Sprawdź, czy wysyłasz dokładnie 'Authorization: Bearer YOUR_API_KEY', że klucz nie został unieważniony i że wczytałeś go ze zmiennej środowiskowej, a nie wkleiłeś przeterminowanego. Kod 403 oznacza natomiast, że klucz jest ważny, ale brakuje mu zakresu uprawnień dla tej akcji.
Wypróbuj Elido
Wklej URL, otrzymaj krótki link
Bez rejestracji. Link działa 30 dni. Zarejestruj się, aby zachować go na zawsze.
Za darmo, bez rejestracji · 2 dziennie