Python3 クローラーでは、プロキシの使用は IP ブロックの防止やクロール速度の向上によく使われる方法で、主に複数の IP アドレスからアクセスしているように見せるために使われます。プロキシは無料プロキシと有料プロキシに大きく分けられ、無料プロキシは不安定で、有料プロキシは比較的安定していて信頼性があります。
以下は Python3 クローラープロキシの利用シーンと用途です。
IP ブロックの防止:一部のサイトでは IP ごとのアクセス頻度制限が設けられており、回数が上限を超えるとその IP からのアクセスが禁止されます。プロキシを使えば、このような事態を避けられます。
クロール速度の向上:プロキシを使えば複数の接続を同時に確立できるため、対象データをすばやくクロールできます。
地域制限の回避:サイトによっては、地域ごとに提供するサービスが異なります。特定地域向けにのみ公開されているサイトへアクセスする必要がある場合、プロキシを使えばこの制限を回避し、必要なデータを取得できます。
要するに、プロキシIPは Python3 クローラーにおいて非常に重要な役割を果たします。ただし、プロキシの利用には一定のセキュリティ上の問題も伴うため、利用時には適切なプロキシサービスプロバイダーを選び、ネットワークセキュリティ規定を厳格に守る必要があります。
事前準備
まずは利用可能なプロキシを 1 つ用意する必要があります。プロキシとは IP アドレスとポートの組み合わせで、つまり IP:ポート という形式です。プロキシアクセスに認証が必要な場合は、さらにユーザー名とパスワードの 2 つの情報が必要です。
ここでは、私のローカル環境にプロキシソフトを 1 つインストールしてあり、ローカルの 7890 ポートに HTTP プロキシサービス、つまり 127.0.0.1:7890 を作成しています。また、このソフトは 7891 ポートに SOCKS プロキシサービス、つまり 127.0.0.1:7891 も作成します。そのため、このプロキシを設定するだけで、ローカルマシンの IP を、そのプロキシソフトが接続しているサーバーの IP に切り替えられます。
以下のサンプルでは、上記のプロキシを使って設定方法を説明します。必要に応じて、自分で使えるプロキシに置き換えてください。
プロキシ設定後、テスト用の URL は http://httpbin.org/get です。このリンクにアクセスすると、リクエストに関する情報を取得できます。返された結果の origin フィールドがクライアントの IP なので、それを見ればプロキシ設定が成功したか、つまり IP の偽装に成功したかを判断できます。
では次に、各リクエストライブラリでのプロキシ設定方法を見ていきましょう。
Python3 クローラープロキシを取得する
一部のサイトは、自サイトのデータに対する頻繁なアクセスを検知し、それを阻止する対策を取ります。プロキシサーバーを使えばアクセス元を分散できるため、検知される可能性を下げ、クロール成功率を高められます。
最適な米国静的プロキシIP
IPRoyalは中国地域に非常に親和的なプロキシサービスプロバイダーであり、その住宅プロキシソリューションは非常に魅力的です
IPRoyalを見る
最も安い静的プロキシ
Proxy-seller はデータセンタープロキシのプロバイダーであり、多くの小規模なインターネットマーケターに人気があります。
Proxy-sellerを見る
最もお手頃な静的プロキシ
Shifter.io は、プライバシー保護とより良いインターネット体験をユーザーに提供することを目的とした、よく知られたプロキシサービスプロバイダーです。
Shifter.ioを見る
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: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、password が 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
ここではローカルで 7891 ポート上に SOCKS5 プロキシを起動する必要があります。正常に起動すれば、上の 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: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)
ここでは追加でパッケージを 1 つインストールする必要があります 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 プロキシを設定でき、実行結果はまったく同じです。1 つ目の方法と比べると、こちらはグローバル設定になります。状況に応じて使い分けるとよいでしょう。
4. 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 オブジェクトに SyncProxyTransport ではなく AsyncProxyTransport を使い、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: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 プロキシ、およびそれらに対応するプロキシ認証の設定にも対応しています。詳しくは公式説明を参照してください。
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 でも認証付きプロキシをとても簡単に設定できます。
9. まとめ
以上で、各リクエストライブラリにおけるプロキシの使い方を整理しました。ライブラリごとに設定方法は大きく変わらないため、これらの方法を身につけておけば、今後 IP ブロックの問題に遭っても、簡単にプロキシ追加で解決できるようになります。
異なる地域にあるプロキシサーバーを使うことで、別々の地域からクロールしているように見せかけ、特定エリアのデータを取得できます。これは地域関連データを収集する必要があるタスクで非常に有用です。プロキシサーバーを使えば、クローラーの実際の IP アドレスを隠せるため、サイトによるアクセス禁止や頻度制限を避けやすくなります。これはプライバシーと安全の保護にも役立ちます。一部のサイトは、同一 IP アドレスからの過剰なリクエストを検知して遮断することでクローラーを防いでいます。プロキシサーバーを使えば、この種のアンチクローリング対策を回避し、より高速かつ高い成功率でデータをクロールできます。