Python 利用免费HTTP代理IP网站多线程筛选出自己的代理IP池

LONG LONG TIME NO SEE


在这里插入图片描述

前言

有爬虫就会有反爬,就好像有正版就肯定会有做盗版的一样。

某小博物馆免票展览一批最新出土的文物,张三也想进去看看(,顺便实施盗窃)。
13:00 pm,进去一次,……,出来;
13:01 pm,又进去一次,……,出来;
13:02 pm,又进去一次,引起门口保安注意,……,出来;
13:03 pm,又进去一次,保安认为他进出次数过于频繁,将其认定为贼并乱棒打出
13:04 pm,张三又想进去。。。不好意思,张三再也进不了这个博物馆了

爬虫和反爬就像上面这则故事的张三和保安。正常来说,当你短期内非常暴力地大量访问了某一个或者某一类网页后,你大概率会被人家拉黑。 反爬最基本的策略就是一刀切——把你的IP给封杀了,这是最简单粗暴的方法,但也是对付像我一样的初级爬虫小白比较有效的一招。

张三不甘心,于是第二天叫来了他异父异母的兄弟们【张四、张五、张六……张一百】
13:00 pm,张四进去,……,出来;
13:01 pm,张五进去,……,出来;
13:02 pm,张六进去,……,出来;
……
xx:xx pm,张一百进去,……,出来;
xx:xx+1 pm,张四进去,……,出来;
……
yy:yy pm,博物馆 空

事实上,真正的反爬远比这个复杂得多,张三遇到的只是最最low的保安。但是这个故事也可以说明,对于比较简单的网站的反爬,只需要不停地更换自己的IP地址就能对付。 其原因也很简单,不停地换生面孔,“保安”没有足够的证据证明想进来的是“贼”而拦住他,即使拦住,也找不到幕后主使“张三”。

IP是上网需要唯一的身份地址,身份凭证,而代理IP就是我们上网过程中的一个中间平台,是由你的电脑先访问代理IP,之后再由代理IP访问你点开的页面。


一、怎么找IP代理?

这玩意百度一搜一大把。根据是否要¥,分为免费代理和付费代理。
当然,付费代理的稳定性和可用性不知道比免费的高出多少倍。
但是话又说回来了,人家钱都不收你的就免费给你用,还要啥自行车

搜索关键字“代理IP”,如图
在这里插入图片描述
我瞄中了“快代理”,它打出的招牌是“国内高匿免费HTTP代理IP”,那相比应该有许多可以用的吧(虽然最后事实告诉我可以用的仅凤毛麟角)

二、直接上手

先把可用的搞下来

# -*- coding: utf-8 -*-
# GETIP.py
# @Time: 2021/3/29 14:42
# @Software: PyCharm

import time
from requests_html import HTMLSession
import random


def GetID():
    session = HTMLSession()
    fo = open('代理IP.txt', "w")

    # 快代理找代理池,写进文件
    useful_IP = []
    for page in range(1, 11):
        res = session.get("https://www.kuaidaili.com/free/intr/{}".format(page))
        IPs = res.html.xpath("//tbody/tr/td[position()<5]")
        useful_IP += ["{},{},{}".format(ip[0].text, ip[1].text, ip[2].text) for ip in
                      zip(IPs[::4], IPs[1::4], IPs[3::4])]
        time.sleep(random.randint(3, 5))
    fo.write("\n".join(useful_IP))

    fo.close()
    session.close()


if __name__ == '__main__':
    GetID()

再对它进行筛选和分析

# -*- coding: utf-8 -*-
# CHECKIP.py
# @Time: 2021/3/29 17:34
# @Software: PyCharm

import time
import GETIP
import requests

# GETIP.GetID()  # 获取IP列表

fp = open('代理IP.txt', mode='r', encoding='utf-8')  # 总的ip列表
fp2 = open('可用代理IP.txt', mode='a', encoding='utf-8')  # 经过验证的ip

num = 0

useful_IP = fp.read().splitlines()


