每日爬蟲練習:多線程代理IP池實戰(抓取、清洗)

一、前言

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錄入成功!')

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章