diff --git a/instapi/models/feed.py b/instapi/models/feed.py
index 300bb30..7d0e74e 100644
--- a/instapi/models/feed.py
+++ b/instapi/models/feed.py
@@ -1,5 +1,5 @@
 from dataclasses import dataclass
-from typing import Iterable, List, Optional
+from typing import Iterable, List, Optional, cast
 
 from ..cache import cached
 from ..client import client
@@ -23,6 +23,10 @@ class Feed(ResourceContainer):
     like_count: int
     comment_count: int = 0
 
+    @property
+    def caption(self) -> str:
+        return cast(str, self._media_info()["caption"]["text"])
+
     @classmethod
     def iter_timeline(cls) -> Iterable["Feed"]:
         """
diff --git a/instapi/models/media.py b/instapi/models/media.py
index 2ef1352..775db03 100644
--- a/instapi/models/media.py
+++ b/instapi/models/media.py
@@ -1,6 +1,7 @@
 from dataclasses import dataclass
 from typing import cast
 
+from ..cache import cached
 from ..client import client
 from ..types import StrDict
 from .base import Entity
@@ -8,6 +9,7 @@ from .base import Entity
 
 @dataclass(frozen=True)
 class Media(Entity):
+    @cached
     def _media_info(self) -> StrDict:
         items, *_ = client.media_info(self.pk)["items"]
         return cast(StrDict, items)
diff --git a/instapi/models/resource.py b/instapi/models/resource.py
index dfbcf93..db43a09 100644
--- a/instapi/models/resource.py
+++ b/instapi/models/resource.py
@@ -195,7 +195,7 @@ class Image(Resource):
         """
         try:
             from PIL import Image as PILImage
-        except ImportError:
+        except ImportError:  # pragma: no cover
             raise RuntimeError("Inst-API is installed without pillow\npip install inst-api[pillow]")
 
         candidate = candidate or self.best_candidate

diff --git a/tests/unit_tests/models/test_feed.py b/tests/unit_tests/models/test_feed.py
index 5aca118..85c82ad 100644
--- a/tests/unit_tests/models/test_feed.py
+++ b/tests/unit_tests/models/test_feed.py
@@ -1,6 +1,6 @@
 from pytest import fixture
 
-from ..conftest import random_int
+from ..conftest import random_int, random_string
 from .conftest import as_dicts
 
 
@@ -109,3 +109,11 @@ class TestFeed:
         feeds = feed.timeline(limit=limit)
 
         assert feeds == feeds[:limit]
+
+    def test_caption(self, mocker, feed):
+        caption = random_string()
+        mocker.patch(
+            "instapi.models.feed.Feed._media_info", return_value={"caption": {"text": caption}}
+        )
+
+        assert feed.caption == caption

Need implementation of getting post messages
There is not enough method to extract the text of posts using the public API.
Currently it is needed to use low-level API method `_media_info` to get a post caption.

*Example*
```python
user = User.from_username('9gag')

f, = user.feeds(limit=1)
print(f._media_info()['caption']['text'])
```
tests/unit_tests/models/test_feed.py::TestFeed::test_caption
tests/unit_tests/models/test_feed.py::TestFeed::test_usertags_one_user tests/unit_tests/models/test_feed.py::TestFeed::test_usertags_many_users tests/unit_tests/models/test_feed.py::TestFeed::test_usertags_no_users tests/unit_tests/models/test_feed.py::TestFeed::test_like tests/unit_tests/models/test_feed.py::TestFeed::test_unlike tests/unit_tests/models/test_feed.py::TestFeed::test_liked_by_user_in_likers tests/unit_tests/models/test_feed.py::TestFeed::test_liked_by_user_not_in_likers tests/unit_tests/models/test_feed.py::TestFeed::test_iter_likes tests/unit_tests/models/test_feed.py::TestFeed::test_likes_without_limit tests/unit_tests/models/test_feed.py::TestFeed::test_likes_with_limit tests/unit_tests/models/test_feed.py::TestFeed::test_iter_comments tests/unit_tests/models/test_feed.py::TestFeed::test_comments_without_limit tests/unit_tests/models/test_feed.py::TestFeed::test_comments_with_limit tests/unit_tests/models/test_feed.py::TestFeed::test_iter_timeline tests/unit_tests/models/test_feed.py::TestFeed::test_timeline_without_limit tests/unit_tests/models/test_feed.py::TestFeed::test_timeline_with_limit