前言
用来采集IP的网址
免费IP的是最拉跨的,要买的话推荐是买它家的隧道代理
一、认识代理
当你访问网站过于频繁的时候,可能会触发反爬机制然后你的IP就被封了,访问不了网站了,怎么办?
换IP而且控制访问频率
import requests
UA = {
"User-Agent":"*****"
url ="*****"
dict ={
"http":"http://120.234.203.171:9002", #ip:端口 => 120.234.203.171:9002
"https":"https://120.234.203.171:9002"
}
#代理ip使用注意: 需要根据你要访问的网址来确定代理ip能否访问 如果你的网址为https 而代理只支持http代码可能会报错
#代理需要知道其组成为 ip:端口
# resp = requests.get(url,headers = UA) #未使用代理ip
resp =requests.get(url,proxies = dict,headers = UA) #使用代理
#代理属于灰色产业 可以溯源 一般免费的都不好用卡的死
resp.encoding = 'utf-8'
print(resp.text)
二、我需要很多IP怎么办?
弄一个代理IP池,思路是从很多提供(多个)免费代理的网站上提取免费IP存到你的数据库(去重)里,然后筛选处好用的IP供自己使用。
数据库选择:Redis 数据结构:zset (有序集合)
思路:多进程+爬取ip+验证Ip+提供ip+模块化编程
python 模块化编程知识:
比如两个py文件test1,test2。
可以在test2中import test1进行模块导入,导入时会为test1开辟内存空间,并且在该内存空间中执行test1文件。
如果不想执行test1文件而只是想导入test1中的函数可以通过判断语句来实现
#单独运行test1文件时__name__的值为'__main__'
#作为模块导入时__name__的值为'__test1__'
if __name__ == '__main__'
准备工作:
连接上Redis
新建文件
参数文件
HOST = "***"
#后台端口
PORT = ****
#App名字
APPNAME = "ip"
#数据库端口
PORT2 =***
#密码
PASS = "****"
#数据库号
DBBH= 1
0.对Redis数据库的通用操作/模块化编程的益处
定义一个类ProyxRedis,在新建对象时自动连接Redis数据库。
实现添加Ip且不重复添加。
对可用IP给满分,不可用减分,分值小于0的IP进行删除。
获取所有IP
获取单个IP(优先可以使用的IP)
import redis
import random
#从Setting中导入参数
from Setting import *
class ProyxRedis:
#实现类的时候必定执行__init__
def __init__(self):
self.red = redis.Redis(
port=PORT2 , #端口号
host =HOST, #ip地址
password=PASS, #密码
db=DBBH, #数据库编号
decode_responses=True #对返回字节自动解码
)
#添加Ip
def add_ip(self,ip):
if not self.red.zscore("proxy",ip):
self.red.zadd("proxy",{ip:10})
print("采集到新ip"+ip)
else:
print(ip+"已经存在了")
#获取所有Ip
def get_allIP(self):
return self.red.zrange("proxy",0,-1)
#ip分数拉满
def set_maxip(self,ip):
self.red.zadd("proxy",{ip:100})
print(ip+"可用,分数拉满")
#扣分
def desc_score(self,ip):
s = self.red.zscore("proxy",ip)
if s and s>0:
self.red.zincrby("proxy",-1,ip)
print(ip + "不可用,分数-1")
else:
self.red.zrem("proxy",ip)
print(ip + "不可用且分数过低,进行删除")
#拿一个Ip来用
def get_ip(self):
#拿100分到100分的所有ip
ips = self.red.zrange("proxy",100,100,0,-1)
if ips:
return random.choice(ips)
else:
ipst=self.red.zrange("proxy",11,99,0,-1)
if ipst:
return random.choice(ipst)
else:
print("无可用ip")
收集IP
import requests
from lxml import etree
import time
#导入模块
import proxy_redis
#实例化类
red = proxy_redis.ProyxRedis()
UA = {
"User-Agent":"***"
}
def get_kip():
def get_kxxip(i):
def run():
i=1
while 1:
try:
get_kip()
get_kxxip(i)
i=i+1
except:
print("崩了")
time.sleep(20)
if __name__ == '__main__':
run()
协程验证IP可用性
import time
import proxy_redis
import asyncio
import aiohttp
async def verify(i,sem,red):
#响应等待时间上限
time2=aiohttp.ClientTimeout(total=10)
try:
async with aiohttp.ClientSession() as session:
async with session.get("http://www.***.com",proxy=i,timeout=time2) as resp:
#这里要获取page_source是因为网站可能请求超时
page_source=await resp.text()
if resp.status in [200,302]:
red.set_maxip(i)
print(i+"可用"+"分值拉满")
else:
red.desc_score(i)
print(i + "不可用" + "分值减小")
except Exception as e:
print("长时间无应答",e)
red.desc_score(i)
print(i + "不可用" + "分值减小")
async def main(red):
all_ip=red.get_allIP()
task = []
sem =asyncio.Semaphore(30) #控制并发量
for i in all_ip:
task.append(asyncio.create_task(verify(i,sem,red)))
if task: #保证task不为空
await asyncio.wait(task)
def run():
red = proxy_redis.ProyxRedis()
time.sleep(10) #多进程情况下应优先采集数据故sleep(10)让ip_collection先获取部分数据,
#防止task为空
while 1:
try:
asyncio.run(main(red))
time.sleep(30)
except Exception as e:
print("检验出错",e)
time.sleep(30)
if __name__ == '__main__':
run()
提供接口
import proxy_redis #类
from sanic import Sanic, json
from sanic_cors import CORS
import multiprocessing
from Setting import * #参数
app = Sanic(APPNAME) #app名字
CORS(app) #跨域
red = proxy_redis.ProyxRedis()
@app.route("/get_proxy") #打开谷歌输入 网址/get_proxy
def qip(req):
ip = red.get_ip()
return json({"ip": ip}) #返回IP
#不建议用默认端口号,因为端口号6379被占用了。这个端口号一般用于Redis服务,默认情况下是被Redis占用的。你需要将端口号修改为其他未被占用的端口。
def run():
if not multiprocessing.get_start_method():
multiprocessing.set_start_method("spawn")
app.run(host=HOST, port=PORT) #运行app提供IP
if __name__ == '__main__':
run()
多进程任务执行
from ip_api import run as api_run
from ip_verify import run as verify_run
from ip_collection import run as coll_run
from multiprocessing import Process
def run():
p1 = Process(target=api_run)
p2 = Process(target=verify_run)
p3=Process(target=coll_run)
p1.start() #提供IP接口
p3.start() #收集IP
p2.start() #验证IP
if __name__ == '__main__':
run()
# 在后台运行python来采集Ip
#在终端进入当前Py文件的目录
#dir命令查看当前路径下的文件有哪些
#执行RUN.py命令:
#python RUN.py
测试效果
import requests
UA = {
"User-Agent":"***"
}
def get_proxy():
url = "http://****/get_proxy"
resp = requests.get(url,headers = UA)
dic = resp.json()
proxy={
"http":dic["ip"][0],
"https":dic["ip"][0]
}
print(proxy)
# 网页可能会重新定向到https,但是我的代理Ip只能使用http访问,所以https也用http试试
#{'http': 'http://121.8.215.106:9797', 'https': 'http://121.8.215.106:9797'}
return proxy
url = "http://www.***.com"
#实际效果看代理池中的ip
resp = requests.get(url,headers = UA,proxies=get_proxy())
print(resp.text)