If you have to use a SOCKS5 proxy, here's the solution:
import socks
import socket
import urllib.request
proxy_ip = "127.0.0.1"
proxy_port = 1080
socks.set_default_proxy(socks.PROXY_TYPE_SOCKS5, proxy_ip, proxy_port)
socket.socket = socks.socksocket
url = 'https://example.com/foo/bar.jpg'
urllib.request.urlretrieve(url, 'bar.png')
More Info:
This works very well, but if we want to use ProxyHandler, for some reason it errors for SOCKS proxies, even though it should support it.
proxy = urllib.request.ProxyHandler({'socks': 'socks://127.0.0.1:1080'})
opener = urllib.request.build_opener(proxy)
urllib.request.install_opener(opener)
urllib.request.urlretrieve(url, 'bar.png')
class urllib.request.ProxyHandler(proxies=None)
Cause requests to go
through a proxy. If proxies is given, it must be a dictionary mapping
protocol names to URLs of proxies. The default is to read the list of
proxies from the environment variables _proxy. If no proxy
environment variables are set, then in a Windows environment proxy
settings are obtained from the registry’s Internet Settings section,
and in a macOS environment proxy information is retrieved from the
System Configuration Framework.
When a SOCKS5 proxy is globally set on my Windows OS, I get this:
>>> urllib.request.getproxies()
{'socks': 'socks://127.0.0.1:1080'}
But it still fails.