diff --git a/w3lib/url.py b/w3lib/url.py
index 5feddab..a41446c 100644
--- a/w3lib/url.py
+++ b/w3lib/url.py
@@ -538,6 +538,8 @@ def canonicalize_url(
     # UTF-8 can handle all Unicode characters,
     # so we should be covered regarding URL normalization,
     # if not for proper URL expected by remote website.
+    if isinstance(url, str):
+        url = url.strip()
     try:
         scheme, netloc, path, params, query, fragment = _safe_ParseResult(
             parse_url(url), encoding=encoding or "utf8"

diff --git a/tests/test_url.py b/tests/test_url.py
index c7079c6..9c70805 100644
--- a/tests/test_url.py
+++ b/tests/test_url.py
@@ -1085,6 +1085,17 @@ class CanonicalizeUrlTest(unittest.TestCase):
             "http://www.example.com/path/to/%23/foo/bar?url=http%3A%2F%2Fwww.example.com%2F%2Fpath%2Fto%2F%23%2Fbar%2Ffoo#frag",
         )
 
+    def test_strip_spaces(self):
+        self.assertEqual(
+            canonicalize_url(" https://example.com"), "https://example.com/"
+        )
+        self.assertEqual(
+            canonicalize_url("https://example.com "), "https://example.com/"
+        )
+        self.assertEqual(
+            canonicalize_url(" https://example.com "), "https://example.com/"
+        )
+
 
 class DataURITests(unittest.TestCase):
     def test_default_mediatype_charset(self):

`canonicalize_url` should not accept whitespace at the begin of an URI
Accepting whitespace in the begin of URI introduces a crawling issue. Unique URIs are generated on each depth and crawler gets in a loop. 

When a URI is extracted and begins with whitespace it is being considered a relative URI and its concatenated at the end of current URI, which leads to unique URI on each crawler depth. 

But, accordingly to RFC2396 [ Page 38], the scheme part of an URI should begin with an ALPHA character. 

> "The syntax for URI scheme has been changed to require that all schemes begin with an alpha character." 

After further investigation, the core python `urlparse` function doesn't follow RFC strictly, they consider some rules. Like on Python 3.5 they say: 

> "Changed in version 3.3: The fragment is now parsed for all URL schemes (unless allow_fragment is false), in accordance with RFC 3986. Previously, a whitelist of schemes that support fragments existed." 

However a better implementation should be in accordance with RFC 3986 (which is an update of RFC2396 mentioned before), the `urlparse` should not accept whitespace at the begin of URI. 

When compared to the with Ruby implementation of RFC 2396,  they don't allow whitespace at the begin of absolute or relative URIs and throws an exception "bad URI(is not URI?)".

In order to fix that on Scrapy level, I suggest the following. 

In `scrapy/utils/url.py` add at the begin of `canonicalize_url`:

```
if re.match('[a-zA-Z]', url[:1]) == None:
    raise ValueError('Bad URI (is not a valid URI?)')
```

An a test in `tests/test_utils_url.py`:

```
def test_rfc2396_scheme_should_begin_with_alpha(self):
    self.assertRaises(ValueError, canonicalize_url," http://www.example.com")
```

But raising an exception breaks a lot of tests and can introduce unexpected behaviors. You could simple `.strip()` url, but won't make it RFC compliant. 

tests/test_url.py::CanonicalizeUrlTest::test_strip_spaces
tests/test_url.py::UrlTests::test_add_or_replace_parameter tests/test_url.py::UrlTests::test_add_or_replace_parameters tests/test_url.py::UrlTests::test_add_or_replace_parameters_does_not_change_input_param 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_encode_idna_domain_with_port tests/test_url.py::UrlTests::test_safe_url_string_encode_idna_domain_with_username_and_empty_password_and_port_number tests/test_url.py::UrlTests::test_safe_url_string_encode_idna_domain_with_username_password_and_port_number tests/test_url.py::UrlTests::test_safe_url_string_misc tests/test_url.py::UrlTests::test_safe_url_string_preserve_nonfragment_hash tests/test_url.py::UrlTests::test_safe_url_string_quote_path tests/test_url.py::UrlTests::test_safe_url_string_remove_ascii_tab_and_newlines tests/test_url.py::UrlTests::test_safe_url_string_unsafe_chars tests/test_url.py::UrlTests::test_safe_url_string_user_and_pass_percentage_encoded tests/test_url.py::UrlTests::test_safe_url_string_userinfo_unsafe_chars tests/test_url.py::UrlTests::test_safe_url_string_with_query tests/test_url.py::UrlTests::test_url_query_cleaner 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::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_preserve_nonfragment_hash 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