diff --git a/src/caoscrawler/__init__.py b/src/caoscrawler/__init__.py
index 3c71caed3362e50b5c4af947e0e3b1fa7805f8d5..41b96323b1106d8ce28caadc4a2da012f3dc22ea 100644
--- a/src/caoscrawler/__init__.py
+++ b/src/caoscrawler/__init__.py
@@ -1,5 +1,10 @@
-from . import converters
-from .conv_impl.spss import SPSSConverter
+from . import converters, utils
+try:
+    from .conv_impl.spss import SPSSConverter
+except ImportError as err:
+    SPSSConverter: type = utils.MissingImport(
+        name="SPSSConverter", hint="Try installing with the `spss` extra option.",
+        err=err)
 from .crawl import Crawler, SecurityMode
 from .version import CfoodRequiredVersionError, get_caoscrawler_version
 
diff --git a/src/caoscrawler/utils.py b/src/caoscrawler/utils.py
index c62f44eeaa75ca42579aa3d6ead437e901cd38ff..096fde9b573f4ff60995498144cad3589ce7dbb2 100644
--- a/src/caoscrawler/utils.py
+++ b/src/caoscrawler/utils.py
@@ -25,6 +25,9 @@
 
 # Some utility functions, e.g. for extending pylib.
 
+import sys
+from typing import Optional
+
 import linkahead as db
 
 
@@ -39,3 +42,30 @@ def has_parent(entity: db.Entity, name: str):
         if parent.name == name:
             return True
     return False
+
+
+def MissingImport(name: str, hint: str = "", err: Optional[Exception] = None) -> type:
+    """Factory with dummy classes, which may be assigned to variables but never used."""
+    def _error():
+        error_msg = f"This class ({name}) cannot be used, because some libraries are missing."
+        if hint:
+            error_msg += "\n\n" + hint
+
+        if err:
+            print(error_msg, file=sys.stdout)
+            raise RuntimeError(error_msg) from err
+        raise RuntimeError(error_msg)
+
+    class _Meta(type):
+        def __getattribute__(cls, *args, **kwargs):
+            _error()
+
+        def __call__(cls, *args, **kwargs):
+            _error()
+
+    class _DummyClass(metaclass=_Meta):
+        pass
+
+    _DummyClass.__name__ = name
+
+    return _DummyClass
diff --git a/unittests/test_utilities.py b/unittests/test_utilities.py
index 5a80ab9b230db4540d741bf8fa4f9d11b5158aab..dfb79c8b6b10909952174cf24c3aa9198f3b7743 100644
--- a/unittests/test_utilities.py
+++ b/unittests/test_utilities.py
@@ -19,7 +19,10 @@
 # along with this program. If not, see <https://www.gnu.org/licenses/>.
 #
 
+import pytest
+
 from caoscrawler.crawl import split_restricted_path
+from caoscrawler.utils import MissingImport
 
 
 def test_split_restricted_path():
@@ -33,3 +36,33 @@ def test_split_restricted_path():
     assert split_restricted_path("/test//bla") == ["test", "bla"]
     assert split_restricted_path("//test/bla") == ["test", "bla"]
     assert split_restricted_path("///test//bla////") == ["test", "bla"]
+
+
+def test_dummy_class():
+    Missing = MissingImport(name="Not Important", hint="Do the thing instead.")
+    with pytest.raises(RuntimeError) as err_info_1:
+        print(Missing.__name__)
+    with pytest.raises(RuntimeError) as err_info_2:
+        Missing()
+    with pytest.raises(RuntimeError) as err_info_3:
+        print(Missing.foo)
+
+    for err_info in (err_info_1, err_info_2, err_info_3):
+        msg = str(err_info.value)
+        assert "(Not Important)" in msg
+        assert msg.endswith("Do the thing instead.")
+
+    MissingErr = MissingImport(name="Not Important", hint="Do the thing instead.",
+                               err=ImportError("Old error"))
+    with pytest.raises(RuntimeError) as err_info_1:
+        print(MissingErr.__name__)
+    with pytest.raises(RuntimeError) as err_info_2:
+        MissingErr()
+    with pytest.raises(RuntimeError) as err_info_3:
+        print(MissingErr.foo)
+
+    for err_info in (err_info_1, err_info_2, err_info_3):
+        msg = str(err_info.value)
+        assert "(Not Important)" in msg
+        orig_msg = str(err_info.value.__cause__)
+        assert orig_msg == "Old error"