侧边栏壁纸
  • 累计撰写 56 篇文章
  • 累计创建 39 个标签
  • 累计收到 69 条评论

目 录CONTENT

文章目录

基于Python的Linux环境下,一键生成IP代理池绕过爬虫的IP限制

草莓牛奶
2023-09-03 / 0 评论 / 0 点赞 / 230 阅读 / 2,604 字 / 正在检测是否收录...
温馨提示:
「博客文章out of date 会及时更新,无特殊说明仍然有效,欢迎指正内容中的错误」

一、介绍

这个Python脚本是一个高度可配置的代理服务器管理工具,主要用于网络爬虫应用。其核心功能是生成大量的IPv6地址和相应的代理服务,从而允许用户在数据抓取过程中轻松绕过IP限制。这一目标是通过几个主要步骤实现的:

  1. 生成IPv6地址: 脚本使用Linux的ipdhclient命令来动态创建虚拟网络接口,并为每个接口分配一个唯一的IPv6地址。这些新创建的接口都连接到一个预先指定的基础接口(默认为eth0)。
  2. 代理池管理: 对于每个生成的IPv6地址,脚本会创建一个相应的代理服务,并将这些代理信息存储在一个名为proxy_pool的字典中。每个代理都绑定到一个特定的端口和网络接口。
  3. 固定端口支持: 虽然每个代理都有一个唯一的端口,但脚本还提供了一个统一的入口端口(默认为10000)供客户端连接。这意味着客户端可以通过连接到这个固定端口来访问任何可用的代理服务。
  4. 动态代理切换: 脚本提供了一个特定的函数switch_http_server,允许用户在运行时动态切换代理。这是通过修改一个全局标志变量global_flag实现的,当该标志被设置时,下一个请求将自动使用代理池中的下一个代理。

通过综合应用以上特性,这个脚本不仅提供了一种高效的方式来生成和管理大量的IPv6代理,还为动态和灵活的网络爬虫应用提供了强大的支持。

