7

【2022 年】Python3 爬虫教程 - 代理的使用方法

 2 years ago
source link: https://cuiqingcai.com/2022102.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前面我们介绍了多种请求库,如 urllib、requests、Selenium、Playwright 等用法,但是没有统一梳理代理的设置方法,本节我们来针对这些库来梳理下代理的设置方法。

1. 准备工作

在本节开始之前,请先根据上一节了解一下代理的基本原理,了解了基本原理之后我们可以更好地理解和学习本节的内容。

另外我们需要先获取一个可用代理,代理就是 IP 地址和端口的组合,就是 <ip>:<port> 这样的格式。如果代理需要访问认证,那就还需要额外的用户名密码两个信息。

那怎么获取一个可用代理呢?

使用搜索引擎搜索 “代理” 关键字,可以看到许多代理服务网站,网站上会有很多免费或付费代理,比如快代理的免费 HTTP 代理:https://www.kuaidaili.com/free/ 上面就写了很多免费代理,但是这些免费代理大多数情况下并不一定稳定,所以比较靠谱的方法是购买付费代理。付费代理的各大代理商家都有套餐,数量不用多,稳定可用即可,我们可以自行选购。

另外除了购买付费 HTTP 代理,我们也可以在本机配置一些代理软件,具体的配置方法可以参考 https://setup.scrape.center/proxy-client,软件运行之后会在本机创建 HTTP 或 SOCKS 代理服务,所以代理地址一般都是 127.0.0.1:<port> 这样的格式,不同的软件用的端口可能不同。

这里我的本机安装了一部代理软件,它会在本地 7890 端口上创建 HTTP 代理服务,即代理为 127.0.0.1:7890。另外,该软件还会在 7891 端口上创建 SOCKS 代理服务,即代理为 127.0.0.1:7891,所以只要设置了这个代理,就可以成功将本机 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: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)

运行结果如下:

{
"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"
}

这里我们需要借助 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:[email protected]: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:[email protected]: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,代理设置成功。

3.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)

运行结果如下:

{
"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"
}

和 urllib 一样,当请求的链接是 HTTP 协议的时候,会使用 http 键名对应的代理,当请求的链接是 HTTPS 协议的时候,会使用 https 键名对应的代理,不过这里统一使用了 HTTP 协议的代理。

运行结果中的 origin 若是代理服务器的 IP,则证明代理已经设置成功。

如果代理需要认证,那么在代理的前面加上用户名和密码即可,代理的写法就变成如下所示:

proxy = 'username:[email protected]: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 代理,运行结果完全相同。相比第一种方法,此方法是全局设置的。我们可以在不同情况下选用不同的方法。

4. 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:[email protected]: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 对象,其他的不变,运行结果是一样的。

5. 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 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()

运行结果是一样的。

6.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:[email protected]: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 代理以及对应的代理认证,可以参考其官方介绍。

7. 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())

运行结果也是一样的。

8. 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 实现认证代理的设置。

以上我们就总结了各个请求库的代理使用方式,各种库的设置方法大同小异,学会了这些方法之后,以后如果遇到封 IP 的问题,我们可以轻松通过加代理的方式来解决。

本节代码:https://github.com/Python3WebSpider/ProxyTest


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK