1. 程式人生 > >Python 抓取可用代理IP

Python 抓取可用代理IP

問題描述

在做資料抓取的時候,經常會碰到有些網站對同一IP的訪問頻率做限制。遇到這種情況一般只有兩種解決方案:

  1. 降低抓取頻率。這種方法在資料變化不頻繁,資料量不大的情況下還好,但是,如果資料變化頻繁或者資料量龐大,此方法明顯不能滿足需求。
  2. 使用代理IP。抓取的過程中,經常更換代理IP,這種方法基本可以有效解決同一IP訪問頻率限制的問題。此方案的難點在於如何獲取大量可用的代理IP。

代理IP獲取

代理IP的獲取途徑基本也就兩種:

  1. 購買付費代理IP。一般都是按使用時長和代理IP數收費,優點就是可靠性高。
  2. 使用免費代理。可以從免費代理網站獲取,但是穩定性不好,絕大部分都會很快失效。

付費代理沒什麼好講的,付款之後一般就可以拿到資料介面,程式裡邊直接呼叫即可。

下面講一下免費代理IP的獲取及篩選。這種出力不討好的繁瑣工作當然應該交給程式來自動完成。

這裡以西刺代理為例講一下獲取https代理的分析過程並給出示例程式。

通過對頁面請求進行分析,可以找到包含https代理的實際請求地址是: http://www.xicidaili.com/wn/{page},第一頁page=1,第二頁page=2...以此類推。西刺代理的IP每幾分鐘都會更新一次,所以每次只抓取前幾頁基本就可以了。

網路請求使用Python的requests庫,頁面解析使用pyquery。也可以使用urllib和beautifulSoup,不過個人感覺稍微麻煩一些。

廢話不多說了,下面直接上程式,程式碼基於Python3編寫,如果要在Python2下執行需要稍作修改。

"""
該程式用於從代理網站獲取可用ip
使用方法1: 直接執行該檔案,會在同目錄下生成ips.txt檔案,檔案內包含可用的代理
使用方法2: 其他程式匯入該檔案,然後直接使用該檔案內定義的全域性變數'proxies'
"""
import random
import threading
import time
from concurrent import futures

import requests
from pyquery import PyQuery

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
                  Chrome/53.0.2785.104 Safari/537.36 Core/1.53.2306.400 QQBrowser/9.5.10530.400'}
# 檢測代理ip有效性的網站
CHECK_URL = 'https://ip.cn'
# 抓取地址(西刺代理)
FETCH_URL = 'http://www.xicidaili.com/wn/{}'
# 抓取頁數,每頁100條
PAGES = 3
# 代理型別(http/https)
PROXY_TYPE = 'https'
# 有效代理ip列表
proxies = []
# 執行緒池,用於同時驗證多個代理ip
POOL = futures.ThreadPoolExecutor(max_workers=50)


def add_proxy(proxy: str):
    """
    新增代理

    :param proxy: 代理ip+埠號
    :return:
    """
    try:
        r = requests.get(CHECK_URL, proxies={PROXY_TYPE: proxy}, timeout=30)
        print(PyQuery(r.content.decode()).find('#result').text(), '\n')

        if r.status_code == 200 and proxy not in proxies:
            proxies.append(proxy)
    except Exception as e:
        if proxy in proxies:
            proxies.remove(proxy)
        print(proxy, e)


def fetch_proxy():
    """
    抓取代理ip
    :return:
    """
    for page in range(1, PAGES + 1):
        r = requests.get(FETCH_URL.format(page), headers=headers)
        doc = PyQuery(r.content.decode('utf-8'))
        # 獲取資料列表對應的table
        table = doc('#ip_list')
        # 獲取table中除了表頭以外的所有行
        rows = table('tr:nth-of-type(n+2)').items()
        # 提取每一行中的ip和埠號
        for row in rows:
            ip = row('td:nth-of-type(2)').text()
            port = row('td:nth-of-type(3)').text()
            proxy = ip + ':' + port
            # 線上程池中檢測該代理是否可用
            POOL.submit(add_proxy, proxy)
        # 10秒鐘後抓取下一頁
        time.sleep(10)


def run():
    while True:
        try:
            fetch_proxy()
            print('有效代理:', proxies)
            # 將有效代理寫入檔案
            with open('ips.txt', 'w', encoding='utf-8') as f:
                f.write('\n'.join(proxies))
        except Exception as e:
            print(e)
        # 抓取一次之後休息一段時間,防止被遮蔽
        time.sleep(random.randint(100, 600))


# 啟動抓取執行緒
threading.Thread(target=run).start()

程式執行一段時間之後,開啟ips.txt檔案即可看到抓取到的可用代理IP,如圖: