diff --git a/CHANGES.md b/CHANGES.md
index c610c2f..ed13d9e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,6 +11,12 @@ Whenever possible, link the given PR with the feature/fix.
 
 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## Development
+
+### Added
+
+* New setting `SPIDERFEEDER_INPUT_FORMAT` to set the file format or fall back to the file extension. [PR#18](https://github.com/ejulio/spider-feeder/pull/18)
+
 
 ## 0.2.0 (2019-08-27)
 
diff --git a/README.md b/README.md
index 1505701..d06fa3a 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,11 @@ There are two extensions to load input data to your spiders.
 
 `SPIDERFEEDER_INPUT_FILE_ENCODING` sets the file encoding. DEFAULT = `'utf-8'`.
 
+`SPIDERFEEDER_INPUT_FORMAT` sets the file format (`txt`, `csv`, `json`). DEFAULT = `None`.
+This setting is preferred over the file extension in `SPIDERFEEDER_INPUT_URI`.
+So, if `SPIDERFEEDER_INPUT_FORMAT` is set, this is the one to be used, otherwise
+it will fall back to the file extension in `SPIDERFEEDER_INPUT_URI`.
+
 `SPIDERFEEDER_INPUT_FIELD` sets the url field when parsing `json` or `csv` files.
 
 `SPIDERFEEDER_FILE_HANDLERS` is a set of functions to be matched with the given file scheme.
diff --git a/spider_feeder/store/file_store.py b/spider_feeder/store/file_store.py
index 8cd7ba1..b88a1e0 100644
--- a/spider_feeder/store/file_store.py
+++ b/spider_feeder/store/file_store.py
@@ -38,7 +38,8 @@ class FileStore(BaseStore):
         super().__init__(settings)
         self._input_file_uri = input_file_uri
         self._settings = settings
-        self._file_encoding = settings.get('SPIDERFEEDER_INPUT_FILE_ENCODING', 'utf-8')
+        self._input_file_encoding = settings.get('SPIDERFEEDER_INPUT_FILE_ENCODING', 'utf-8')
+        self._input_format = settings.get('SPIDERFEEDER_INPUT_FORMAT', None)
 
         handlers = settings.getdict('SPIDERFEEDER_FILE_HANDLERS', {})
         self._handlers = dict(self.FILE_HANDLERS, **handlers)
@@ -46,17 +47,24 @@ class FileStore(BaseStore):
         parsers = settings.getdict('SPIDERFEEDER_FILE_PARSERS', {})
         self._parsers = dict(self.FILE_PARSERS, **parsers)
 
+    @property
+    def _file_format(self):
+        if self._input_format:
+            return self._input_format
+
+        (_, file_extension) = path.splitext(self._input_file_uri)
+        return file_extension[1:]  # remove the "."
+
     def _open(self):
         parsed = urlparse(self._input_file_uri)
         logger.info(f'Opening file {self._input_file_uri} with scheme {parsed.scheme}.')
         open = load_object(self._handlers[parsed.scheme])
-        return open(self._input_file_uri, encoding=self._file_encoding)
+        return open(self._input_file_uri, encoding=self._input_file_encoding)
 
     def _parse(self, fd):
-        (_, file_extension) = path.splitext(self._input_file_uri)
-        file_extension = file_extension[1:]
-        logger.info(f'Parsing file {self._input_file_uri} with format {file_extension}.')
-        parser = load_object(self._parsers[file_extension])
+        file_format = self._file_format
+        logger.info(f'Parsing file {self._input_file_uri} with format {file_format}.')
+        parser = load_object(self._parsers[file_format])
         return parser(fd, self._settings)
 
     def read_input_items(self):

Add a setting for input format
Currently the input format is inferred from the URI extension.
However, it may fail in cases of URLs or files without extension.

Add a new setting, `SPIDERFEEDER_INPUT_FORMAT`? that sets the file format.
If it is not set, the it falls back to the file extension
diff --git a/tests/store/test_file_store.py b/tests/store/test_file_store.py
index a255af3..913f215 100644
--- a/tests/store/test_file_store.py
+++ b/tests/store/test_file_store.py
@@ -98,6 +98,54 @@ def test_load_json_file(mocker, uri_scheme, file_opener):
     ]
 
 
