diff --git a/w3lib/url.py b/w3lib/url.py
index 4be74f7..fc9b343 100644
--- a/w3lib/url.py
+++ b/w3lib/url.py
@@ -182,6 +182,8 @@ def url_query_cleaner(url, parameterlist=(), sep='&', kvsep='=', remove=False, u
     seen = set()
     querylist = []
     for ksv in query.split(sep):
+        if not ksv:
+            continue
         k, _, _ = ksv.partition(kvsep)
         if unique and k in seen:
             continue

diff --git a/tests/test_url.py b/tests/test_url.py
index 0df5bfd..9476b30 100644
--- a/tests/test_url.py
+++ b/tests/test_url.py
@@ -284,6 +284,10 @@ class UrlTests(unittest.TestCase):
                          'http://example.com/?version=1&pageurl=test&param2=value2')
 
     def test_url_query_cleaner(self):
+        self.assertEqual('product.html',
+                url_query_cleaner("product.html?"))
+        self.assertEqual('product.html',
+                url_query_cleaner("product.html?&"))
         self.assertEqual('product.html?id=200',
                 url_query_cleaner("product.html?id=200&foo=bar&name=wired", ['id']))
         self.assertEqual('product.html?id=200',
@@ -308,6 +312,10 @@ class UrlTests(unittest.TestCase):
                 url_query_cleaner("product.html?id=2&foo=bar&name=wired", ['id', 'foo'], remove=True))
         self.assertEqual('product.html?foo=bar&name=wired',
                 url_query_cleaner("product.html?id=2&foo=bar&name=wired", ['id', 'footo'], remove=True))
+        self.assertEqual('product.html',
+                url_query_cleaner("product.html", ['id'], remove=True))
+        self.assertEqual('product.html',
+                url_query_cleaner("product.html?&", ['id'], remove=True))
         self.assertEqual('product.html?foo=bar',
                 url_query_cleaner("product.html?foo=bar&name=wired", 'foo'))
         self.assertEqual('product.html?foobar=wired',

url_query_cleaner appends ? to urls without a query string
```python
>>> url_query_cleaner('http://domain.tld/', ['bla'], remove=True)
'http://domain.tld/?'
```

This is the code which does it: `url = '?'.join([base, sep.join(querylist)]) if querylist else base` (`querylist==['']`).
tests/test_url.py::UrlTests::test_url_query_cleaner
tests/test_url.py::UrlTests::test_any_to_uri tests/test_url.py::UrlTests::test_file_uri_to_path tests/test_url.py::UrlTests::test_is_url tests/test_url.py::UrlTests::test_path_to_file_uri tests/test_url.py::UrlTests::test_safe_download_url tests/test_url.py::UrlTests::test_safe_url_idna tests/test_url.py::UrlTests::test_safe_url_idna_encoding_failure tests/test_url.py::UrlTests::test_safe_url_port_number tests/test_url.py::UrlTests::test_safe_url_string tests/test_url.py::UrlTests::test_safe_url_string_bytes_input tests/test_url.py::UrlTests::test_safe_url_string_bytes_input_nonutf8 tests/test_url.py::UrlTests::test_safe_url_string_misc tests/test_url.py::UrlTests::test_safe_url_string_unsafe_chars tests/test_url.py::UrlTests::test_safe_url_string_with_query tests/test_url.py::UrlTests::test_url_query_cleaner_keep_fragments tests/test_url.py::UrlTests::test_url_query_parameter tests/test_url.py::UrlTests::test_url_query_parameter_2 tests/test_url.py::UrlTests::test_urljoin_rfc_deprecated tests/test_url.py::CanonicalizeUrlTest::test_append_missing_path tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_idns tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_parse_url tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url_idempotence tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url_idna_exceptions tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url_unicode_path tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url_unicode_query_string tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_url_unicode_query_string_wrong_encoding tests/test_url.py::CanonicalizeUrlTest::test_canonicalize_urlparsed tests/test_url.py::CanonicalizeUrlTest::test_domains_are_case_insensitive tests/test_url.py::CanonicalizeUrlTest::test_dont_convert_safe_characters tests/test_url.py::CanonicalizeUrlTest::test_keep_blank_values tests/test_url.py::CanonicalizeUrlTest::test_non_ascii_percent_encoding_in_paths tests/test_url.py::CanonicalizeUrlTest::test_non_ascii_percent_encoding_in_query_arguments tests/test_url.py::CanonicalizeUrlTest::test_normalize_percent_encoding_in_paths tests/test_url.py::CanonicalizeUrlTest::test_normalize_percent_encoding_in_query_arguments tests/test_url.py::CanonicalizeUrlTest::test_port_number tests/test_url.py::CanonicalizeUrlTest::test_quoted_slash_and_question_sign tests/test_url.py::CanonicalizeUrlTest::test_remove_fragments tests/test_url.py::CanonicalizeUrlTest::test_return_str tests/test_url.py::CanonicalizeUrlTest::test_safe_characters_unicode tests/test_url.py::CanonicalizeUrlTest::test_sorting tests/test_url.py::CanonicalizeUrlTest::test_spaces tests/test_url.py::CanonicalizeUrlTest::test_typical_usage tests/test_url.py::CanonicalizeUrlTest::test_urls_with_auth_and_ports tests/test_url.py::DataURITests::test_base64 tests/test_url.py::DataURITests::test_base64_spaces tests/test_url.py::DataURITests::test_bytes_uri tests/test_url.py::DataURITests::test_default_mediatype tests/test_url.py::DataURITests::test_default_mediatype_charset tests/test_url.py::DataURITests::test_mediatype_parameters tests/test_url.py::DataURITests::test_missing_comma tests/test_url.py::DataURITests::test_missing_scheme tests/test_url.py::DataURITests::test_scheme_case_insensitive tests/test_url.py::DataURITests::test_text_charset tests/test_url.py::DataURITests::test_text_uri tests/test_url.py::DataURITests::test_unicode_uri tests/test_url.py::DataURITests::test_wrong_base64_param tests/test_url.py::DataURITests::test_wrong_scheme