代理的設定

JJJhr發表於2024-07-12

準備工作

  需要先獲取一個可用代理,代理就是 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'

  這裡只需要將 usernamepassword 替換即可。

如果需要使用 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 引數的鍵名不能再是 httphttps,而需要更改為 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'

  這裡只需要將 usernamepassword 替換即可。

  執行結果和使用 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'

這裡只需要將 usernamepassword 替換即可。

對於 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 實現認證代理的設定。

相關文章