在使用爬虫进行数据抓取时候,会遇到很多反爬虫措施,封IP是常见的一种反扒措施,但是这种反扒措施是很古老的方式,对于运维人员来说当时看起来是比较有效的一种方式,但是一般的大量抓取都会携带使用代理ip 去请求,也就是ip 池
1 购买市面上的一些 API 接口,每次返回多少ip,在爬虫程序种接入使用(买代理)
2 自己抓取一些免费的代理,去放到Redis 里面维护起来,定时进行筛选,过滤过期的IP
这两种方式都可以实现使用代理请求目标网站,但是使用过的朋友应知道这两种方式获取的ip 质量非常差,尤其是第二种,可以说根本没法用,除非你是自己玩玩,如果是企业级别或者是对数据质量要求较高,或许第一种方式可以尝试,但还是不稳定
VPS是什么? 我们平常使用ECS服务器,vps是低配版的ECS,vps 比ecs便宜
VPS(Virtual Private Server 虚拟专用服务器)技术,将一台服务器分割成多个虚拟专享服务器的优质服务。实现VPS的技术分为容器技术,和虚拟化技术 。在容器或虚拟机中,每个VPS都可分配独立公网IP地址、独立操作系统、实现不同VPS间磁盘空间、内存、CPU资源、进程和系统配置的隔离,为用户和应用程序模拟出“独占”使用计算资源的体验。VPS可以像独立服务器一样,重装操作系统,安装程序,单独重启服务器
ADSL (Asymmetric Digital Subscriber Line ,非对称数字用户环路)是一种新的数据传输方式。它因为上行和下行带宽不对称,因此称为非对称数字用户线环路。它采用频分复用技术把普通的电话线分成了电话、上行和下行三个相对独立的信道,从而避免了相互之间的干扰。
也就是你每拨一次号就换一次IP。
我买的是XX的VPS服务器,这种拨号服务器有很多,但一定要注意可靠。不推荐某家,都差不多,大家自己筛选就好。大多平均一个月100左右
我们可以在某平台购买一台一天使用时间低配vps测试使用(要开通拨号上网功能)
安装(前提是已经安装好pyhon3) Centos安装Python3
以CentOS上TinyProxy为例:
安装
yum install -y epel-release
yum update -y
yum install -y tinyproxy
配置
vi /etc/tinyproxy/tinyproxy.conf
取消注释
Allow 127.0.0.1
启动
systemctl enable tinyproxy.service
systemctl restart tinyproxy.service
开启
adls-start
既可拨号成功,如果要断掉,则
adls-stop
所以断线重播的命令就是二者组合起来,先执行adsl-stop再执行adsl-start,每拨一次号,ifocnfig命令观察一下主机的IP,发现主机的IP一直是在变化的,网卡名称叫做ppp0。
这样我们就得到了一个新的获取ip的方式,如果我们要在爬虫代码中使用这个IP作为代理ip,需获取这个ip 并验证可用性并保存到数据库直至获取一个新的ip 为止
def get_ip(self, ifname='ppp0'):
"""
获取本机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:
proxies = {"http": "http://" + proxy}
response = requests.get("http://www.baidu.com", proxies=proxies)
if response.status_code == 200:
return True
except (ConnectionError, ReadTimeout):
return False
将代理放到Redis
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)
Redis
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)
主进程
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()
print(ip, '正则匹配到的ip')
if ip:
print('Now IP', ip)
print('Testing Proxy, Please Wait')
proxy = '{ip}:{port}'.format(ip=ip, port=PROXY_PORT)
print('组装好的代理ip-port', proxy)
if self.test_proxy(proxy):
print('Valid Proxy')
self.set_proxy(proxy)
print('Sleeping', ADSL_CYCLE)
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)