|
|
|
import requests, random, socket
|
|
|
|
|
|
|
|
# These are just some random useragents, you can replace these with a different list
|
|
|
|
user_agents = [
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
|
|
|
|
"Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20100101 Firefox/21.0",
|
|
|
|
"Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0",
|
|
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1",
|
|
|
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36"
|
|
|
|
]
|
|
|
|
|
|
|
|
class NotFoundException(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class DownloadException(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Very nasty monkeypatching ahead!
|
|
|
|
socket.real_create_connection = socket.create_connection
|
|
|
|
|
|
|
|
class ModifiedSession(requests.Session):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
try:
|
|
|
|
self.bound_ip = kwargs['bound_ip']
|
|
|
|
del kwargs['bound_ip']
|
|
|
|
except KeyError, e:
|
|
|
|
self.bound_ip = ""
|
|
|
|
|
|
|
|
requests.Session.__init__(self, *args, **kwargs)
|
|
|
|
self.headers['User-Agent'] = random.choice(user_agents)
|
|
|
|
|
|
|
|
def patch_socket(self):
|
|
|
|
socket.create_connection = get_patched_func(self.bound_ip)
|
|
|
|
|
|
|
|
def unpatch_socket(self):
|
|
|
|
socket.create_connection = socket.real_create_connection
|
|
|
|
|
|
|
|
def get(self, *args, **kwargs):
|
|
|
|
self.patch_socket()
|
|
|
|
response = requests.Session.get(self, *args, **kwargs)
|
|
|
|
self.unpatch_socket()
|
|
|
|
return response
|
|
|
|
|
|
|
|
def post(self, *args, **kwargs):
|
|
|
|
self.patch_socket()
|
|
|
|
response = requests.Session.post(self, *args, **kwargs)
|
|
|
|
self.unpatch_socket()
|
|
|
|
return response
|
|
|
|
|
|
|
|
def get_patched_func(bind_addr):
|
|
|
|
def set_src_addr(*args):
|
|
|
|
address, timeout = args[0], args[1]
|
|
|
|
source_address = (bind_addr, 0)
|
|
|
|
return socket.real_create_connection(address, timeout, source_address)
|
|
|
|
return set_src_addr
|
|
|
|
|
|
|
|
# You're looking at duct tape and tie-wraps. It's like your local Home
|
|
|
|
# Depot, except in Python.
|
|
|
|
|
|
|
|
def download_file(request, target):
|
|
|
|
if request.status_code == 200:
|
|
|
|
f = open(target, "wb")
|
|
|
|
|
|
|
|
for chunk in request.iter_content():
|
|
|
|
f.write(chunk)
|
|
|
|
|
|
|
|
f.close()
|
|
|
|
else:
|
|
|
|
raise DownloadException("Status code was %s" % request.status_code)
|