开始前的准备
注:在开始完成这个项目之前,需要懂一些简单的爬虫知识和tkinter的界面相关知识,不过这些相关的内容,博主也会通过链接的方式,在其他文章内对其进行详细描述,手把手教你完成一个IP代理池。
第一步:IP代理池的功能实现
框架
一个IP代理池主要需要IP的获取以及IP的检测两大功能,以及一个方便的取用方式
获取:主要通过爬虫来获取大量的免费IP代理
检测:可以通过ping的方式,来对IP的可用性进行检测
取用:可以通过构建一个异步的web服务,以此能够用API的方式,极为方便的取用IP
因此我们可以先获得一个大概的代码框架:
class IP代理池(object):
'''
IP代理池
用于获取代理IP以及维护代理IP池
'''
def __init__(self):
pass
def 代理爬取(self,num):
pass
def 代理检测(self):
pass
def 代理取用(self):
pass
if __name__ == '__main__':
IPAP = IP代理池()
IP的爬取
我们可以通过爬虫,来获取网上的一些代理。
这里我们仅主要介绍爬取一个网站,其余的大家可以自己去寻找并获取,以丰富自己的IP代理来源。
在代码的框架上进行修改,得到:
import time
import httpx
from lxml import etree
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}
class IP代理池(object):
'''
IP代理池
'''
def __init__(self):
self.IPPool = []
self.快代理链接 = "https://www.kuaidaili.com/free/"
def 代理爬取(self,num):
for i in range(1,num):
url = self.快代理链接+"inha/"+str(i)
res = httpx.get(url, headers=headers)
if(res.status_code == 200):
con = etree.HTML(res.text)
ip_list = con.xpath('//*[@id="list"]/table/tbody/tr/td/text()')
for i in range(len(ip_list)//8):
self.IPPool.append({"IP":ip_list[i*8+0],"Port":ip_list[i*8+1],"匿名度":ip_list[i*8+2],"类型":ip_list[i*8+3]})
print(self.IPPool)
time.sleep(1)
def 代理检测(self):
pass
def 代理取用(self):
pass
if __name__ == '__main__':
IPAP = IP代理池()
IPAP.代理爬取(2)
IP的检测
以下代码添加了IP的可用性检测模块,通过获取百度首页的方式,来判断代理是否可用,并筛选出反应速度在0.3s以上的代理,写入csv文件中
import time,os,csv
import httpx
from lxml import etree
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}
class IP代理池(object):
'''
IP代理池
'''
def __init__(self):
self.IP池 = []
self.可用IP = []
self.快代理链接 = "https://www.kuaidaili.com/free/"
# 如果存在IP代理池文件,则进行读取
if(os.path.exists("IPPool.csv")):
# 读取相关文档
with open("IPPool.csv",'r') as csv_f:
reader = csv.DictReader(csv_f)
for cvs_row in reader:
self.IP池.append({'IP':cvs_row['IP'],'Port':cvs_row['Port'],'匿名度':cvs_row['匿名度'],'类型':cvs_row['类型']})
def 代理爬取(self,num):
for i in range(1,num+1):
url = self.快代理链接+"inha/"+str(i)
res = httpx.get(url, headers=headers)
if(res.status_code == 200):
con = etree.HTML(res.text)
ip_list = con.xpath('//*[@id="list"]/table/tbody/tr/td/text()')
for i in range(len(ip_list)//8):
ipcon = {"IP":ip_list[i*8+0],"Port":ip_list[i*8+1],"匿名度":ip_list[i*8+2],"类型":ip_list[i*8+3]}
if(not ipcon in self.IP池):
self.IP池.append(ipcon)
print("添加IP代理:"+ipcon["IP"]+":"+ipcon["Port"])
else:
print("IP代理:"+ipcon["IP"]+":"+ipcon["Port"]+"已存在")
time.sleep(1)
def 代理检测(self):
for each in self.IP池:
proxies = {each["类型"]+"://":each["类型"]+"://"+each["IP"]+":"+each["Port"]}
res = httpx.get("https://www.baidu.com/", headers=headers, proxies=proxies, timeout=0.3)
if(res.status_code == 200):
if(not each in self.可用IP):
self.可用IP.append(each)
print("IP代理:"+each["IP"]+":"+each["Port"]+"可使用")
else:
print("IP代理:"+each["IP"]+":"+each["Port"]+"已存在")
else:
print("IP代理:"+each["IP"]+":"+each["Port"]+"无效")
with open("IPPool.csv",'w',newline='') as csv_f:
write=csv.writer(csv_f)
# 写入头
row=['IP','Port','匿名度','类型']
write.writerow(row)
for each in self.可用IP:
# 写入数据
row=[each["IP"],each["Port"],each["匿名度"],each["类型"]]
write.writerow(row)
print("代理IP写入完毕!")
def 代理取用(self):
pass
if __name__ == '__main__':
IPAP = IP代理池()
index = input('1.爬取代理\n2.检测代理\n3.取用代理\n请选择:')
while(True):
if(index == '1'):
IPAP.代理爬取(2)
IPAP.代理检测()
elif(index == '2'):
IPAP.代理检测()
elif(index == '3'):
IPAP.代理取用()
IP的取用
IP的取用部分本来也是想要封装在类里的,但是Sanic似乎必须运行在主线程,暂时一下子没有找到什么解决方法,能力有限,也就先这样用了。
主要是希望能够通过API的方式进行调用,获取IP,当前是通过get的方式,来随机获取IP,后续也可以进行进一步优化,通过post请求,按照指定方式来获取指定数量的IP。
import time,os,csv,random
import httpx
from sanic import Sanic
from lxml import etree
import threading
from sanic.response import json
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}
class IP代理池(object):
'''
IP代理池
'''
def __init__(self):
self.IP池 = []
self.可用IP = []
self.快代理链接 = "https://www.kuaidaili.com/free/"
# 如果存在IP代理池文件,则进行读取
if(os.path.exists("IPPool.csv")):
# 读取相关文档
with open("IPPool.csv",'r') as csv_f:
reader = csv.DictReader(csv_f)
for cvs_row in reader:
self.IP池.append({'IP':cvs_row['IP'],'Port':cvs_row['Port'],'匿名度':cvs_row['匿名度'],'类型':cvs_row['类型']})
def 代理爬取(self,num):
for i in range(num):
url = self.快代理链接+"inha/"+str(i+1)
try:
res = httpx.get(url, headers=headers)
except:
print("爬取超时")
time.sleep(1)
if(res.status_code == 200):
con = etree.HTML(res.text)
ip_list = con.xpath('//*[@id="list"]/table/tbody/tr/td/text()')
for i in range(len(ip_list)//8):
ipcon = {"IP":ip_list[i*8+0],"Port":ip_list[i*8+1],"匿名度":ip_list[i*8+2],"类型":ip_list[i*8+3]}
if(not (ipcon in self.IP池)):
self.IP池.append(ipcon)
print("添加IP代理:"+ipcon["IP"]+":"+ipcon["Port"])
else:
print("IP代理:"+ipcon["IP"]+":"+ipcon["Port"]+"已存在")
def 代理检测(self):
for each in self.IP池:
proxies = {each["类型"]+"://":each["类型"]+"://"+each["IP"]+":"+each["Port"]}
try:
res = httpx.get("https://www.baidu.com/", headers=headers, proxies=proxies, timeout=0.3)
except:
print("检测超时,检测未通过")
if(res.status_code == 200):
if(not each in self.可用IP):
self.可用IP.append(each)
print("IP代理:"+each["IP"]+":"+each["Port"]+"可使用")
else:
print("IP代理:"+each["IP"]+":"+each["Port"]+"已存在")
else:
print("IP代理:"+each["IP"]+":"+each["Port"]+"无效")
with open("IPPool.csv",'w',newline='') as csv_f:
write=csv.writer(csv_f)
# 写入头
row=['IP','Port','匿名度','类型']
write.writerow(row)
for each in self.可用IP:
# 写入数据
row=[each["IP"],each["Port"],each["匿名度"],each["类型"]]
write.writerow(row)
print("代理IP写入完毕!")
IPAP = IP代理池()
app = Sanic("IPPoll")
@app.route("/")
async def IP代理取用(request):
num = random.randint(0,len(IPAP.IP池)-1)
return json({
'IP': IPAP.IP池[num]['IP'],
'Port': IPAP.IP池[num]['Port'],
'Type': IPAP.IP池[num]['类型']
})
def IP爬取():
index = input('1.爬取代理\n2.检测代理\n请选择:\n')
while(True):
if(index == '1'):
IPAP.代理爬取(50)
IPAP.代理检测()
elif(index == '2'):
IPAP.代理检测()
if __name__ == '__main__':
threading.Thread(target=IP爬取).start()
app.run(host="localhost", port=8000)
使用方式:
直接访问 “http://localhost:8000/” 即可。
这样一来,整个的基本盘也就完成了,后续当然还可以进行很多的优化,这些就交给大家自己去尝试了。
如:
IP获取的各种方式
IP爬取的速度
代理IP获取的来源
定时的IP获取
或者如果需要UI界面的话,也可以进行添加
等等等等……
最后:千万记得,点赞,关注,收藏哦~
有什么其他的问题也可以在评论区询问,作者后面有时间也会把优化完的IP代理池也发一下,一切以使用更方便为目的。