+@pytest.mark.parametrize('uri_scheme, file_opener', [
+    ('file://', 'spider_feeder.store.file_handler.local.open'),
+    ('s3://', 'spider_feeder.store.file_handler.s3.open'),
+    ('', 'spider_feeder.store.file_handler.local.open'),
+])
+def test_get_file_format_from_setting(mocker, uri_scheme, file_opener):
+    file_content = StringIO('\n'.join(['http://url1.com', 'http://url2.com']))
+    mock = mocker.patch(file_opener, return_value=file_content, autospec=True)
+
+    store = FileStore(f'{uri_scheme}temp', Settings({
+        'SPIDERFEEDER_INPUT_FORMAT': 'txt'
+    }))
+
+    store_meta = []
+    store_urls = []
+    for (url, meta) in store:
+        store_urls.append(url)
+        store_meta.append(meta)
+
+    mock.assert_called_with(f'{uri_scheme}temp', encoding='utf-8')
+    assert store_meta == [{}, {}]
+    assert store_urls == ['http://url1.com', 'http://url2.com']
+
+
+@pytest.mark.parametrize('uri_scheme, file_opener', [
+    ('file://', 'spider_feeder.store.file_handler.local.open'),
+    ('s3://', 'spider_feeder.store.file_handler.s3.open'),
+    ('', 'spider_feeder.store.file_handler.local.open'),
+])
+def test_get_file_format_setting_is_preferred_over_file_extension(mocker, uri_scheme, file_opener):
+    file_content = StringIO('\n'.join(['http://url1.com', 'http://url2.com']))
+    mock = mocker.patch(file_opener, return_value=file_content, autospec=True)
+
+    store = FileStore(f'{uri_scheme}temp.csv', Settings({
+        'SPIDERFEEDER_INPUT_FORMAT': 'txt'
+    }))
+
+    store_meta = []
+    store_urls = []
+    for (url, meta) in store:
+        store_urls.append(url)
+        store_meta.append(meta)
+
+    mock.assert_called_with(f'{uri_scheme}temp.csv', encoding='utf-8')
+    assert store_meta == [{}, {}]
+    assert store_urls == ['http://url1.com', 'http://url2.com']
+
+
 def test_fail_if_input_field_and_not_dict_data(mocker):
     mocker.patch(
         'spider_feeder.store.file_handler.local.open',

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-django pytest-cov pytest-localserver pytest-mock pytest-benchmark pytest-bdd pytest-rerunfailures jsonschema more-itertools pluggy atomicwrites pyrsistent configparser contextlib2 importlib-metadata packaging Mako glob2 parse parse-type toml iniconfig docutils py-cpuinfo urllib3 certifi Logbook WebOb argparse greenlet mock msgpack-python pep8 pytz ecs_logging structlog pytest-asyncio asynctest typing_extensions
apt-get update apt-get install -y gcc
3.9
tests/requirements/reqs-base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asynctest==0.13.0
atomicwrites==1.4.1
attrs==25.3.0
Automat==24.8.1
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
configparser==7.2.0
constantly==23.10.4
contextlib2==21.6.0
coverage==7.8.0
cryptography==44.0.2
cssselect==1.3.0
defusedxml==0.7.1
docutils==0.21.2
ecs-logging==2.2.0
exceptiongroup==1.2.2
filelock==3.18.0
gherkin-official==29.0.0
glob2==0.7
greenlet==3.1.1
hyperlink==21.0.0
idna==3.10
importlib_metadata==8.6.1
incremental==24.7.2
iniconfig==2.1.0
itemadapter==0.11.0
itemloaders==1.3.2
jmespath==1.0.1
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
Logbook==1.8.1
lxml==5.3.1
Mako==1.3.9
MarkupSafe==3.0.2
mock==5.2.0
more-itertools==10.6.0
msgpack-python==0.5.6
packaging==24.2
parse==1.20.2
parse_type==0.6.4
parsel==1.10.0
pep8==1.7.1
pluggy==1.5.0
Protego==0.4.0
py-cpuinfo==9.0.0
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
PyDispatcher==2.0.7
pyOpenSSL==25.0.0
pyrsistent==0.20.0
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-bdd==8.1.0
pytest-benchmark==5.1.0
pytest-cov==6.0.0
pytest-django==4.10.0
pytest-localserver==0.9.0.post0
pytest-mock==3.14.0
pytest-rerunfailures==15.0
pytz==2025.2
queuelib==1.8.0
referencing==0.36.2
requests==2.32.3
requests-file==2.1.0
rpds-py==0.24.0
Scrapy==2.12.0
service-identity==24.2.0
six==1.17.0
-e git+https://github.com/ejulio/spider-feeder.git@33b16cc74b46b119cf3fd483c789dad70f3a9102#egg=spider_feeder
structlog==25.2.0
tldextract==5.1.3
toml==0.10.2
tomli==2.2.1
Twisted==24.11.0
typing_extensions==4.13.0
urllib3==2.3.0
w3lib==2.3.1
WebOb==1.8.9
Werkzeug==3.1.3
zipp==3.21.0
zope.interface==7.2

name: spider-feeder
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - argparse==1.4.0
      - asynctest==0.13.0
      - atomicwrites==1.4.1
      - attrs==25.3.0
      - automat==24.8.1
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - configparser==7.2.0
      - constantly==23.10.4
      - contextlib2==21.6.0
      - coverage==7.8.0
      - cryptography==44.0.2
      - cssselect==1.3.0
      - defusedxml==0.7.1
      - docutils==0.21.2
      - ecs-logging==2.2.0
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - gherkin-official==29.0.0
      - glob2==0.7
      - greenlet==3.1.1
      - hyperlink==21.0.0
      - idna==3.10
      - importlib-metadata==8.6.1
      - incremental==24.7.2
      - iniconfig==2.1.0
      - itemadapter==0.11.0
      - itemloaders==1.3.2
      - jmespath==1.0.1
      - jsonschema==4.23.0
      - jsonschema-specifications==2024.10.1
      - logbook==1.8.1
      - lxml==5.3.1
      - mako==1.3.9
      - markupsafe==3.0.2
      - mock==5.2.0
      - more-itertools==10.6.0
      - msgpack-python==0.5.6
      - packaging==24.2
      - parse==1.20.2
      - parse-type==0.6.4
      - parsel==1.10.0
      - pep8==1.7.1
      - pluggy==1.5.0
      - protego==0.4.0
      - py-cpuinfo==9.0.0
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pydispatcher==2.0.7
      - pyopenssl==25.0.0
      - pyrsistent==0.20.0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-bdd==8.1.0
      - pytest-benchmark==5.1.0
      - pytest-cov==6.0.0
      - pytest-django==4.10.0
      - pytest-localserver==0.9.0.post0
      - pytest-mock==3.14.0
      - pytest-rerunfailures==15.0
      - pytz==2025.2
      - queuelib==1.8.0
      - referencing==0.36.2
      - requests==2.32.3
      - requests-file==2.1.0
      - rpds-py==0.24.0
      - scrapy==2.12.0
      - service-identity==24.2.0
      - six==1.17.0
      - structlog==25.2.0
      - tldextract==5.1.3
      - toml==0.10.2
      - tomli==2.2.1
      - twisted==24.11.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - w3lib==2.3.1
      - webob==1.8.9
      - werkzeug==3.1.3
      - zipp==3.21.0
      - zope-interface==7.2
prefix: /opt/conda/envs/spider-feeder

tests/store/test_file_store.py::test_get_file_format_from_setting[file://-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_get_file_format_from_setting[-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_get_file_format_setting_is_preferred_over_file_extension[file://-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_get_file_format_setting_is_preferred_over_file_extension[-spider_feeder.store.file_handler.local.open]
tests/store/test_file_store.py::test_load_txt_file[s3://-spider_feeder.store.file_handler.s3.open] tests/store/test_file_store.py::test_load_csv_file[s3://-spider_feeder.store.file_handler.s3.open] tests/store/test_file_store.py::test_load_json_file[s3://-spider_feeder.store.file_handler.s3.open] tests/store/test_file_store.py::test_get_file_format_from_setting[s3://-spider_feeder.store.file_handler.s3.open] tests/store/test_file_store.py::test_get_file_format_setting_is_preferred_over_file_extension[s3://-spider_feeder.store.file_handler.s3.open]
tests/store/test_file_store.py::test_load_txt_file[file://-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_load_txt_file[-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_load_csv_file[file://-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_load_csv_file[-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_load_json_file[file://-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_load_json_file[-spider_feeder.store.file_handler.local.open] tests/store/test_file_store.py::test_fail_if_input_field_and_not_dict_data tests/store/test_file_store.py::test_file_encoding tests/store/test_file_store.py::test_custom_file_handler tests/store/test_file_store.py::test_custom_file_parser
README.md spider_feeder/store/file_store.py CHANGES.md
README.md spider_feeder/store/file_store.py CHANGES.md