Я использую запросы-кэш для кэширования HTTP-ответов в удобочитаемом формате.
Я пропатчил requests
, используя бэкэнд filesystem
, и сериализатор на json
, вот так:
import requests_cache
requests_cache.install_cache('example_cache', backend='filesystem', serializer='json')
Ответы кэшируются как json, но тело ответа кодируется (я думаю, с использованием библиотеки коты, как описано здесь).
Есть ли способ заставить requests-cache
сохранять ответы как есть?
То, что вы хотите сделать, имеет смысл, но это немного сложнее, чем кажется. Файлы ответов, которые вы видите, являются представлениями объектов requests.Response
. Response._content
содержит исходные байты, полученные от сервера. Затем методы и свойства оболочки, такие как Response.json()
и Response.text
, попытаются декодировать этот контент. Чтобы объект Response
работал правильно, он должен иметь исходное двоичное тело ответа.
Когда request-cache сериализует этот ответ как JSON, двоичное содержимое кодируется в Base85. Вот почему вы видите там закодированные байты вместо JSON. Чтобы сохранить все, включая текст ответа, в формате JSON, есть несколько вариантов:
Сделайте пользовательский сериализатор. Если вы хотите иметь возможность изменять содержимое ответа и отражать эти изменения в ответах, возвращаемых request-cache, это, вероятно, будет лучшим способом сделать это.
Это может стать немного запутанным, потому что вам придется:
Response
.Однако это выполнимо. Я мог бы попытаться придумать пример позже, если это необходимо.
Сделайте пользовательский сервер. Он может расширить FileCache
и FileDict
и скопировать действительное содержимое JSON в отдельный файл. Вот рабочий пример:
import json
from os.path import splitext
from requests import Response
from requests_cache import CachedSession, FileCache, FileDict
class JSONFileCache(FileCache):
"""Filesystem backend that copies JSON-formatted response content into a separate file
alongside the main response file
"""
def __init__(self, cache_name, **kwargs):
super().__init__(cache_name, **kwargs)
self.responses = JSONFileDict(cache_name, **kwargs)
class JSONFileDict(FileDict):
def __setitem__(self, key: str, value: Response):
super().__setitem__(key, value)
response_path = splitext(self._path(key))[0]
json_path = f'{response_path}_content.json'
# Will handle errors and skip writing if content can't be decoded as JSON
with self._try_io(ignore_errors=True):
content = json.dumps(value.json(), indent=2)
with open(json_path, mode='w') as f:
f.write(content)
Пример использования:
custom_backend = JSONFileCache('example_cache', serializer='json')
session = CachedSession(backend=custom_backend)
session.get('https://httpbin.org/get')
После создания запроса вы увидите пару файлов вида:
example_cache/680f2a52944ee079.json
example_cache/680f2a52944ee079_content.json
Это может быть не совсем то, что вам нужно, но это самый простой вариант, если вам нужно только прочитать содержимое ответа и не нужно его изменять.