欢迎 Star:完整代码,一般以下方法不但适用于家庭网络的IPV6,同样适用于VPS等环境……(如果这种方法不适用,可以看看谁不想要 2^64 个 IP 的代理池

问题和考虑因素

  1. IPv6封锁: 如果一个网络安全系统选择封锁整段IPv6地址,那么这个脚本生成的多个IPv6代理可能会一并被封。这种情况下,即使生成了大量的IPv6地址也无法达到绕过IP限制的目的。

  2. 现代WAF(Web应用防火墙): 通常,现代的WAF不仅仅依赖于IP地址进行流量限制。它们可能还使用更复杂的算法和多种信号(如请求头、行为分析等)来识别和阻止恶意流量。但是,依赖于庞大的IPv6地址空间确实能在某种程度上绕过基于单一IP的流量限制。

    ……

image-20230903000648681

二、管理IPV6网口

is_root()

用途

函数是用来判断当前运行脚本的用户是否是root用户。这很重要,因为只有root用户才能执行一些网络设置相关的操作。

实现逻辑

它通过调用os.geteuid()函数来获取当前用户的有效用户ID,然后检查这个ID是否为0(root用户的ID总是0)。

def is_root():
    # 获取当前用户的有效用户ID
    return os.geteuid() == 0  # 检查是否为root用户(ID为0)

interface_exists(interface_name)

用途

函数用来检查一个给定名称的网络接口是否存在。

实现逻辑

它使用subprocess库来运行Linux命令ip link show <interface_name>。如果该命令成功执行(返回码为0),那么意味着该网络接口存在。

def interface_exists(interface_name):
    # 运行Linux命令以检查网络接口是否存在
    cmd_result = subprocess.run(["ip", "link", "show", interface_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return cmd_result.returncode == 0  # 返回码为0表示存在

create_ipv6_addresses()

用途

创建n个IPv6地址,与基础接口(默认为'eth0')关联。

实现逻辑
  1. 首先,它会检查是否为root用户。
  2. 然后,对于每一个要创建的IPv6地址,都会创建一个新的虚拟网络接口,并连接到基础接口(默认是'eth0')。
  3. 使用dhclient命令为这些新创建的接口分配IPv6地址。
def create_ipv6_addresses(n, base_interface='eth0'):
    interfaces = []
    sudo_cmd = ["sudo"] if not is_root() else []  # 如果不是root用户,添加sudo
    for i in range(1, n + 1):
        interface_name = f"{base_interface}_{i}"
        # 如果接口存在,则先删除
        if interface_exists(interface_name):
            subprocess.run(sudo_cmd + ["ip", "link", "delete", interface_name])
        # 创建新的网络接口
        subprocess.run(sudo_cmd + ["ip", "link", "add", "link", base_interface, interface_name, "type", "macvlan", "mode", "bridge"])
        # 激活新接口
        subprocess.run(sudo_cmd + ["ip", "link", "set", interface_name, "up"])
        # 使用dhclient为新接口分配IPv6地址
        subprocess.run(sudo_cmd + ["dhclient", "-6", "-nw", interface_name])
        interfaces.append(interface_name)
    return interfaces

delete_ipv6_addresses()

用途

删除之前创建的IPv6地址。

实现逻辑

它遍历所有虚拟接口,并使用ip link delete命令来删除它们。

def delete_ipv6_addresses(n, base_interface='eth0'):
    sudo_cmd = ["sudo"] if not is_root() else []  # 如果不是root用户,添加sudo
    for i in range(1, n + 1):
        interface_name = f"{base_interface}_{i}"
        # 删除网络接口
        subprocess.run(sudo_cmd + ["ip", "link", "delete", interface_name])

三、代理服务

forward_data()

用途

函数负责数据转发。

实现逻辑

它从源socket读取数据,然后发送到目标socket,直到源socket没有更多的数据可读。

def forward_data(source, destination):
    try:
        while True:
            data = source.recv(4096)  # 从源socket接收数据
            if len(data) == 0:
                break
            destination.send(data)  # 将数据发送到目标socket
    finally:
        source.close()
        destination.close()

handle_client_with_proxy_pool()

用途

处理客户端的连接请求,并使用代理池进行转发。

实现逻辑
  1. 根据global_flagproxy_switch_count来选择一个代理。
  2. 创建一个新的目标socket,并连接到该代理。
  3. 创建两个线程,用于数据转发。
def handle_client_with_proxy_pool(client_socket, proxy_pool):
    global proxy_switch_count
    global global_flag
    if global_flag == 1:
        proxy_switch_count += 1  # 如果全局标志为1,增加代理切换计数
        global_flag = 0
    # 选择一个代理
    proxy_index = proxy_switch_count % len(proxy_pool)
    selected_proxy_key = list(proxy_pool.keys())[proxy_index]
    selected_proxy = proxy_pool[selected_proxy_key]
    # 创建目标socket,并设置其接口
    target_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    target_socket.setsockopt(socket.SOL_SOCKET, 25, str(selected_proxy['interface'] + '\0').encode('utf-8'))
    target_socket.connect(('127.0.0.1', selected_proxy['port']))
    # 创建两个线程用于数据转发
    threading.Thread(target=forward_data, args=(client_socket, target_socket)).start()
    threading.Thread(target=forward_data, args=(target_socket, client_socket)).start()

start_proxy_pool_server(bind_ip, bind_port, proxy_pool)

用途

启动代理服务器。

实现逻辑
  1. 创建一个新的socket,绑定到指定的IP和端口。
  2. 开始监听,并在接收到新的客户端连接时,使用handle_client_with_proxy_pool函数来处理。
def start_proxy_pool_server(bind_ip, bind_port, proxy_pool):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((bind_ip, bind_port))  # 绑定到指定的IP和端口
    server_socket.listen(5)  # 开始监听
    while True:
        client_socket, _ = server_socket.accept()  # 接受新的客户端连接
        # 创建一个新线程来处理这个客户端
        thread = threading.Thread(target=handle_client_with_proxy_pool, args=(client_socket, proxy_pool))
        thread.daemon = True
        thread.start()

stop_proxy_servers()

用途

函数用于停止代理服务器并删除所有之前创建的IPv6地址。

实现逻辑与代码
  1. 打印正在关闭代理服务器的信息。
  2. 调用delete_ipv6_addresses()函数以删除所有创建的IPv6地址。
  3. 打印代理服务器已关闭的信息。
def stop_proxy_servers(n, base_interface='eth0'):
    print("正在关闭代理服务器...")
    print("删除IPv6地址...")
    delete_ipv6_addresses(n, base_interface)  # 调用函数以删除所有IPv6地址
    print("代理服务器已关闭.")

start_proxy_servers()

用途

函数用于启动代理服务器。

实现逻辑与代码
  1. 首先调用create_ipv6_addresses()函数以创建n个IPv6地址。
  2. 初始化一个名为proxy_pool的字典,用于存储代理信息。
  3. 遍历每个新创建的接口,并将其信息(IP地址、端口、接口名)添加到proxy_pool中。
  4. 打印proxy_pool的内容。
  5. 调用start_proxy_pool_server()函数以启动代理服务器。
def start_proxy_servers(n, start_port=20000, proxy_port=10000, base_interface='eth0'):
    interfaces = create_ipv6_addresses(n, base_interface)  # 创建IPv6地址
    proxy_pool = {}
    for i, interface_name in enumerate(interfaces):
        port = start_port + i
        # 将代理信息添加到proxy_pool字典
        proxy_pool[interface_name] = {"ip": "127.0.0.1", "port": port, "interface": interface_name}
    print(json.dumps(proxy_pool, indent=4))  # 打印代理池
    # 启动代理服务器
    thread = threading.Thread(target=start_proxy_pool_server, args=("0.0.0.0", proxy_port, proxy_pool))
    thread.daemon = True
    thread.start()

四、切换代理服务

switch_proxy_server()

用途

函数用于改变一个全局变量global_flag,从而触发代理切换。

实现逻辑

非常简单,就是将全局变量global_flag设置为1。

def switch_proxy_server():
    global global_flag
    global_flag = 1  # 设置全局标志为1

五、使用示例

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import gen_proxy_servers
#引入本脚本

# 初始化代理信息
proxy_port = 10000  # 这是您的代理服务器在运行的统一入口端口
proxy_ip = "127.0.0.1"  # 这是您的代理服务器在运行的IP地址
start_port = 20000
base_interface = 'eth0'

#生成100个IPV6
start_proxy_servers(100, start_port, proxy_port, base_interface)

# 设置Chrome选项
chrome_options = Options()
chrome_options.add_argument("--headless")  # 无头模式

# 设置代理
chrome_options.add_argument(f"--proxy-server=http://{proxy_ip}:{proxy_port}")

# 启动Chrome浏览器
driver = webdriver.Chrome(options=chrome_options)

# 打开网站
driver.get("http://www.example.com")

# 切换代理(假设switch_proxy_server函数在这里被调用)
switch_proxy_server()

# 打开另一个网站
driver.get("http://www.another-example.com")

#关闭
stop_proxy_servers(100, base_interface)
0

评论区