9.1 代理的設定
9.1 代理的設定
在前面我們介紹了多種請求庫,如 Requests、Urllib、Selenium 等。我們接下來首先貼近實戰,瞭解一下代理怎麼使用,為後面瞭解代理池、ADSL 撥號代理的使用打下基礎。
下面我們來梳理一下這些庫的代理的設定方法。
1. 獲取代理
做測試之前,我們需要先獲取一個可用代理。搜尋引擎搜尋 “代理” 關鍵字,就可以看到許多代理服務網站,網站上會有很多免費代理,比如西刺:http://www.xicidaili.com/。但是這些免費代理大多數情況下都是不好用的,所以比較靠譜的方法是購買付費代理。付費代理在很多網站上都有售賣,數量不用多,穩定可用即可,我們可以自行選購。
如果本機有相關代理軟體的話,軟體一般會在本機建立 HTTP 或 SOCKS 代理服務,本機直接使用此代理也可以。
在這裡,我的本機安裝了一部代理軟體,它會在本地 9743 埠上建立 HTTP 代理服務,即代理為 127.0.0.1:9743,另外還會在 9742 埠建立 SOCKS 代理服務,即代理為 127.0.0.1:9742。我只要設定了這個代理,就可以成功將本機 IP 切換到代理軟體連線的伺服器的 IP 了。
本章下面的示例裡,我使用上述代理來演示其設定方法,你也可以自行替換成自己的可用代理。設定代理後測試的網址是:http://httpbin.org/get,我們訪問該網址可以得到請求的相關資訊,其中 origin 欄位就是客戶端的 IP,我們可以根據它來判斷代理是否設定成功,即是否成功偽裝了 IP。
2. urllib
首先我們以最基礎的 urllib 為例,來看一下代理的設定方法,程式碼如下:
from urllib.error import URLError from urllib.request import ProxyHandler, build_opener proxy = '127.0.0.1:9743' proxy_handler = ProxyHandler({ 'http': 'http://' + proxy, 'https': 'https://' + proxy }) opener = build_opener(proxy_handler) try: response = opener.open('http://httpbin.org/get') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
執行結果如下:
{"args": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.6"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
這裡我們需要藉助 ProxyHandler 設定代理,引數是字典型別,鍵名為協議型別,鍵值是代理。注意,此處代理前面需要加上協議,即 http 或者 https。當請求的連結是 http 協議的時候,ProxyHandler 會呼叫 http 代理。當請求的連結是 https 協議的時候,會呼叫 https 代理。此處生效的代理是:http://127.0.0.1:9743。
建立完 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:[email protected]:9743'
proxy_handler = ProxyHandler({
'http': 'http://' + proxy,
'https': 'https://' + proxy
})
opener = build_opener(proxy_handler)
try:
response = opener.open('http://httpbin.org/get')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
這裡改變的只是 proxy 變數,只需要在代理前面加入代理認證的使用者名稱密碼即可,其中 username 就是使用者名稱,password 為密碼,例如 username 為 foo,密碼為 bar,那麼代理就是 foo:[email protected]:9743。
如果代理是 SOCKS5 型別,那麼可以用如下方式設定代理:
import socks
import socket
from urllib import request
from urllib.error import URLError
socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 9742)
socket.socket = socks.socksocket
try:
response = request.urlopen('http://httpbin.org/get')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
此處需要一個 socks 模組,可以通過如下命令安裝:
pip3 install PySocks
本地我有一個 SOCKS5 代理,執行在 9742 埠,執行成功之後和上文 HTTP 代理輸出結果是一樣的:
{"args": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.6"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
結果的 origin 欄位同樣為代理的 IP。現在,代理設定成功。
3. requests
對於 requests 來說,代理設定更加簡單,我們只需要傳入 proxies 引數即可。
還是以上例中的代理為例,我們來看下 requests 的代理的設定:
import requests
proxy = '127.0.0.1:9743'
proxies = {
'http': 'http://' + proxy,
'https': 'https://' + proxy,
}
try:
response = requests.get('http://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",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.18.1"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
可以發現,requests 的代理設定比 urllib 簡單很多,它只需要構造代理字典,然後通過 proxies 引數即可,而不需要重新構建 Opener。
其執行結果的 origin 也是代理的 IP,這證明代理已經設定成功。
如果代理需要認證,同樣在代理的前面加上使用者名稱密碼即可,代理的寫法就變成如下所示:
proxy = 'username:[email protected]:9743'
和 urllib 一樣,這裡只需要將 username 和 password 替換即可。
如果需要使用 SOCKS5 代理,則可以使用如下方式來設定:
import requests
proxy = '127.0.0.1:9742'
proxies = {
'http': 'socks5://' + proxy,
'https': 'socks5://' + proxy
}
try:
response = requests.get('http://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",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.18.1"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
另外,還有一種設定方式,和 urllib 中的方法相同,使用 socks 模組,也需要像上文一樣安裝 socks 庫。這種設定方法如下所示:
import requests
import socks
import socket
socks.set_default_proxy(socks.SOCKS5, '127.0.0.1', 9742)
socket.socket = socks.socksocket
try:
response = requests.get('http://httpbin.org/get')
print(response.text)
except requests.exceptions.ConnectionError as e:
print('Error', e.args)
使用這種方法也可以設定 SOCKS5 代理,執行結果完全相同。相比第一種方法,此方法是全域性設定。我們可以在不同情況下選用不同的方法。
4. Selenium
Selenium 同樣也可以設定代理,包括兩種方式:一種是有介面瀏覽器,以 Chrome 為例;另一種是無介面瀏覽器,以 PhantomJS 為例。
Chrome
對於 Chrome 來說,用 Selenium 設定代理的方法也非常簡單,設定方法如下所示:
from selenium import webdriver
proxy = '127.0.0.1:9743'
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--proxy-server=http://' + proxy)
browser = webdriver.Chrome(chrome_options=chrome_options)
browser.get('http://httpbin.org/get')
在這裡我們通過 ChromeOptions 來設定代理,在建立 Chrome 物件的時候用 chrome_options 引數傳遞即可。
執行程式碼之後便會彈出一個 Chrome 瀏覽器,我們訪問目標連結之後輸出結果如下所示:
{"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.8",
"Connection": "close",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
代理設定成功,origin 同樣為代理 IP 的地址。
如果代理是認證代理,則設定方法相對比較麻煩,設定方法如下所示:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import zipfile
ip = '127.0.0.1'
port = 9743
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)
chrome_options = Options()
chrome_options.add_argument("--start-maximized")
chrome_options.add_extension(plugin_file)
browser = webdriver.Chrome(chrome_options=chrome_options)
browser.get('http://httpbin.org/get')
這裡需要在本地建立一個 manifest.json 配置檔案和 background.js 指令碼來設定認證代理。執行程式碼之後本地會生成一個 proxy_auth_plugin.zip 檔案來儲存當前配置。
執行結果和上例一致,origin 同樣為代理 IP。
PhantomJS
對於 PhantomJS 來說,代理設定方法可以藉助 service_args 引數,也就是命令列引數。代理設定方法如下所示:
from selenium import webdriver
service_args = [
'--proxy=127.0.0.1:9743',
'--proxy-type=http'
]
browser = webdriver.PhantomJS(service_args=service_args)
browser.get('http://httpbin.org/get')
print(browser.page_source)
我們只需要使用 service_args 引數,將命令列的一些引數定義為列表,在初始化的時候傳遞給 PhantomJS 物件即可。
執行結果如下所示:
{"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en,*",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.0 Safari/538.1"
},
"origin": "106.185.45.153",
"url": "http://httpbin.org/get"
}
設定代理成功,執行結果的 origin 同樣為代理的 IP。
如果需要認證,那麼只需要再加入 --proxy-auth 選項即可,這樣引數就改為下面這樣:
service_args = [
'--proxy=127.0.0.1:9743',
'--proxy-type=http',
'--proxy-auth=username:password'
]
將 username 和 password 替換為認證所需的使用者名稱和密碼即可。
5. 本節程式碼
本節程式碼地址為:https://github.com/Python3WebSpider/ProxySettings。
6. 結語
本節介紹了前文所講的請求庫的代理設定方法,後面我們會使用這些方法來搭建代理池和爬取網站,可讓讀者進一步加深印象。