一 什么是ADSL
ADSL:非对称数字用户环路,它的上行和下行带宽不对称,它采用频分复用技术把普通的电话线分成了电话、上行和下行3个相对独立的信道,从而避免了相互之间的干扰。
ADSL通过拨号的方式上网,需要输入ADSL账号和密码,每次拨号就更换一个IP。IP分布在多个A段,如果IP都能使用,则意味着IP量级和达千万。如果我们将ADSL主机作为代理。每隔一段时间主机拨号就换一个IP,这样可以有效防止IP被封禁。另外,主机的稳定性很好,代理响应速度很快。
二 准备工作
成功安装Redis数据库,另外还需要安装下面软件。
'requests>=2.13.0', 'tornado>=4.4.3', 'redis>=2.10.5'
三 购买动态拨号主机
1 可到云立方购买:https://www.yunlifang.cn/dynamicvps.asp
2 购买后推荐安装CentOS 7操作系统。
3 通过远程管理面板连接VPS主机
4 运行ppp.sh脚本进行配置
5 拨号的两条命令
adsl-start
adsl-stop
6 不停的启动关闭,并执行命令ifconfig,会发现IP在不停的变化
四 安装代理服务器
以CentOS上TinyProxy为例进行安装:
1 安装
yum install -y epel-release
yum update -y
yum install -y tinyproxy
2 配置
vi /etc/tinyproxy/tinyproxy.conf
取消注释
Allow 127.0.0.1
3 启动
systemctl enable tinyproxy.service
systemctl restart tinyproxy.service
4 防火墙
如不能访问可能是防火墙问题,可以放行端口
iptables -I INPUT -p tcp --dport 8888 -j ACCEPT
或直接关闭防火墙
systemctl stop firewalld.service
5 测试
curl -x 192.168.0.110:8888 httpbin.org/get
五 动态获取IP
多配置一些拨号主机,因为存在主机拨号切换IP的间歇代理不可用问题,所以可以将可用的代理信息存到一个Redis数据库,并把不用的信息删除。
六 存储模块
各个拨号机器只需要将各自的主机标识和当前IP和端口发送给数据库就好了。
# coding=utf-8
import redis
import random
from adslproxy.config import *
class RedisClient(object):
def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, proxy_key=PROXY_KEY):
"""
初始化Redis连接
:param host: Redis 地址
:param port: Redis 端口
:param password: Redis 密码
:param proxy_key: Redis 哈希表名
"""
self.db = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True)
self.proxy_key = proxy_key
def set(self, name, proxy):
"""
设置代理
:param name: 主机名称
:param proxy: 代理
:return: 设置结果
"""
return self.db.hset(self.proxy_key, name, proxy)
def get(self, name):
"""
获取代理
:param name: 主机名称
:return: 代理
"""
return self.db.hget(self.proxy_key, name)
def count(self):
"""
获取代理总数
:return: 代理总数
"""
return self.db.hlen(self.proxy_key)
def remove(self, name):
"""
删除代理
:param name: 主机名称
:return: 删除结果
"""
return self.db.hdel(self.proxy_key, name)
def names(self):
"""
获取主机名称列表
:return: 获取主机名称列表
"""
return self.db.hkeys(self.proxy_key)
def proxies(self):
"""
获取代理列表
:return: 代理列表
"""
return self.db.hvals(self.proxy_key)
def random(self):
"""
随机获取代理
:return:
"""
proxies = self.proxies()
return random.choice(proxies)
def all(self):
"""
获取字典
:return:
"""
return self.db.hgetall(self.proxy_key)
七 拨号模块
# coding=utf-8
import re
import time
import requests
from requests.exceptions import ConnectionError, ReadTimeout
from adslproxy.db import RedisClient
from adslproxy.config import *
import platform
if platform.python_version().startswith('2.'):
import commands as subprocess
elif platform.python_version().startswith('3.'):
import subprocess
else:
raise ValueError('python version must be 2 or 3')
class Sender():
def get_ip(self, ifname=ADSL_IFNAME):
"""
获取本机IP
:param ifname: 网卡名称
:return:
"""
(status, output) = subprocess.getstatusoutput('ifconfig')
if status == 0:
pattern = re.compile(ifname + '.*?inet.*?(\d+\.\d+\.\d+\.\d+).*?netmask', re.S)
result = re.search(pattern, output)
if result:
ip = result.group(1)
return ip
def test_proxy(self, proxy):
"""
测试代理
:param proxy: 代理
:return: 测试结果
"""
try:
response = requests.get(TEST_URL, proxies={
'http': 'http://' + proxy,
'https': 'https://' + proxy
}, timeout=TEST_TIMEOUT)
if response.status_code == 200:
return True
except (ConnectionError, ReadTimeout):
return False
def remove_proxy(self):
"""
移除代理
:return: None
"""
self.redis = RedisClient()
self.redis.remove(CLIENT_NAME)
print('Successfully Removed Proxy')
def set_proxy(self, proxy):
"""
设置代理
:param proxy: 代理
:return: None
"""
self.redis = RedisClient()
if self.redis.set(CLIENT_NAME, proxy):
print('Successfully Set Proxy', proxy)
def adsl(self):
"""
拨号主进程
:return: None
"""
while True:
print('ADSL Start, Remove Proxy, Please wait')
self.remove_proxy()
(status, output) = subprocess.getstatusoutput(ADSL_BASH)
if status == 0:
print('ADSL Successfully')
ip = self.get_ip()
if ip:
print('Now IP', ip)
print('Testing Proxy, Please Wait')
proxy = '{ip}:{port}'.format(ip=ip, port=PROXY_PORT)
if self.test_proxy(proxy):
print('Valid Proxy')
self.set_proxy(proxy)
print('Sleeping')
time.sleep(ADSL_CYCLE)
else:
print('Invalid Proxy')
else:
print('Get IP Failed, Re Dialing')
time.sleep(ADSL_ERROR_CYCLE)
else:
print('ADSL Failed, Please Check')
time.sleep(ADSL_ERROR_CYCLE)
def run():
sender = Sender()
sender.adsl()
if __name__ == '__main__':
run()
八 接口模块
# coding=utf-8
import json
import tornado.ioloop
import tornado.web
from tornado.web import RequestHandler, Application
from adslproxy.config import *
class MainHandler(RequestHandler):
def initialize(self, redis):
self.redis = redis
def get(self, api=''):
if not api:
links = ['random', 'proxies', 'names', 'all', 'count']
self.write('<h4>Welcome to ADSL Proxy API</h4>')
for link in links:
self.write('<a href=' + link + '>' + link + '</a>
')
if api == 'random':
result = self.redis.random()
if result:
self.write(result)
if api == 'names':
result = self.redis.names()
if result:
self.write(json.dumps(result))
if api == 'proxies':
result = self.redis.proxies()
if result:
self.write(json.dumps(result))
if api == 'all':
result = self.redis.all()
if result:
self.write(json.dumps(result))
if api == 'count':
self.write(str(self.redis.count()))
def server(redis, port=API_PORT, address=''):
application = Application([
(r'/', MainHandler, dict(redis=redis)),
(r'/(.*)', MainHandler, dict(redis=redis)),
])
application.listen(port, address=address)
print('ADSL API Listening on', port)
tornado.ioloop.IOLoop.instance().start()