Learning Platform
Глоссарий Troubleshooting
Урок 13.01 · 25 мин
Начальный
curlwgetHTTPREST APIdownloadsauthentication

curl и wget: скачивание и HTTP из command line

curl и wget — две главные утилиты для работы с сетью из command line. На уровне «скачать файл» они выглядят похоже, но философия разная: curl — это универсальный HTTP-клиент для скриптов и API-запросов, wgetспециализированный downloader, заточенный под массовое и recursive скачивание.

Для DE это инструменты ежедневного использования: дёрнуть Airflow REST API, выкачать CSV-дамп с governmental portal, проверить, что endpoint жив, сделать webhook-вызов после ETL. В этом уроке — что и когда использовать.


curl vs wget: что выбрать

curl vs wget — разная философия

Один инструмент — для API, другой — для bulk downloads

curlУниверсальный HTTP/HTTPS/FTP/SFTP клиент. Поддерживает все методы (GET/POST/PUT/DELETE), headers, cookies, auth. По умолчанию выводит в stdout. Скриптинг-friendly
wgetСпециализированный downloader. По умолчанию сохраняет файлы. Поддерживает recursive download, resume, retry. Заточен под массовое скачивание
curl https://api/usersСкачать и вывести в stdout
wget https://example/fileСкачать и сохранить как локальный файл

Правило DE:

  • Делаешь HTTP API-запрос (REST API, webhook) -> curl
  • Качаешь файл с известного URL -> можно оба, но wget проще
  • Качаешь много файлов / recursive -> wget
  • Скрипт обрабатывает ответ через jq, awk -> curl

curl базовые приёмы

# Простой GET, тело в stdout
curl https://api.example.com/users

# Скачать и сохранить как локальный файл с тем же именем
curl -O https://example.com/data.csv
# data.csv появится в текущей директории

# Скачать и сохранить под другим именем
curl -o my-data.csv https://example.com/data.csv

# Следовать redirects (важно — без -L curl остановится на 301/302)
curl -L https://github.com/...

Флаги, которые встречаются часто:

Главные флаги curl

Что встретите в туториалах и Stack Overflow

-OSave as remote filename. Сохраняет с именем как на сервере
-o filenameSave as local filename. Сохраняет под указанным именем
-LFollow redirects (301/302/303/307/308). Без -L curl останется на странице redirect
-X METHODHTTP метод: GET, POST, PUT, DELETE, PATCH
-d 'data'Тело запроса (для POST/PUT)
-H 'Header: value'Кастомный header. Можно несколько -H
-sSilent — без progress bar
-SShow errors даже в silent mode. Обычно с -s
-iInclude response headers в выводе
-vVerbose — показать всё: handshake, request/response headers, body
-u user:passBasic auth. Лучше использовать -H 'Authorization: Bearer ...'
--data-binary @file.jsonПослать содержимое файла как тело (без mangling)
-w '%{http_code}'Шаблонизированный вывод. %{http_code} — статус код, %{time_total} — время

Анатомия HTTP-запроса: методы, заголовки, статус-коды

POST, PUT, DELETE — API-вызовы

# POST с JSON-телом
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "[email protected]"}'

# С Bearer token
curl -X POST https://api.example.com/users \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice"}'

# PUT, обновление
curl -X PUT https://api.example.com/users/123 \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'

# DELETE
curl -X DELETE https://api.example.com/users/123 \
  -H "Authorization: Bearer $TOKEN"

# Послать тело из файла
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  --data-binary @user.json
TIP

--data-binary @file (с символом @ перед именем файла) посылает содержимое точно как есть. Просто -d @file тоже работает, но -d удаляет переводы строк — это часто ломает JSON. Для JSON-данных всегда используйте --data-binary @.


Headers и аутентификация

# Один header
curl -H "Authorization: Bearer $TOKEN" https://api.example.com

# Несколько headers
curl -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     -H "X-Request-ID: $(uuidgen)" \
     https://api.example.com

# Basic auth (легаси, многие API уходят от него)
curl -u username:password https://api.example.com
# Эквивалент: -H "Authorization: Basic $(echo -n 'username:password' | base64)"

Сохранять токен в переменную окружения — стандарт:

# Один раз в shell
export AIRFLOW_TOKEN="eyJhbGc..."

# Использовать
curl -H "Authorization: Bearer $AIRFLOW_TOKEN" \
  https://airflow.company.com/api/v1/dags

Никогда не хардкодить токены в скрипты — кладите в .env файлы или secrets manager.


Обработка ответа: статус код, заголовки, тело

Иногда нужно знать: получилось ли? Какой статус?

# Только статус код
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com
# 200

# Статус + время
curl -s -o /dev/null \
  -w "status=%{http_code} time=%{time_total}s size=%{size_download}b\n" \
  https://api.example.com

# Статус и тело отдельно
curl -s -w "\n%{http_code}" https://api.example.com
# {"data": ...}
# 200

В скриптах:

#!/bin/bash
RESPONSE=$(curl -s -w "\n%{http_code}" "$URL")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')

if [ "$HTTP_CODE" != "200" ]; then
  echo "API error: $HTTP_CODE"
  echo "$BODY" >&2
  exit 1
fi

echo "$BODY" | jq '.data'

wget — для bulk и recursive

# Простое скачивание
wget https://example.com/data.csv

# Указать имя
wget -O backup.csv https://example.com/data.csv

# Тихо
wget -q https://example.com/data.csv

# С прогресс-баром
wget --progress=bar:force https://example.com/big-file.zip

# Resume прерванное скачивание
wget -c https://example.com/huge-file.tar.gz

Recursive download — конёк wget:

# Скачать весь сайт (или его раздел)
wget -r --no-parent https://example.com/docs/
# -r recursive
# --no-parent — не выходить «выше» по дереву URL

# Конкретные типы файлов
wget -r --no-parent -A "*.csv" https://data.gov.ru/2026/

# Ограничить глубину
wget -r -l 3 --no-parent https://example.com/

Полезные опции:

# Mirror (recursive + timestamps + no parent)
wget -m https://example.com

# С user-agent (некоторые сайты блокируют дефолтный)
wget -U "Mozilla/5.0" https://example.com

# Pause между запросами (не DDOS-ить сервер)
wget --wait=1 -r https://example.com

# Список URL из файла
wget -i urls.txt

DE-сценарии

1. Hit Airflow REST API

AIRFLOW="https://airflow.company.com/api/v1"
TOKEN="eyJhbGc..."

# Список DAGs
curl -s -H "Authorization: Bearer $TOKEN" "$AIRFLOW/dags" | jq '.dags[].dag_id'

# Триггер DAG
curl -X POST "$AIRFLOW/dags/etl_daily/dagRuns" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"conf\": {\"date\": \"2026-05-13\"}}"

# Статус последнего run
curl -s -H "Authorization: Bearer $TOKEN" \
  "$AIRFLOW/dags/etl_daily/dagRuns?limit=1&order_by=-execution_date" \
  | jq '.dag_runs[0].state'

2. Скачать data dump с публичного API

# Скачать CSV дамп
curl -L -o sales-2026-04.csv \
  "https://data.gov.example.com/2026/sales/2026-04.csv"

# Проверить размер
ls -lh sales-2026-04.csv

# Распарсить через awk
awk -F',' 'NR > 1 {sum += $3} END {print "Total:", sum}' sales-2026-04.csv

3. Health check для monitoring

#!/bin/bash
SERVICES=("https://airflow.company.com/health"
          "https://api.company.com/healthz"
          "https://grafana.company.com/api/health")

for url in "${SERVICES[@]}"; do
  CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url")
  if [ "$CODE" = "200" ]; then
    echo "OK: $url"
  else
    echo "FAIL: $url (HTTP $CODE)"
  fi
done

4. Webhook после ETL

# После успешной ETL — оповестить Slack
curl -X POST -H 'Content-type: application/json' \
  --data "{\"text\":\"ETL succeeded at $(date -Iseconds)\"}" \
  https://hooks.slack.com/services/T00000/B00000/XXXXXXXXX

5. Загрузить файл на S3 через presigned URL

# Получили presigned URL от backend
S3_URL="https://bucket.s3.amazonaws.com/upload?X-Amz-Algorithm=...&X-Amz-Signature=..."

# Upload через curl PUT
curl -X PUT \
  -H "Content-Type: application/octet-stream" \
  --data-binary @local-file.parquet \
  "$S3_URL"

curl для диагностики: timing, TLS, proxy, verbose

Debugging — когда не работает

# Verbose: показать всё
curl -v https://api.example.com
# Видно: DNS resolve, TCP connect, TLS handshake, headers, body

# Trace всего I/O в файл
curl --trace trace.log https://api.example.com

# Только заголовки ответа (HEAD-запрос)
curl -I https://api.example.com

# Время выполнения детально
curl -w "@curl-timing.txt" -o /dev/null -s https://api.example.com

Файл curl-timing.txt:

time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
time_total: %{time_total}\n

Это сразу видно: где задержка — в DNS, TCP connect, TLS handshake, или собственно сервер?


Хитрые моменты

URL-encoding

Параметры URL надо encode-ить:

# Плохо — пробелы и символы могут сломать URL
curl "https://api.example.com/search?q=data engineer&date=2026-05-13"

# Хорошо — --data-urlencode
curl -G "https://api.example.com/search" \
  --data-urlencode "q=data engineer" \
  --data-urlencode "date=2026-05-13"
# -G делает GET вместо POST, но использует --data

Proxy

# Через корпоративный proxy
curl -x http://proxy.company.com:8080 https://api.example.com

# Или через env vars (curl уважает)
export HTTPS_PROXY=http://proxy.company.com:8080
curl https://api.example.com

Игнорировать SSL ошибки (только для debug!)

# Если сервер с самоподписанным сертификатом
curl -k https://internal.dev.company.com
# В production никогда не используйте -k!

Попробуй сам

# 1. Простой GET
curl https://api.github.com/zen

# 2. Скачать с прогрессом
curl -O https://raw.githubusercontent.com/torvalds/linux/master/README

# 3. JSON-ответ + jq
curl -s https://api.github.com/users/torvalds | jq '.public_repos, .followers'

# 4. POST с JSON
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"hello": "world"}'

# 5. Только статус код
curl -s -o /dev/null -w "%{http_code}\n" https://github.com

# 6. Время выполнения
curl -s -o /dev/null \
  -w "DNS=%{time_namelookup} connect=%{time_connect} total=%{time_total}\n" \
  https://github.com

# 7. Recursive wget — небольшая страница
wget --no-parent -r -l 2 -A "*.html" https://example.com/

# 8. Resume — попробуй с большим файлом
wget -c https://download.geofabrik.de/europe-latest.osm.pbf
# Прерви через Ctrl-C, потом запусти ту же команду — продолжит с того же места

Cross-link: следующий урок 02 — ssh, для удалённого доступа. Модуль 18 — jq для обработки JSON-ответов. Модуль 17 — bash-скрипты с error handling для curl-вызовов.


Проверка знанийKnowledge check
У вас REST API за authentication, и нужно сделать POST с JSON-телом. Напишите curl-команду, которая: 1) посылает POST на https://api.example.com/etl/trigger, 2) включает Bearer token из переменной $ETL_TOKEN, 3) посылает тело {"date": "2026-05-13"}, 4) выводит только статус код в stdout, 5) не падает на redirect.
ОтветAnswer
curl -s -L -X POST https://api.example.com/etl/trigger -H "Authorization: Bearer $ETL_TOKEN" -H "Content-Type: application/json" -d '{"date": "2026-05-13"}' -o /dev/null -w "%{http_code}\n". Разбор флагов: -s silent (без progress bar), -L follow redirects (если API за load balancer возвращает 307), -X POST метод, -H заголовок (нужны два: Authorization и Content-Type), -d тело запроса (для small JSON inline ОК; для больших — --data-binary @file.json), -o /dev/null отбросить body (нам нужен только статус код), -w "%{http_code}\n" вывести только HTTP status в stdout. Это идиоматичная forme для health checks и triggers в bash-скриптах. Дальнейший шаг — проверить exit code или статус через if [ "$CODE" = "200" ]. Альтернатива через --fail (-f): curl вернёт ненулевой exit code если HTTP 4xx/5xx — удобно в скриптах с set -e.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Когда лучше использовать curl, а когда wget?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5