使用 Selenium 结合隧道代理(尤其是动态/轮转代理)做爬虫,能有效解决 IP 被封禁的问题,但会带来明显的性能开销和配置复杂性。
隧道代理确实能解决IP封锁问题,但Selenium这种浏览器自动化工具和代理结合会有特殊痛点。最明显的就是性能损耗——每个请求都要走代理隧道,浏览器渲染本身又慢,两者叠加可能让速度难以接受。不过用户没提具体场景,或许大家更在意稳定性而非速度?
如果大家在Selenium程序运行经常出现如下问题,需要重点关注如下:
1、提示弹窗要求手动输入用户名和密码的问题:
注意选择浏览器版本对应的demo,例如Chrome版本>=92,注意看demo的标题进行选择。
注意浏览器版本和浏览器驱动要一致,例如:100版本的需要下载对于100版本的driver.
2、临时文件存放目录权限错误的问题:
注意设置临时文件存放目录权限,例如 plugin_path = r’/tmp/{}_{}@t.16yun.zip’,该文件用于临时存放用户名和密码,如果目录不存在运行也会提示错误,或者提示弹窗要求手动输入用户名和密码。
3、程序运行被目标网站识别的问题:
设置运行模式(防止被网站反爬),如果浏览器正常运行下,navigator.webdriver的值应该是undefined或者false,如果为true目标网站能检测到selenium,设置为开发者模式,可以防止目标网站识别。
问题解决方案
1、代理认证弹窗问题(要求手动输入用户名密码)
原因:浏览器未正确加载代理认证插件或插件配置错误
解决方案:
from selenium import webdriver
import zipfile
import os
# 创建代理认证扩展插件
def create_proxy_extension(proxy_host, proxy_port, proxy_user, proxy_pass):
manifest_json = """
{
"version": "1.0.0",
"manifest_version": 2,
"name": "16YUN Proxy",
"permissions": ["proxy", "tabs", "unlimitedStorage", "storage"],
"background": {"scripts": ["background.js"]},
"minimum_chrome_version": "76.0.0"
}
"""
background_js = """
var config = {
mode: "fixed_servers",
rules: {
singleProxy: {
scheme: "http",
host: "%s",
port: parseInt(%s)
},
bypassList: ["localhost"]
}
};
chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});
function callbackFn(details) {
return {
authCredentials: {
username: "%s",
password: "%s"
}
};
}
chrome.webRequest.onAuthRequired.addListener(
callbackFn,
{urls: ["<all_urls>"]},
['blocking']
);
""" % (proxy_host, proxy_port, proxy_user, proxy_pass)
# 创建临时目录
ext_dir = os.path.join(os.getcwd(), 'proxy_extension')
os.makedirs(ext_dir, exist_ok=True)
# 写入文件
with open(os.path.join(ext_dir, "manifest.json"), "w") as f:
f.write(manifest_json)
with open(os.path.join(ext_dir, "background.js"), "w") as f:
f.write(background_js)
# 打包扩展
ext_path = os.path.join(os.getcwd(), "proxy_auth_extension.zip")
with zipfile.ZipFile(ext_path, "w") as zp:
zp.write(os.path.join(ext_dir, "manifest.json"), "manifest.json")
zp.write(os.path.join(ext_dir, "background.js"), "background.js")
return ext_path
# 使用示例
proxy_extension = create_proxy_extension(
proxy_host="t.16yun.cn",
proxy_port="31111",
proxy_user="YOUR_USERNAME",
proxy_pass="YOUR_PASSWORD"
)
options = webdriver.ChromeOptions()
options.add_extension(proxy_extension)
driver = webdriver.Chrome(options=options)
关键点:
1、Chrome版本≥92时需使用manifest V3格式(上述代码为V2)
2、确保插件目录权限正确(Windows需管理员权限,Linux/Mac设chmod 755
)
3、浏览器驱动与浏览器版本严格匹配(chromedriver下载页)
2、临时文件目录权限问题
解决方案:
import tempfile
# 安全创建临时目录
def create_temp_dir():
temp_dir = tempfile.mkdtemp(prefix="selenium_proxy_")
os.chmod(temp_dir, 0o755) # 设置权限
return temp_dir
# 使用示例
plugin_path = os.path.join(create_temp_dir(), "proxy_auth.zip")
预防措施:
1、避免使用系统保护区(如C:\Windows
,/root
)
2、定期清理旧临时文件:
import shutil
shutil.rmtree(temp_dir) # 使用后清理
3、使用绝对路径而非相对路径
3、反爬检测识别问题
解决方案:
options = webdriver.ChromeOptions()
# 基础反检测设置
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
# 高级隐身设置
options.add_argument("--disable-infobars")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
options.add_argument("--disable-extensions")
options.add_argument("--disable-popup-blocking")
options.add_argument("--ignore-certificate-errors")
options.add_argument("--start-maximized")
# 修改WebDriver属性
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
window.navigator.chrome = { runtime: {} };
"""
})
# 随机化User-Agent
from fake_useragent import UserAgent
ua = UserAgent()
options.add_argument(f"user-agent={ua.random}")
# 使用代理IP池(示例)
proxy_list = [
"http://user:pass@ip1:port",
"http://user:pass@ip2:port"
]
options.add_argument(f'--proxy-server={random.choice(proxy_list)}')
增强隐身技巧:
1、鼠标轨迹模拟:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
actions.move_by_offset(random.randint(5,15), random.randint(5,15)).perform()
2、页面加载策略:
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
caps = DesiredCapabilities.CHROME
caps["pageLoadStrategy"] = "eager" # 不等待完整加载
3、禁用自动化特征:
options.add_argument("--disable-blink-features")
options.add_argument("--disable-web-security")
最佳实践总结
1、版本管理:
-
使用
webdriver-manager
自动匹配驱动版本:from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverManager().install())
2、异常处理:
from selenium.common.exceptions import WebDriverException
try:
driver.get(url)
except WebDriverException as e:
if "proxy" in str(e).lower():
refresh_proxy() # 重新获取代理
3、综合配置模板:
def create_stealth_driver():
options = webdriver.ChromeOptions()
# 代理设置
options.add_extension(create_proxy_extension(...))
# 反检测设置
options.add_argument("--disable-blink-features=AutomationControlled")
# 无头模式配置
options.add_argument("--headless=new")
options.add_argument("--window-size=1920,1080")
# 创建驱动
driver = webdriver.Chrome(options=options)
# WebDriver属性覆盖
driver.execute_cdp_cmd(...)
return driver
4、调试工具:
-
检查
navigator.webdriver
属性:console.log(navigator.webdriver) // 应为undefined
-
检测WebGL渲染器:
document.createElement('canvas').getContext('webgl').getParameter(37445)
重要提示:隧道代理需定期更换IP(建议每5-10个请求更换),并使用商业级代理服务(如Luminati、Oxylabs等)避免IP被封。