每日爬虫练习:多线程代理IP池实战(抓取、清洗)

董桐
2023-12-01

一、前言

2020-04-04日爬虫练习
每日一个爬虫小练习,学习爬虫的记得关注哦!

学习编程就像学习骑自行车一样,对新手来说最重要的是持之以恒的练习。
在《汲取地下水》这一章节中看见的一句话:“别担心自己的才华或能力不足。持之以恒地练习,才华便会有所增长”,现在想来,真是如此。

二、需求:

分页爬取快代理国内免费高匿IP,并对IP进行清洗验证,将可用的IP储存到本地

三、IP代理池设计

3.1 意义

学习爬虫,离不开高频访问(请求),现在很多网站为了抵御爬虫,设置防爬措施,对频繁访问的IP要求重新登录,或者或跳转至一个带有滑块验证的页面,要求用户登录或拖动滑块。目前对于反爬措施中IP限制,使用动态IP代理访问还是可行的。

3.2 IP代理科普

IP代理有透明代理、匿名代理、混淆代理和高匿代理。这四种代理,主要是代理服务器端的配置不同,导致其向目标地址发送请求时,REMOTE_ADDR、HTTP_VIA、HTTP_X_FORWARDED_FOR三个变量不同。

一:透明代理(Transparent Proxy)

REMOTE_ADDR=Proxy IP

HTTP_VIA=Proxy IP

HTTP_X_FORWARDED_FOR=Your IP

透明代理虽然可以直接”隐藏”你的IP,但是还是可以从HTTP_X_FORWARDED_FOR来查到你是谁。

二:匿名代理(Anonymous Proxy)

REMOTE_ADDR=Proxy IP

HTTP_VIA=Proxy IP

HTTP_X_FORWARDED_FOR=Proxy IP

匿名代理比透明代理进步一点:别人只能知道你用了代理,无法知道你是谁。

三:混淆代理(Distorting Proxies)

REMOTE_ADDR=Proxy IP

HTTP_VIA=Proxy IP

HTTP_X_FORWARDED_FOR=Random IP address

与匿名代理相同,如果使用了混淆代理,别人还是能知道你在用代理,但是会得到一个假的IP地址,伪装的更逼真

四:高匿代理(High Anonymity Proxy)

REMOTE_ADDR=Proxy IP

HTTP_VIA=not determined

HTTP_X_FORWARDED_FOR=not determined

使用高匿代理,能让别人根本无法发现你是在用代理,所以是最好的选择。

3.3 技术路线

1.requests
2.BeautifulSoup
3.threading.Thread # 多线程

3.4 设计思路

  1. 目前网上有很多免费的代理IP,不过这种免费代理IP都不稳定,获取到的免费IP都得通过清洗(检测)是否可用。
  2. 本博文爬取的是快代理IP的国内高匿IP:https://www.kuaidaili.com/free/
  3. 由于清洗代理,时间大都花在网络请求上了,个人试了下多线程爬取,速度有很大提升。

3.5 实战过程中遇到的问题

1.由于快代理的HTTP 是大写,直接进行 requests请求的时候, requests请求可以成功,但是请求使用的将会是你真实的ip地址 ,所以得进行大小写转换。
2. 如果爬取到的代理IP协议是https,在访问http网站时,requests请求可以成功,但是请求使用的将会是你真实的ip地址
3. 一开始使用http://icanhazip.com/网站进行验证,如果正常ip,它返回值的text,将会是你请求IP,但是它对80,8080等一些特殊端口不友好,无法做到正确验证,而且响应速度慢,特别影响效率。
4. 使用https://www.baidu.com/进行验证有两个好处,
----百度支持http和https,所以两个协议都能使用代理IP进行正常访问
----百度请求和响应速度特别快,如果状态码为200,那就说明代理ip有效,能起到快速清洗效果

ps:这是我爬虫实战过程中遇到的问题,觉得有帮助的给个赞吧!

四、快代理高匿IP爬取清洗实战:

'''

 爬取快代理IP,建设自己的爬虫代理池
 version:01
 author:金鞍少年
 date:2020-04-04
'''

import requests
from bs4 import BeautifulSoup
import time
from threading import Thread

class Douban:

    def __init__(self):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
            'Referer': 'https://www.kuaidaili.com/free/'
        }

    # 获取分页html
    def get_page_html(self, url):
        try:
            result = requests.get(url=url, headers=self.headers)
            result.raise_for_status()   # 主动抛出一个异常
            html = BeautifulSoup(result.text, 'lxml')
            return html
        except:
            print('链接失败!')

    # 获取免费ip 信息
    def get_proxy(self, html):
        proxies = []  # 代理池
        trs = html.find('table', class_='table table-bordered table-striped').find('tbody').find_all('tr')
        for tr in trs:
            tcp = list(tr.stripped_strings)[3].lower()
            ip = list(tr.stripped_strings)[0]
            port = list(tr.stripped_strings)[1]
            proxies.append((tcp, ip+":"+port))  # 拼接IP地址,端口号
        return proxies

    # 开启多线程任务
    def test_proxies(self, proxies):
        proxies = proxies
        for proxy in proxies:
            test = Thread(target=self.thread_test_proxy, args=(proxy[0], proxy[1],))
            test.start()

    # 开启线程验证ip模式
    def thread_test_proxy(self, tcp, address):
        try:
            print('待验证ip:%s' % address)
            # 因为TCP分http和https,所以分开传入做精准验证
            result = requests.get('https://www.baidu.com/', headers=self.headers, proxies={tcp: address}, timeout=3)  # timeout 超时时间
            if result.status_code == 200:
                self.save_proxys((tcp, address))  # 写入文件
            else:
                pass
        except Exception:
            pass

    # 保存IP到本地
    def save_proxys(self, proxy):
        with open("./res/快代理免费高匿IP.text", 'a+') as f:
            print('有效IP:【{}:{}】'.format(proxy[0], proxy[1]))
            f.write('{}:{}'.format(proxy[0], proxy[1]) + '\n')

    # 逻辑功能
    def func(self, base_url, page):
        for i in range(1, page):  # 快代理分页
            try:
                time.sleep(1)
                url = base_url.format(i)
                proxies = self.get_proxy(self.get_page_html(url))
                self.test_proxies(proxies)
            except Exception as e:
                print('错误类型:%s' % e)
                continue


if __name__ == '__main__':
    obj = Douban()
    obj.func('https://www.kuaidaili.com/free/inha/{}/', 2)  # rul 和爬取分页数

    print('爬取完毕,IP录入成功!')

 类似资料: