準備工作
需要先獲取一個可用代理,代理就是 IP 地址和埠的組合,就是 <ip>:<port>
這樣的格式。如果代理需要訪問認證,那就還需要額外的使用者名稱密碼兩個資訊。
那怎麼獲取一個可用代理呢?
使用搜尋引擎搜尋 “代理” 關鍵字,可以看到許多代理服務網站,網站上會有很多免費或付費代理,比如快代理的免費 HTTP 代理:https://www.kuaidaili.com/free/ 上面就寫了很多免費代理,但是這些免費代理大多數情況下並不一定穩定,所以比較靠譜的方法是購買付費代理。付費代理的各大代理商家都有套餐,數量不用多,穩定可用即可,可以自行選購。
另外除了購買付費 HTTP 代理,也可以在本機配置一些代理軟體,軟體執行之後會在本機建立 HTTP 或 SOCKS 代理服務,所以代理地址一般都是 127.0.0.1:<port>
這樣的格式,不同的軟體用的埠可能不同。
設定代理後,測試的網址是 http://httpbin.org/get,訪問該連結可以得到請求的相關資訊,其中返回結果的 origin
欄位就是客戶端的 IP,我們可以根據它來判斷代理是否設定成功,即是否成功偽裝了 IP。
好,接下來我們就來看下各個請求庫的代理設定方法吧。
urllib
以最基礎的 urllib 為例,來看一下代理的設定方法,程式碼如下:
from urllib.error import URLError from urllib.request import ProxyHandler, build_opener proxy = '127.0.0.1:7890' proxy_handler = ProxyHandler({ 'http': 'http://' + proxy, 'https': 'http://' + proxy }) opener = build_opener(proxy_handler) try: response = opener.open('https://httpbin.org/get') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
這裡需要藉助 ProxyHandler 設定代理,引數是字典型別,鍵名為協議型別,鍵值是代理。注意,此處代理前面需要加上協議,即 http://
或者 https://
,當請求的連結是 HTTP 協議的時候,會使用 http 鍵名對應的代理,當請求的連結是 HTTPS 協議的時候,會使用 https 鍵名對應的代理。不過這裡把代理本身設定為了 HTTP 協議,即字首統一設定為了 http://
,所以不論訪問 HTTP 還是 HTTPS 協議的連結,都會使用配置的 HTTP 協議的代理進行請求。
建立完 ProxyHandler 物件之後,需要利用 build_opener 方法傳入該物件來建立一個 Opener,這樣就相當於此 Opener 已經設定好代理了。接下來直接呼叫 Opener 物件的 open 方法,即可訪問所想要的連結。
執行結果:
執行輸出結果是一個 JSON,它有一個欄位 origin,標明瞭客戶端的 IP。驗證一下,此處的 IP 確實為代理的 IP,並不是真實的 IP。這樣就成功設定好代理,並可以隱藏真實 IP 了。
如果遇到需要認證的代理,可以用如下的方法設定:
from urllib.error import URLError from urllib.request import ProxyHandler, build_opener proxy = 'username:password@127.0.0.1:7890' proxy_handler = ProxyHandler({ 'http': 'http://' + proxy, 'https': 'http://' + proxy }) opener = build_opener(proxy_handler) try: response = opener.open('https://httpbin.org/get') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
這裡改變的只是 proxy 變數,只需要在代理前面加入代理認證的使用者名稱密碼即可,其中 username 就是使用者名稱,password 為密碼,例如 username 為 foo,密碼為 bar,那麼代理就是 foo:bar@127.0.0.1:7890
。
如果代理是 SOCKS5 型別,那麼可以用如下方式設定代理:
import socks import socket from urllib import request from urllib.error import URLError socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 7891) socket.socket = socks.socksocket try: response = request.urlopen('https://httpbin.org/get') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
此處需要一個 socks 模組,可以透過如下命令安裝:
pip3 install PySocks
這裡需要本地執行一個 SOCKS5 代理,執行在 7891 埠,執行成功之後和上文 HTTP 代理輸出結果是一樣的:
{ "args": {}, "headers": { "Accept-Encoding": "identity", "Host": "httpbin.org", "User-Agent": "Python-urllib/3.7", "X-Amzn-Trace-Id": "Root=1-60e9a1b6-0a20b8a678844a0b2ab4e889" }, "origin": "210.173.1.204", "url": "https://httpbin.org/get" }
結果的 origin 欄位同樣為代理的 IP,代理設定成功。
requests 的代理設定
對於 requests 來說,代理設定非常簡單,只需要傳入 proxies
引數即可。
以本機的代理為例,來看下 requests 的 HTTP 代理設定,程式碼如下:
import requests proxy = '127.0.0.1:7890' proxies = { 'http': 'http://' + proxy, 'https': 'http://' + proxy, } try: response = requests.get('https://httpbin.org/get', proxies=proxies) print(response.text) except requests.exceptions.ConnectionError as e: print('Error', e.args)
執行結果:
和 urllib 一樣,當請求的連結是 HTTP 協議的時候,會使用 http 鍵名對應的代理,當請求的連結是 HTTPS 協議的時候,會使用 https 鍵名對應的代理,不過這裡統一使用了 HTTP 協議的代理。
執行結果中的 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 代理,執行結果完全相同。相比第一種方法,此方法是全域性設定的。我們可以在不同情況下選用不同的方法。
httpx 的代理設定
httpx 的用法本身就與 requests 的使用非常相似,所以其也是透過 proxies 引數來設定代理的,不過與 requests 不同的是,proxies 引數的鍵名不能再是 http
或 https
,而需要更改為 http://
或 https://
,其他的設定是一樣的。
對於 HTTP 代理來說,設定方法如下:
import httpx proxy = '127.0.0.1:7890' proxies = { 'http://': 'http://' + proxy, 'https://': 'http://' + proxy, } with httpx.Client(proxies=proxies) as client: response = client.get('https://httpbin.org/get') print(response.text)
對於需要認證的代理,也是改下 proxy 的值即可:
proxy = 'username:password@127.0.0.1:7890'
這裡只需要將 username
和 password
替換即可。
執行結果和使用 requests 是類似的,結果如下:
{ "args": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "httpbin.org", "User-Agent": "python-httpx/0.18.1", "X-Amzn-Trace-Id": "Root=1-60e9a3ef-5527ff6320484f8e46d39834" }, "origin": "210.173.1.204", "url": "https://httpbin.org/get" }
對於 SOCKS 代理,需要安裝 httpx-socks 庫,安裝方法如下:
pip3 install "httpx-socks[asyncio]"
這樣會同時安裝同步和非同步兩種模式的支援。
對於同步模式,設定方法如下:
import httpx from httpx_socks import SyncProxyTransport transport = SyncProxyTransport.from_url( 'socks5://127.0.0.1:7891') with httpx.Client(transport=transport) as client: response = client.get('https://httpbin.org/get') print(response.text)
這裡需要設定一個 transport 物件,並配置 SOCKS 代理的地址,同時在宣告 httpx 的 Client 物件的時候傳入 transport 引數即可,執行結果和剛才是一樣的。
對於非同步模式,設定方法如下:
import httpx import asyncio from httpx_socks import AsyncProxyTransport transport = AsyncProxyTransport.from_url( 'socks5://127.0.0.1:7891') async def main(): async with httpx.AsyncClient(transport=transport) as client: response = await client.get('https://httpbin.org/get') print(response.text) if __name__ == '__main__': asyncio.get_event_loop().run_until_complete(main())
和同步模式不同的是,transport 物件用的是 AsyncProxyTransport 而不是 SyncProxyTransport,同時需要將 Client 物件更改為 AsyncClient 物件,其他的不變,執行結果是一樣的。
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()
執行結果如下:
<html><head><meta name="color-scheme" content="light dark"><meta charset="utf-8"></head><body><pre>{ "args": {}, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding": "gzip, deflate, br, zstd", "Accept-Language": "zh-CN,zh;q=0.9", "Host": "httpbin.org", "Priority": "u=0, i", "Sec-Ch-Ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"", "Sec-Ch-Ua-Mobile": "?0", "Sec-Ch-Ua-Platform": "\"Windows\"", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", "X-Amzn-Trace-Id": "Root=1-6690195d-568a877b46d33cea5922e611" }, "origin": "188.253.4.231", "url": "https://httpbin.org/get" } </pre><div class="json-formatter-container"></div></body></html>
代理設定成功,origin
同樣為代理 IP 的地址。
如果代理是認證代理,則設定方法相對比較繁瑣,具體如下所示:
from selenium import webdriver from selenium.webdriver.chrome.options import Options import zipfile ip = '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 webdriver proxy = '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()
執行結果是一樣的。
aiohttp 的代理設定
對於 aiohttp 來說,可以透過 proxy
引數直接設定。HTTP 代理設定如下:
import asyncio import aiohttp proxy = '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 代理,其程式碼如下:
import asyncio import aiohttp from aiohttp_socks import ProxyConnector connector = ProxyConnector.from_url('socks5://127.0.0.1:7891') async def main(): async with aiohttp.ClientSession(connector=connector) as session: async with session.get('https://httpbin.org/get') as response: print(await response.text()) if __name__ == '__main__': asyncio.get_event_loop().run_until_complete(main())
執行結果是一樣的。
另外,這個庫還支援設定 SOCKS4、HTTP 代理以及對應的代理認證,可以參考其官方介紹。
Pyppeteer 的代理設定
對於 Pyppeteer 來說,由於其預設使用的是類似 Chrome 的 Chromium 瀏覽器,因此其設定方法和 Selenium 的 Chrome 一樣,如 HTTP 無認證代理設定方法都是透過 args
來設定的,實現如下:
import asyncio from pyppeteer import launch proxy = '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 launch proxy = '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())
執行結果也是一樣的。
Playwright 的代理設定
相對 Selenium 和 Pyppeteer 來說,Playwright 的代理設定更加方便,其預留了一個 proxy 引數,可以在啟動 Playwright 的時候設定。
對於 HTTP 代理來說,可以這樣設定:
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(proxy={ 'server': 'http://127.0.0.1:7890' }) page = browser.new_page() page.goto('https://httpbin.org/get') print(page.content()) browser.close()
在呼叫 launch 方法的時候,可以傳一個 proxy 引數,是一個字典。字典有一個必填的欄位叫做 server,這裡我們可以直接填寫 HTTP 代理的地址即可。
執行結果:
{ "args": {}, "headers": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9", "Host": "httpbin.org", "Sec-Ch-Ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"92\"", "Sec-Ch-Ua-Mobile": "?0", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4498.0 Safari/537.36", "X-Amzn-Trace-Id": "Root=1-60e99eef-4fa746a01a38abd469ecb467" }, "origin": "210.173.1.204", "url": "https://httpbin.org/get" }
對於 SOCKS 代理,設定方法也是完全一樣的,只需要把 server 欄位的值換成 SOCKS 代理的地址即可:
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(proxy={ 'server': 'socks5://127.0.0.1:7891' }) page = browser.new_page() page.goto('https://httpbin.org/get') print(page.content()) browser.close()
執行結果和剛才也是完全一樣的。
對於有使用者名稱和密碼的代理,Playwright 的設定也非常簡單,只需要在 proxy 引數額外設定 username 和 password 欄位即可,假如使用者名稱和密碼分別是 foo 和 bar,則設定方法如下:
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(proxy={ 'server': 'http://127.0.0.1:7890', 'username': 'foo', 'password': 'bar' }) page = browser.new_page() page.goto('https://httpbin.org/get') print(page.content()) browser.close()
這樣就能非常方便地為 Playwright 實現認證代理的設定。