def verify_proxy():
    global num
    for line in useful_IP:
        ip, host, protocol = line.split(',')
        url1 = 'http://ip.tool.chinaz.com/'
        url2 = 'https://ip.cn/'
        try:
            if protocol == 'HTTPS':
                requests.get(url2, proxies={'https': '{}:{}'.format(ip, host)}, timeout=5)
                print('该 {} ip-> {}:{} 验证通过'.format(protocol, ip, host))
                num += 1
                fp2.write('{},{},{}\n'.format(ip, host, protocol))
            else:
                requests.get(url1, proxies={'http': '{}:{}'.format(ip, host)}, timeout=5)
                print('该 {} ip-> {}:{} 验证通过'.format(protocol, ip, host))
                num += 1
                fp2.write('{},{},{}\n'.format(ip, host, protocol))
        except Exception as e:
            print('该 {} ip-> {}:{} 验证失败'.format(protocol, ip, host))
            with open('错误日志.txt', mode='a', encoding='utf-8') as fe:
                fe.write('{}\n{}\n{}\n\n'.format('验证代理', str(e), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
    return num


verify_proxy()

fp.close()
fp2.close()
print('可用ip的数量是{}'.format(num))

三、代码的合并、重构和优化

有用到多线程,头一次启用需要用到文件里写死的proxy_list,这几个也是我爬下来的,之后估计会失效,第一次用的时候需要自己先找几个可靠的代理来跑。从第二次开始,便会读取在本地创建的存有可用代理的文件,可以在后台写个脚本,每天定时自动跑一次,基本上能够保证《可用代理IP.txt》中每天都是自己的最新的可用代理池了。

# -*- coding: utf-8 -*-
# @Time: 2021/3/30 11:49
# @Author: 胡志远
# @Software: PyCharm

import time
from requests_html import HTMLSession
import random
import threading
from queue import Queue
from pathlib import Path


def get_proxy_list(is_UsefulIPs):
    if is_UsefulIPs:
        fp = open('可用代理IP.txt', mode='r')  # 可用ip列表
    else:
        fp = open('代理IP.txt', mode='r')  # 总的ip列表
    IPs = set(fp.read().splitlines())  # 去重
    fp.close()
    format_IP = []
    for line in IPs:
        ip, host, protocol = line.split(',')
        if protocol == 'HTTPS':
            format_IP.append({'https': '{}:{}'.format(ip, host)})
        elif protocol == 'HTTP':
            format_IP.append({'http': '{}:{}'.format(ip, host)})
    return format_IP


global proxy_list

# 不同的代理IP,代理ip的类型必须和请求url的协议头保持一致
if Path("可用代理IP.txt").is_file():
    proxy_list = get_proxy_list(is_UsefulIPs=True)
else:
    # 这个列表要用的话最好更新
    proxy_list = [
        {"http": "59.124.224.180:3128"}
        , {'http': '45.169.16.22:8080'}
        , {'http': '86.62.120.68:3128'}
        , {'http': '45.188.156.129:8080'}
        , {'http': '186.10.118.189:8081'}
    ]


class Thread_crawl(threading.Thread):
    def __init__(self, name, page_queue):
        threading.Thread.__init__(self)
        self.page_queue = page_queue
        self.name = name

    def run(self) -> None:
        while True:
            if self.page_queue.empty():
                break
            else:
                print(self.name, '将要从队列中取任务')
                page = self.page_queue.get()
                print(self.name, '取出的任务是:', page)
                url = 'https://www.kuaidaili.com/free/intr/{}'.format(page)
                self.get_content(url=url)
                print(self.name, '完成任务的页码是:', page)

    def get_content(self, url):
        time.sleep(random.randint(3, 8))
        proxy = random.choice(proxy_list)
        self.get_data(session.get(url, proxies=proxy).html)

    def get_data(self, response):
        IPs = response.xpath("//tbody/tr/td[position()<5]")
        useful_IP = ["{},{},{}".format(ip[0].text, ip[1].text, ip[2].text) for ip in
                     zip(IPs[::4], IPs[1::4], IPs[3::4])]
        if useful_IP:
            fo.write("\n".join(useful_IP) + "\n")


def GetID(pages):
    page_queue = Queue()
    for page in range(1, pages):
        page_queue.put(page)
    # 生成线程
    crawl_name = ['c1', 'c2', 'c3', 'c4', 'c5']
    crawl_tread = []
    for name in crawl_name:
        crawl = Thread_crawl(name, page_queue)
        crawl.start()
        crawl_tread.append(crawl)  # 存放进程,堵塞主进程
    # 堵塞主线程,让子线程都完成任务后,主线程在往下执行
    for thread in crawl_tread:
        thread.join()


class Thread_analyse(threading.Thread):
    url1 = 'http://ip.tool.chinaz.com/'
    url2 = 'https://ip.cn/'

    def __init__(self, name, IP_queue):
        threading.Thread.__init__(self)
        self.IP_queue = IP_queue
        self.name = name

    def run(self) -> None:
        while True:
            if self.IP_queue.empty():
                break
            else:
                print(self.name, '将要从队列中取任务')
                IP = self.IP_queue.get()
                print(self.name, '取出的任务是:', IP)
                self.tryGet(IP)

    def tryGet(self, ip_proxy):
        try:
            if ip_proxy.get('http'):
                session.get(self.url1, proxies=ip_proxy, timeout=5)
                fo2.write('{},HTTP\n'.format(ip_proxy.get('http').replace(':', ',')))
            else:
                session.get(self.url2, proxies=ip_proxy, timeout=5)
                fo2.write('{},HTTPS\n'.format(ip_proxy.get('https').replace(':', ',')))
            print('{} 验证通过'.format(ip_proxy))
        except Exception:
            print('{} 验证失败'.format(ip_proxy))


def CheckIP():
    IP_queue = Queue()
    format_IP = get_proxy_list(is_UsefulIPs=False)
    for ip in format_IP:
        IP_queue.put(ip)
    # 生成线程
    analyse_name = ['C1', 'C2', 'C3', 'C4', 'C5']
    analyse_tread = []
    for name in analyse_name:
        analyse = Thread_analyse(name, IP_queue)
        analyse.start()
        analyse_tread.append(analyse)  # 存放进程,堵塞主进程
    # 堵塞主线程,让子线程都完成任务后,主线程在往下执行
    for thread in analyse_tread:
        thread.join()


if __name__ == '__main__':
    session = HTMLSession()

    ## 重新获取最新IP列表

    fo = open('代理IP.txt', mode='w')  # 总的ip列表
    GetID(51)  # 爬50页
    fo.close()

    print("~" * 35)  # 分割线

    ## 筛选可用代理IP

    fo2 = open('可用代理IP.txt', mode='w')  # 经过验证的ip
    CheckIP()
    fo2.close()

    session.close()

【代码运行截图】
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
吐槽一句,免费的实不靠谱,可用的真太少了。


总结

请遵守道德和法律的约束,不要违法乱纪

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远哥挺乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值