第20讲:代理的基本原理和用法
我們在做爬蟲的過程中經常會遇到這樣的情況,最初爬蟲正常運行,正常抓取數據,一切看起來都是那么的美好,然而一杯茶的功夫可能就會出現錯誤,比如 403 Forbidden,這時候打開網頁一看,可能會看到 “您的 IP 訪問頻率太高” 這樣的提示,或者跳出一個驗證碼讓我們輸入,輸入之后才可能解封,但是輸入之后過一會兒就又這樣了。
出現這種現象的原因是網站采取了一些反爬蟲的措施,比如服務器會檢測某個 IP 在單位時間內的請求次數,如果超過了這個閾值,那么會直接拒絕服務,返回一些錯誤信息,這種情況可以稱之為封 IP,于是乎就成功把我們的爬蟲禁掉了。
既然服務器檢測的是某個 IP 單位時間的請求次數,那么我們借助某種方式來偽裝我們的 IP,讓服務器識別不出是由我們本機發起的請求,不就可以成功防止封 IP 了嗎?所以這時候代理就派上用場了。
本課時我們先來看下代理的基本原理和使用代理處理反爬蟲的方法。
1.基本原理
代理實際上指的就是代理服務器,英文叫作 proxy server,它的功能是代理網絡用戶去獲取網絡信息。形象地說,它是網絡信息的中轉站。在我們正常請求一個網站時,是發送了請求給 Web 服務器,Web 服務器把響應傳回給我們。如果設置了代理服務器,實際上就是在本機和服務器之間搭建了一個橋,此時本機不是直接向 Web 服務器發起請求,而是向代理服務器發出請求,請求會發送給代理服務器,然后由代理服務器再發送給 Web 服務器,接著由代理服務器再把 Web 服務器返回的響應轉發給本機。這樣我們同樣可以正常訪問網頁,但這個過程中 Web 服務器識別出的真實 IP 就不再是我們本機的 IP 了,就成功實現了 IP 偽裝,這就是代理的基本原理。
2.代理的作用
那么,代理有什么作用呢?我們可以簡單列舉如下。
- 突破自身 IP 訪問限制,訪問一些平時不能訪問的站點。
- 訪問一些單位或團體內部資源,如使用教育網內地址段免費代理服務器,就可以用于對教育網開放的各類 FTP 下載上傳,以及各類資料查詢共享等服務。
- 提高訪問速度,通常代理服務器都設置一個較大的硬盤緩沖區,當有外界的信息通過時,也將其保存到緩沖區中,當其他用戶再訪問相同的信息時, 則直接由緩沖區中取出信息,傳給用戶,以提高訪問速度。
- 隱藏真實 IP,上網者也可以通過這種方法隱藏自己的 IP,免受攻擊,對于爬蟲來說,我們用代理就是為了隱藏自身 IP,防止自身的 IP 被封鎖。
3.爬蟲代理
對于爬蟲來說,由于爬蟲爬取速度過快,在爬取過程中可能遇到同一個 IP 訪問過于頻繁的問題,此時網站就會讓我們輸入驗證碼登錄或者直接封鎖 IP,這樣會給爬取帶來極大的不便。
使用代理隱藏真實的 IP,讓服務器誤以為是代理服務器在請求自己。這樣在爬取過程中通過不斷更換代理,就不會被封鎖,可以達到很好的爬取效果。
4.代理分類
代理分類時,既可以根據協議區分,也可以根據其匿名程度區分,下面分別總結如下:
4.1根據協議區分
根據代理的協議,代理可以分為如下類別:
- FTP 代理服務器,主要用于訪問 FTP 服務器,一般有上傳、下載以及緩存功能,端口一般為 21、2121 等。
- HTTP 代理服務器,主要用于訪問網頁,一般有內容過濾和緩存功能,端口一般為 80、8080、3128 等。
- SSL/TLS 代理,主要用于訪問加密網站,一般有 SSL 或 TLS 加密功能(最高支持 128 位加密強度),端口一般為 443。
- RTSP 代理,主要用于 Realplayer 訪問 Real 流媒體服務器,一般有緩存功能,端口一般為 554。
- Telnet 代理,主要用于 telnet 遠程控制(黑客入侵計算機時常用于隱藏身份),端口一般為 23。
- POP3/SMTP 代理,主要用于 POP3/SMTP 方式收發郵件,一般有緩存功能,端口一般為 110/25。
- SOCKS 代理,只是單純傳遞數據包,不關心具體協議和用法,所以速度快很多,一般有緩存功能,端口一般為 1080。SOCKS 代理協議又分為 SOCKS4 和 SOCKS5,SOCKS4 協議只支持 TCP,而 SOCKS5 協議支持 TCP 和 UDP,還支持各種身份驗證機制、服務器端域名解析等。簡單來說,SOCK4 能做到的 SOCKS5 都可以做到,但 SOCKS5 能做到的 SOCK4 不一定能做到。
4.2根據匿名程度區分
根據代理的匿名程度,代理可以分為如下類別。
- 高度匿名代理,高度匿名代理會將數據包原封不動的轉發,在服務端看來就好像真的是一個普通客戶端在訪問,而記錄的 IP 是代理服務器的 IP。
- 普通匿名代理,普通匿名代理會在數據包上做一些改動,服務端上有可能發現這是個代理服務器,也有一定幾率追查到客戶端的真實 IP。代理服務器通常會加入的 HTTP 頭有 HTTP_VIA 和 HTTP_X_FORWARDED_FOR。
- 透明代理,透明代理不但改動了數據包,還會告訴服務器客戶端的真實 IP。這種代理除了能用緩存技術提高瀏覽速度,能用內容過濾提高安全性之外,并無其他顯著作用,最常見的例子是內網中的硬件防火墻。
- 間諜代理,間諜代理指組織或個人創建的,用于記錄用戶傳輸的數據,然后進行研究、監控等目的的代理服務器。
5.常見代理類型
使用網上的免費代理,最好使用高匿代理,使用前抓取下來篩選一下可用代理,也可以進一步維護一個代理池。
- 使用付費代理服務,互聯網上存在許多代理商,可以付費使用,質量比免費代理好很多。
- ADSL 撥號,撥一次號換一次 IP,穩定性高,也是一種比較有效的解決方案。
- 蜂窩代理,即用 4G 或 5G 網卡等制作的代理,由于蜂窩網絡用作代理的情形較少,因此整體被封鎖的幾率會較低,但搭建蜂窩代理的成本較高。
6.代理設置
在前面我們介紹了多種請求庫,如 Requests、Selenium、Pyppeteer 等。我們接下來首先貼近實戰,了解一下代理怎么使用,為后面了解代理池打下基礎。
下面我們來梳理一下這些庫的代理的設置方法。
做測試之前,我們需要先獲取一個可用代理。搜索引擎搜索 “代理” 關鍵字,就可以看到許多代理服務網站,網站上會有很多免費或付費代理,比如免費代理“快代理”:https://www.kuaidaili.com/free/。但是這些免費代理大多數情況下都是不好用的,所以比較靠譜的方法是購買付費代理。付費代理各大代理商家都有套餐,數量不用多,穩定可用即可,我們可以自行選購。
如果本機有相關代理軟件的話,軟件一般會在本機創建 HTTP 或 SOCKS 代理服務,本機直接使用此代理也可以。
在這里,我的本機安裝了一部代理軟件,它會在本地的 7890 端口上創建 HTTP 代理服務,即代理為127.0.0.1:7890,另外還會在 7891 端口創建 SOCKS 代理服務,即代理為 127.0.0.1:7891。
我只要設置了這個代理,就可以成功將本機 IP 切換到代理軟件連接的服務器的 IP 了。下面的示例里,我將使用上述代理來演示其設置方法,你也可以自行替換成自己的可用代理。設置代理后測試的網址是:http://httpbin.org/get,我們訪問該網址可以得到請求的相關信息,其中 origin 字段就是客戶端的 IP,我們可以根據它來判斷代理是否設置成功,即是否成功偽裝了 IP。
7.requests 設置代理
對于 requests 來說,代理設置非常簡單,我們只需要傳入 proxies 參數即可。
我在這里以我本機的代理為例,來看下 requests 的 HTTP 代理的設置,代碼如下:
import requests proxy = '127.0.0.1:7890' proxies = {'http': 'http://' + proxy,'https': 'https://' + proxy, } try:response = requests.get('https://httpbin.org/get', proxies=proxies)print(response.text) except requests.exceptions.ConnectionError as e:print('Error', e.args) 運行結果: {"args": {},"headers": {"Accept": "*/*","Accept-Encoding": "gzip, deflate","Host": "httpbin.org","User-Agent": "python-requests/2.22.0","X-Amzn-Trace-Id": "Root=1-5e8f358d-87913f68a192fb9f87aa0323"},"origin": "210.173.1.204","url": "https://httpbin.org/get" }可以發現,我們通過一個字典的形式就設置好了 HTTP 代理,它分為兩個類別,有 HTTP 和 HTTPS,如果我們訪問的鏈接是 HTTP 協議,那就用 http 字典名指定的代理,如果是 HTTPS 協議,那就用 https 字典名指定的代理。
其運行結果的 origin 如是代理服務器的 IP,則證明代理已經設置成功。
如果代理需要認證,同樣在代理的前面加上用戶名密碼即可,代理的寫法就變成如下所示:
proxy = 'username:password@127.0.0.1:7890'這里只需要將 username 和 password 替換即可。
如果需要使用 SOCKS 代理,則可以使用如下方式來設置:
import requests proxy = '127.0.0.1:7891' proxies = {'http': 'socks5://' + proxy,'https': 'socks5://' + proxy } try:response = requests.get('https://httpbin.org/get', proxies=proxies)print(response.text) except requests.exceptions.ConnectionError as e:print('Error', e.args)在這里,我們需要額外安裝一個包,這個包叫作 requests[socks],安裝命令如下所示:
pip3 install "requests[socks]"運行結果是完全相同的:
{"args": {},"headers": {"Accept": "*/*","Accept-Encoding": "gzip, deflate","Host": "httpbin.org","User-Agent": "python-requests/2.22.0","X-Amzn-Trace-Id": "Root=1-5e8f364a-589d3cf2500fafd47b5560f2"},"origin": "210.173.1.204","url": "https://httpbin.org/get" }另外,還有一種設置方式即使用 socks 模塊,也需要像上文一樣安裝 socks 庫。這種設置方法如下所示:
import requests import socks import socket socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 7891) socket.socket = socks.socksocket try:response = requests.get('https://httpbin.org/get')print(response.text) except requests.exceptions.ConnectionError as e:print('Error', e.args)使用這種方法也可以設置 SOCKS 代理,運行結果完全相同。相比第一種方法,此方法是全局設置。我們可以在不同情況下選用不同的方法。
8.Selenium 設置代理
Selenium 同樣可以設置代理,在這里以 Chrome 為例來介紹下其設置方法。
對于無認證的代理,設置方法如下:
from selenium import webdriver proxy = '127.0.0.1:7890' options = webdriver.ChromeOptions() options.add_argument('--proxy-server=http://' + proxy) browser = webdriver.Chrome(options=options) browser.get('https://httpbin.org/get') print(browser.page_source) browser.close()運行結果如下:
{"args": {},"headers": {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","Accept-Encoding": "gzip, deflate","Accept-Language": "zh-CN,zh;q=0.9","Host": "httpbin.org","Upgrade-Insecure-Requests": "1","User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36","X-Amzn-Trace-Id": "Root=1-5e8f39cd-60930018205fd154a9af39cc"},"origin": "210.173.1.204","url": "http://httpbin.org/get" }代理設置成功,origin 同樣為代理 IP 的地址。
如果代理是認證代理,則設置方法相對比較麻煩,設置方法如下所示:
from selenium import webdriver from selenium.webdriver.chrome.options import Options import zipfileip = '127.0.0.1' port = 7890 username = 'foo' password = 'bar'manifest_json = """{"version":"1.0.0","manifest_version": 2,"name":"Chrome Proxy","permissions": ["proxy","tabs","unlimitedStorage","storage","<all_urls>","webRequest","webRequestBlocking"],"background": {"scripts": ["background.js"]} } """ background_js = """ var config = {mode: "fixed_servers",rules: {singleProxy: {scheme: "http",host: "%(ip) s",port: %(port) s}}}chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});function callbackFn(details) {return {authCredentials: {username: "%(username) s",password: "%(password) s"}} }chrome.webRequest.onAuthRequired.addListener(callbackFn,{urls: ["<all_urls>"]},['blocking'] ) """ % {'ip': ip, 'port': port, 'username': username, 'password': password}plugin_file = 'proxy_auth_plugin.zip' with zipfile.ZipFile(plugin_file, 'w') as zp:zp.writestr("manifest.json", manifest_json)zp.writestr("background.js", background_js) options = Options() options.add_argument("--start-maximized") options.add_extension(plugin_file) browser = webdriver.Chrome(options=options) browser.get('https://httpbin.org/get') print(browser.page_source) browser.close()這里需要在本地創建一個 manifest.json 配置文件和 background.js 腳本來設置認證代理。運行代碼之后本地會生成一個 proxy_auth_plugin.zip 文件來保存當前配置。
運行結果和上例一致,origin 同樣為代理 IP。
SOCKS 代理的設置也比較簡單,把對應的協議修改為 socks5 即可,如無密碼認證的代理設置方法為:
from selenium import webdriverproxy = '127.0.0.1:7891' options = webdriver.ChromeOptions() options.add_argument('--proxy-server=socks5://' + proxy) browser = webdriver.Chrome(options=options) browser.get('https://httpbin.org/get') print(browser.page_source) browser.close()運行結果是一樣的。
9.aiohttp 設置代理
對于 aiohttp 來說,我們可以通過 proxy 參數直接設置即可,HTTP 代理設置如下:
import asyncio import aiohttpproxy = 'http://127.0.0.1:7890'async def main():async with aiohttp.ClientSession() as session:async with session.get('https://httpbin.org/get', proxy=proxy) as response:print(await response.text())if __name__ == '__main__':asyncio.get_event_loop().run_until_complete(main())如果代理有用戶名密碼,像 requests 一樣,把 proxy 修改為如下內容:
proxy = 'http://username:password@127.0.0.1:7890'這里只需要將 username 和 password 替換即可。
對于 SOCKS 代理,我們需要安裝一個支持庫,叫作 aiohttp-socks,安裝命令如下:pip3 install aiohttp-socks
可以借助于這個庫的 ProxyConnector 來設置 SOCKS 代理,代碼如下:
運行結果是一樣的。
另外這個庫還支持設置 SOCKS4、HTTP 代理以及對應的代理認證,可以參考其官方介紹。
10.Pyppeteer 設置代理
對于 Pyppeteer 來說,由于其默認使用的是類似 Chrome 的 Chromium 瀏覽器,因此設置方法和 Selenium 的 Chrome 是一樣的,如 HTTP 無認證代理設置方法都是通過 args 來設置,實現如下:
import asyncio from pyppeteer import launchproxy = '127.0.0.1:7890'async def main():browser = await launch({'args': ['--proxy-server=http://' + proxy], 'headless': False})page = await browser.newPage()await page.goto('https://httpbin.org/get')print(await page.content())await browser.close()if __name__ == '__main__':asyncio.get_event_loop().run_until_complete(main())運行結果:
{"args": {},"headers": {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","Accept-Encoding": "gzip, deflate, br","Accept-Language": "zh-CN,zh;q=0.9","Host": "httpbin.org","Upgrade-Insecure-Requests": "1","User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3494.0 Safari/537.36","X-Amzn-Trace-Id": "Root=1-5e8f442c-12b1ed7865b049007267a66c"},"origin": "210.173.1.204","url": "https://httpbin.org/get" }同樣可以看到設置成功。
對于 SOCKS 代理,也是一樣的,只需要將協議修改為 socks5 即可,代碼實現如下:
import asyncio from pyppeteer import launchproxy = '127.0.0.1:7891'async def main():browser = await launch({'args': ['--proxy-server=socks5://' + proxy], 'headless': False})page = await browser.newPage()await page.goto('https://httpbin.org/get')print(await page.content())await browser.close()if __name__ == '__main__':asyncio.get_event_loop().run_until_complete(main())運行結果也是一樣的。
11.總結
以上總結了各個庫的代理使用方式,以后如果遇到封 IP 的問題,我們就可以輕松通過加代理的方式來解決啦。
本節代碼:https://github.com/Python3WebSpider/ProxyTest。
總結
以上是生活随笔為你收集整理的第20讲:代理的基本原理和用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第31讲:抓包利器 Charles 的使
- 下一篇: 第19讲:Pyppeteer 爬取实战