Python 抓取可用代理IP
阿新 • • 發佈:2019-01-25
問題描述
在做資料抓取的時候,經常會碰到有些網站對同一IP的訪問頻率做限制。遇到這種情況一般只有兩種解決方案:
- 降低抓取頻率。這種方法在資料變化不頻繁,資料量不大的情況下還好,但是,如果資料變化頻繁或者資料量龐大,此方法明顯不能滿足需求。
- 使用代理IP。抓取的過程中,經常更換代理IP,這種方法基本可以有效解決同一IP訪問頻率限制的問題。此方案的難點在於如何獲取大量可用的代理IP。
代理IP獲取
代理IP的獲取途徑基本也就兩種:
- 購買付費代理IP。一般都是按使用時長和代理IP數收費,優點就是可靠性高。
- 使用免費代理。可以從免費代理網站獲取,但是穩定性不好,絕大部分都會很快失效。
付費代理沒什麼好講的,付款之後一般就可以拿到資料介面,程式裡邊直接呼叫即可。
下面講一下免費代理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,如圖: