Как правильно обрабатывать сжатую страницу при использовании curl?

139

Я написал bash-скрипт, который получает выходные данные с веб-сайта, используя curl, и выполняет кучу манипуляций со строками в выводе html. Проблема в том, что когда я запускаю его на сайте, который возвращает данные gzipped. Переход на сайт в браузере работает нормально.

Когда я запускаю curl вручную, я получаю gzipped-вывод:

$ curl "http://example.com"

Вот заголовок с этого конкретного сайта:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
X-Powered-By: PHP/5.2.17
Last-Modified: Sat, 03 Dec 2011 00:07:57 GMT
ETag: "6c38e1154f32dbd9ba211db8ad189b27"
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: must-revalidate
Content-Encoding: gzip
Content-Length: 7796
Date: Sat, 03 Dec 2011 00:46:22 GMT
X-Varnish: 1509870407 1509810501
Age: 504
Via: 1.1 varnish
Connection: keep-alive
X-Cache-Svr: p2137050.pubip.peer1.net
X-Cache: HIT
X-Cache-Hits: 425

Я знаю, что возвращенные данные gzipped, потому что это возвращает HTML, как и ожидалось:

$ curl "http://example.com" | gunzip

Я не хочу передавать вывод через gunzip, потому что скрипт работает как есть на других сайтах, и передача через gzip нарушит эту функциональность.

Что я пробовал

  1. изменение пользовательского агента (я пробовал ту же строку, которую посылает мой браузер, «Mozilla / 4.0» и т. д.)
  2. локон
  3. поиск Гугл
  4. поиск в стеке

Все вышло пустым

Любые идеи?

BryanH
источник
Для меня проблема была в том, что cURL не смог распаковать Brotli ( curl 7.54.0 (x86_64-apple-darwin17.0) libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0) - решил это, удалив brиз Accept-Encoding. см. stackoverflow.com/questions/18983719/…
Нино Шкопац

Ответы:

260

curlавтоматически распакует ответ, если вы установите --compressedфлаг:

curl --compressed "http://example.com"

--compressed (HTTP) Запрос сжатого ответа с использованием одного из алгоритмов, поддерживаемых libcurl, и сохранение несжатого документа. Если эта опция используется и сервер отправляет неподдерживаемую кодировку, curl сообщит об ошибке.

GZIP, скорее всего поддерживается, но вы можете проверить это, запустив curl -Vи ищет libz где - то в «Особенности» линии:

$ curl -V
...
Protocols: ...
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 

Обратите внимание, что здесь действительно виноват рассматриваемый веб-сайт. Если curlне прошел Accept-Encoding: gzipзаголовок запроса, сервер не должен был отправлять сжатый ответ.

Мартин
источник
24
Это может показаться ошибкой скручивания, потому что она должна запускать свое декодирование на основе ответа, а не того, что запросила (учитывая, что она поддерживает gzip). Цитируя HTTP 1.1: «Если в запросе нет поля Accept-Encoding, сервер МОЖЕТ предположить, что клиент примет любое кодирование контента». Но это говорит о том, что серверы ДОЛЖНЫ в этом случае не кодировать контент, хм, иди разберись.
Джордж Лунд
на самом деле на моей версии работает --comp --compress --compressed
Radu
3
это также устанавливает заголовок запроса: «Accept-Encoding: deflate, gzip», это замечательно, поскольку, если сервер обслуживает gzip и не использует gzip, вам просто нужно --compressed и не добавлять заголовок accept encoding самостоятельно
mbert
помогите моему QA с этим решением за 1 минуту! Спасибо ! Тем не менее, мое приложение фактически отправляет ответ gzip с Content-Encoding: gzip. Браузеры и современные инструменты (например, httpie) автоматически справляются с этим. Я думаю, что curl просто нужен «намек»
Faraway
Удивительно, но настройки Accept-Encoding: deflate, gzipнедостаточно - даже если сервер возвращает ответ gzip с помощью Content-Encoding: gzip, curl не разархивирует его автоматически. --compressedФлаг требуется.
RJH