动态vps搭建代理ip

来源:互联网 发布:python http api接口 编辑:程序博客网 时间:2024/05/22 11:29

动态VPS

通过ADSL上网的方式,执行主动拨号的命令后才能接入网络,停止拨号的命令下线. 一上一下本地外网ip就会改变, 具体就是你拨号上网时运营商会根据你的地区分配一个可用的ip给你. 下线时,收回你的IP.
这个短时间内改变ip的特性非常适合给爬虫提供代理池,或者其他业务.
网上常见的动态vps提供商页面指标通常如下:
这里写图片描述
提供不同地区,不同号段,以及带宽(一般4M,10M,20M) 和其他常见硬件指标, 默认低配大约80元每月.

这应该也是网上常见的动态ip代理提供商的主要来源之一.

如何搭建代理

简介

如果我们要具体利用这个特性,原理如下,可按需求随意更改:

         动态VPS 1      定时上下,开通代理  把代理地址和端口发送到固定外网IP的服务器上            ↓      固定IP的服务器 2接收,保存信息,并通过API提供信息            ↑     运行业务的服务器 3  通过API请求获取代理信息,

然后使用动态VPS的代理进行业务(比如爬虫)

1: 动态vps 生成代理
2: 固定IP服务器 粘合剂,接收1的代理信息, 对3提供代理信息
3: 使用代理的机器

之所以要固定ip服务器, 因为动态vps需要主动把代理信息发送给我们,我们很难主动去查询到它的代理信息,因为它的外网ip一直在变.
所以我们需要一台有固定独立IP的机器来接受信息.

至于能不能简化,如果跑爬虫的机器有固定IP,理论上也可以直接接受代理信息.
不过如果动态vps数量增加,爬虫也是分布式多机器的话,一台服务器拿来当接收方并提供API就容易管理了.
本篇重点是动态vps和固定ip服务器之间的搭建.

============================================================

先配置固定IP服务器

目的是:

  • 提供api,让1和3可以上传和接收信息,
  • 保存信息,方式可以是txt存取,或者redis,信息量只有 0.0.0.0:89 这么大
  • 对1和3提供一定的认证

使用python的flask来快速搭建api

3对于2的请求是get, 那么就需要提供一个get请求的api并提供认证.

main.py 如下

from flask import request, Flask, Responsefrom functools import wrapsimport configdef requires_auth(f):         #认证    @wraps(f)    def decorated(*args, **kwargs):        auth = request.authorization        if not auth or not check_auth(auth.username, auth.password): #认证用户名,密码            return authenticate()        return f(*args, **kwargs)    return decorated@app.route('/', methods=['GET'])  #api请求方式的为get@requires_auth      def proxy():    with open('ip', 'r') as f:  #打开保存代理信息的ip文件        ip = f.read().strip()        f.close()        if ip:            return ip + ':' + str(config.PORT)  #把ip地址和端口拼接在一起发送    return '0'if __name__ == '__main__':    app.run(host='0.0.0.0', port=3954) #2自己的api端口

config.py 配置文件如下

KEY='JustForCheck'         #对1的认证key,url后缀NEED_AUTH=True             #对3开启认证AUTH_USER='NoName'         #对3的用户名AUTH_PASSWORD='NoPassword' #对3的密码PORT=3128                  #1的代理端口

注意这里给3返回的是 ip + config.port 的形式, port是一个定值而不是从1获取得到的.
是因为要使用的1的代理端口是固定的,每次变得是ip地址, 所以2从1接收的只有ip地址.
1要开放的代理端口必须是设定好的,不能随它的ip一起改变.

2对于1之间可以是get请求或者post请求,需根据1的情况判断

两者之间要根据1的实际情况来配置,后面讲到1会说如何判断.

get 请求是,1通过get直接request一下2, 然后2通过1的请求地址得到1的外网ip,
1不需要主要向2传任何信息,类似于1简单ping一下2,2提取1的访问地址就行

@app.route('/record/<key>', methods=['GET'])def record(key):                      #验证url后缀    if key == config.KEY:        ip = request.remote_addr      #直接提取1的访问ip        with open('ip', 'w') as f:    #保存为一个叫IP的文件中            f.write(ip)            f.close()        return ip + '\n'              #给1随便返回一个值,这里是ip信息    else:        return 'Invalid Key'

这里2对于1的验证本质是纯粹的url, 类似于
get一个 http://105.35.108.111:3954/record/JustForCheck
后面的/JustForCheck当成验证key,在config,后缀对了就可以get, 本质就是一个长一点的url地址

post 请求需要1主动上传IP信息, 而2接收这个post即可
之所以会有get和post两种形式,是因为

@app.route('/record/<key>', methods=['POST'])def record(key):    if key == config.KEY:        ip = request.form['value']        #打开post信息中(字典形式)的键名为value的值        with open('ip', 'w') as f:            f.write(ip)            f.close()        return ip + '\n'    else:        return 'Invalid Key'

都配置好后,通过nohup一直执行 &为后台执行
nohup python main.py &

**1的代理ip可能是访问外网的那个外网ip, 比如 curl icanhazip.com后得到 192.12.1.1, 那么这个ip就是我们需要的代理ip,
也就是1get一下2后,2所获取的那个ip.假设1的端口代理都搭建好了,我们在Linux下测试代理 curl -x 192.12.1.1:3128 www.baidu.com
正确会返回一堆值,可能是乱码,不要紧,说明可以通过代理上网, 那么这个就是需要的ip,也就是通过get方式即可.

但是,我在调试了1整天后,都不行,使用那个代理的ip怎么都是timeout,没有反应. 最后通过另一篇文章注意到,
这个代理实际在ifconfig命令后的ppp0中, 而这个跟那个访问外网的ip不一样.所以我们要在1中提取,再post到2中.**

------------------------------------------------0002

配置动态vps,

目的如下,
- 开放代理端口
- 定时拨号,拔号,
- 发送数据

系统这里选择CentOS, 一般服务商的控制面板里会告诉你上网指定:
比如,拨号的用户名密码都已经写好在脚本里,直接运行即可:
开始拨号 pppoe-start
停止拨号 pppoe-stop
查看拨号状态 pppoe-status

开放代理端口

使用Squid或者TinyProxy

Squid
yum -y install squid 安装
chkconfig --level 35 squid on 开机启动
/etc/squid/squid.conf配置文件下,修改一下设定从deny改成allow,主要是开启外部访问
默认端口是3218

http_access allow !Safe_ports        http_access allow CONNECT !SSL_ports  http_access allow all               

启动
sudo service squid start

TinyProxy
yum install tinyproxy 安装
/etc/tinyproxy/tinyproxy.conf 修改

Port 8888 #预设是8888端口Allow 127.0.0.1 #限制接入ip, 或者注释掉,不做限制

启动
service tinyproxy start

然后要在系统防火墙设置开放或者关闭
关闭防火墙

systemctl stop firewalldsystemctl disable  firewalld

开启iptables, 开放对应对口(具体设置看官方文档),
下面是一些开关指令,不行关了也行

systemctl stop iptables  systemctl start iptables  systemctl restart iptables  systemctl reload iptables

iptables -L -n -v 通过iptables查看各状态
-L 即 list ;
-n 不进行ip、端口到域名的逆向解析;
-v 可以查看详细信息。

如下图为关闭
0003---------------------------------------------------

到现在为止,端口已经开放,通过之前的方式来判断本机提供的代理IP具体是哪一个.
然后就是定时发送

以下通过python执行, 需要安装requets
如果vps安装了python, 没安装pip, 可以试试通过如下安装pip,

yum install epel-releaseyum install -y python-pip

如果为post,需要
- 定时插拔
- 先获取本地ip通过正则
- 发送

以下通过commands执行插拔命令

import reimport commandsimport requestsimport timeSERVER_URL = 'http://106.75.148.141:3954/record/JustForCheck'   #2的地址ADSL_CYCLE = 60       #插拔间隔class Main(object):   #通过正则获取本地ip    @classmethod    def _get_ip(self):        status, output = commands.getstatusoutput('ifconfig')        if status == 0:            result = re.search(                '1492\s+?inet\s+?(\d+\.\d+\.\d+\.\d+)\s+?netmask', output)            if result:                return result.group(1)    @classmethod      #发送ip    def _send_ip(self, ip):        try:            requests.post(SERVER_URL, data={'value': ip})        except Exception as e:            print e    @classmethod    def restart_adsl(self):     #把几个动作连起来按频率执行        while 1:            print '重新拨号开始'            status, output = commands.getstatusoutput('pppoe-stop; pppoe-start')    #插拔命令            if status == 0:                print '拨号成功'                ip = self._get_ip()                if ip:                    print '新ip获取成功: %s' % ip                    self._send_ip(ip)                    print '发送成功'                    print '距离下一池插拔 %s 秒' % ADSL_CYCLE                    time.sleep(ADSL_CYCLE)                else:                    print '没能获取本地ip'            else:                print '没能拨号成功'            time.sleep(1)if __name__ == '__main__':    print Main.restart_adsl()

如果是get方式的话,就不需要提取本地ip,只需要插拔后直接通过request进行get就行.
requests.post(SERVER_URL, data={'value': ip})``
改为
requests.get(SERVER_URL)`
并删除对应的获取ip动作

然后执行代码

这样1的任务,插拔,发送就完成了.

简单测试

通过模仿3get2的api

import requestsurl = 'http://106.75.148.141:3954/'proxy = requests.get(url, auth=('NoName', 'NoPassword')).textprint(proxy)

得到:

0004-----------------------

按照预定60秒插拔间隔后在请求一下,如果ip改变了,就说明,整套系统就在执行了.

基本都是参考下面的:
Python爬虫进阶七之设置ADSL拨号服务器代理 http://cuiqingcai.com/3443.html
搭建代理服务器-ADSL拨号(客户端)http://www.tuox.vip/2017/06/13/adsl-client/