您的位置:首页 > 其它

动态vps搭建代理ip

2017-12-15 10:19 3659 查看


动态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, Response
from functools import wraps
import config

def 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端口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

config.py 配置文件如下
KEY='JustForCheck'         #对1的认证key,url后缀
NEED_AUTH=True             #对3开启认证
AUTH_USER='NoName'         #对3的用户名
AUTH_PASSWORD='NoPassword' #对3的密码
PORT=3128                  #1的代理端口
1
2
3
4
5

注意这里给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'
1
2
3
4
5
6
7
8
9
10

这里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'
1
2
3
4
5
6
7
8
9
10

都配置好后,通过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中.**





配置动态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
1
2
3

启动 
sudo service squid start


TinyProxy 
yum install tinyproxy
 安装 

/etc/tinyproxy/tinyproxy.conf
 修改
Port 8888 #预设是8888端口
Allow 127.0.0.1 #限制接入ip, 或者注释掉,不做限制
1
2

启动 
service tinyproxy start


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

关闭防火墙
systemctl stop firewalld
systemctl disable  firewalld
1
2

开启iptables, 开放对应对口(具体设置看官方文档), 

下面是一些开关指令,不行关了也行
systemctl stop iptables
systemctl start iptables
systemctl restart iptables
systemctl reload iptables
1
2
3
4

iptables -L -n -v
 通过iptables查看各状态 

-L 即 list ; 

-n 不进行ip、端口到域名的逆向解析; 

-v 可以查看详细信息。

如下图为关闭 



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

然后就是定时发送

以下通过python执行, 需要安装requets 

如果vps安装了python, 没安装pip, 可以试试通过如下安装pip,
yum install epel-release
yum install -y python-pip
1
2

如果为post,需要 

- 定时插拔 

- 先获取本地ip通过正则 

- 发送

以下通过commands执行插拔命令
import re
import commands
import requests
import time

SERVER_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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

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

改为
requests.get(SERVER_URL)` 

并删除对应的获取ip动作

然后执行代码

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


简单测试

通过模仿3get2的api
import requests
url = 'http://106.75.148.141:3954/'
proxy = requests.get(url, auth=('NoName', 'NoPassword')).text
print(proxy)
1
2
3
4

得到:



按照预定60秒插拔间隔后在请求一下,如果ip改变了,就说明,整套系统就在执行了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: