各位观众老爷,早上好(或者晚上好,取决于你啥时候看的),今天咱们来聊聊怎么自己动手定制代理规则,让你的网络世界更听话。我们主要讲讲用 JS FiddlerScript、Burp Extensions Python API 这几个工具,来玩转自定义代理,让你的爬虫更隐蔽,让你的测试更高效,让你的摸鱼……咳咳,总之,好处多多。
一、代理是个啥?为什么要自定义?
想象一下,你是一个特工,要秘密潜入敌方基地获取情报。直接冲进去肯定不行,太容易暴露。这时候就需要一个“中间人”,帮你伪装身份,传递信息。这个“中间人”就是代理。
代理服务器就像一个中转站,你的请求先发给代理服务器,再由代理服务器转发给目标服务器,目标服务器返回的数据也先到代理服务器,再由代理服务器返回给你。这样,目标服务器就不知道你的真实 IP 地址了。
为什么要自定义代理规则?
- 隐藏身份,防止被封: 爬虫抓取数据的时候,如果频率过高,或者行为过于明显,很容易被目标网站识别出来并封禁 IP。自定义代理规则可以让你轮换 IP,模拟不同的用户行为,降低被封的风险。
- 修改请求和响应: 有时候我们需要修改请求头、请求体,或者修改响应内容,才能更好地完成任务。自定义代理规则可以让你在请求和响应的传输过程中,拦截并修改数据。
- 自动化测试: 在进行 Web 应用测试的时候,我们需要模拟各种不同的场景,比如不同的用户角色、不同的网络环境等等。自定义代理规则可以帮助我们自动化这些测试场景。
- 模拟特定环境: 模拟手机、平板电脑等设备访问网站,方便调试移动端页面。
二、JS FiddlerScript:你的代理魔法棒
Fiddler 是一个强大的 HTTP 调试代理工具,它自带了一个叫做 FiddlerScript 的脚本引擎,可以让你用 JavaScript 来自定义代理规则。
1. FiddlerScript 的基本结构
FiddlerScript 的代码主要写在 OnBeforeRequest
和 OnBeforeResponse
这两个函数里面。
OnBeforeRequest
:在请求发送到目标服务器之前执行,可以修改请求。OnBeforeResponse
:在收到目标服务器的响应之后执行,可以修改响应。
2. 修改请求头
比如,我们要修改 User-Agent,模拟 Chrome 浏览器访问:
static function OnBeforeRequest(oSession: Session) {
oSession.oRequest["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
}
3. 修改请求体
假设我们要修改 POST 请求的参数:
static function OnBeforeRequest(oSession: Session) {
if (oSession.HTTPMethodIs("POST") && oSession.uriContains("example.com")) {
var body = oSession.GetRequestBodyAsString();
body = body.replace("old_value", "new_value"); // 替换请求体中的 old_value 为 new_value
oSession.utilSetRequestBody(body);
}
}
4. 修改响应内容
我们可以修改 HTML 页面,插入一段 JavaScript 代码:
static function OnBeforeResponse(oSession: Session) {
if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "text/html")) {
oSession.utilDecodeResponse(); // 解码响应
oSession.utilReplaceInResponse("</body>", "<script>alert('Hello from Fiddler!');</script></body>"); // 在 </body> 标签前插入 JavaScript 代码
}
}
5. 自动重定向
static function OnBeforeRequest(oSession: Session) {
if (oSession.uriContains("old_url.com")) {
oSession.Redirect("http://new_url.com");
}
}
6. 使用代理服务器
static function OnBeforeRequest(oSession: Session) {
if (oSession.uriContains("target_url.com")) {
oSession["x-overrideGateway"] = "http://proxy_ip:proxy_port"; // 设置代理服务器
}
}
7. FiddlerScript 常用函数
函数名 | 功能 |
---|---|
oSession.HTTPMethodIs() |
判断请求方法是否为指定类型 (GET, POST, PUT, DELETE 等) |
oSession.uriContains() |
判断 URL 是否包含指定字符串 |
oSession.utilDecodeResponse() |
解码响应内容 (gzip, deflate 等) |
oSession.utilSetRequestBody() |
设置请求体 |
oSession.utilReplaceInResponse() |
在响应内容中替换字符串 |
oSession.Redirect() |
重定向到指定的 URL |
oSession["x-overrideGateway"] |
设置代理服务器 |
oSession.hostname |
获取主机名 |
oSession.fullUrl |
获取完整URL |
三、Burp Extensions Python API:Python 大法的力量
Burp Suite 是一个专业的 Web 安全测试工具,它支持通过 Python 编写扩展,自定义代理规则。
1. Burp Extension 的基本结构
一个 Burp Extension 至少需要实现 IBurpExtender
接口,并实现 registerExtenderCallbacks
方法。
from burp import IBurpExtender, IHttpListener
from java.io import PrintWriter
class BurpExtender(IBurpExtender, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self._stdout = PrintWriter(callbacks.getStdout(), True)
# 设置扩展的名称
callbacks.setExtensionName("My Custom Proxy")
# 注册 HTTP Listener
callbacks.registerHttpListener(self)
self._stdout.println("Extension loaded successfully!")
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
# 在这里编写你的代理逻辑
pass
2. 修改请求头
from burp import IBurpExtender, IHttpListener
from java.io import PrintWriter
class BurpExtender(IBurpExtender, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self._stdout = PrintWriter(callbacks.getStdout(), True)
callbacks.setExtensionName("Modify User-Agent")
callbacks.registerHttpListener(self)
self._stdout.println("Extension loaded successfully!")
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
if messageIsRequest:
requestInfo = self._helpers.analyzeRequest(messageInfo)
headers = requestInfo.getHeaders()
url = requestInfo.getUrl()
# 修改 User-Agent
newHeaders = []
for header in headers:
if header.startswith("User-Agent:"):
newHeaders.append("User-Agent: My Custom User-Agent")
else:
newHeaders.append(header)
request = self._helpers.buildHttpMessage(newHeaders, messageInfo.getRequest()[requestInfo.getBodyOffset():])
messageInfo.setRequest(request)
self._stdout.println("Modified User-Agent for: " + str(url))
3. 修改请求体
from burp import IBurpExtender, IHttpListener
from java.io import PrintWriter
class BurpExtender(IBurpExtender, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self._stdout = PrintWriter(callbacks.getStdout(), True)
callbacks.setExtensionName("Modify Request Body")
callbacks.registerHttpListener(self)
self._stdout.println("Extension loaded successfully!")
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
if messageIsRequest:
requestInfo = self._helpers.analyzeRequest(messageInfo)
url = requestInfo.getUrl()
# 获取请求体
requestBodyBytes = messageInfo.getRequest()[requestInfo.getBodyOffset():]
requestBody = self._helpers.bytesToString(requestBodyBytes)
# 修改请求体
modifiedBody = requestBody.replace("old_value", "new_value")
# 构建新的请求
newRequest = self._helpers.buildHttpMessage(requestInfo.getHeaders(), self._helpers.stringToBytes(modifiedBody))
messageInfo.setRequest(newRequest)
self._stdout.println("Modified request body for: " + str(url))
4. 修改响应内容
from burp import IBurpExtender, IHttpListener
from java.io import PrintWriter
class BurpExtender(IBurpExtender, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
self._stdout = PrintWriter(callbacks.getStdout(), True)
callbacks.setExtensionName("Modify Response Body")
callbacks.registerHttpListener(self)
self._stdout.println("Extension loaded successfully!")
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
if not messageIsRequest:
requestInfo = self._helpers.analyzeRequest(messageInfo)
url = requestInfo.getUrl()
response = messageInfo.getResponse()
responseInfo = self._helpers.analyzeResponse(response)
# 获取响应体
responseBodyBytes = response[responseInfo.getBodyOffset():]
responseBody = self._helpers.bytesToString(responseBodyBytes)
# 修改响应体
modifiedBody = responseBody.replace("</body>", "<script>alert('Hello from Burp!');</script></body>")
# 构建新的响应
newResponse = self._helpers.buildHttpMessage(responseInfo.getHeaders(), self._helpers.stringToBytes(modifiedBody))
messageInfo.setResponse(newResponse)
self._stdout.println("Modified response body for: " + str(url))
5. 使用代理服务器(SOCKS)
Burp Suite 本身支持配置上游代理服务器,可以通过 Burp Suite 的设置界面配置。如果想在扩展中动态控制上游代理,相对复杂,需要涉及到 Java 的 Socket API,这里就不详细展开了。
6. Burp Extension 常用函数
函数名 | 功能 |
---|---|
callbacks.getHelpers() |
获取 IExtensionHelpers 对象,用于处理 HTTP 请求和响应 |
helpers.analyzeRequest(messageInfo) |
分析 HTTP 请求,返回 IRequestInfo 对象 |
helpers.analyzeResponse(response) |
分析 HTTP 响应,返回 IResponseInfo 对象 |
helpers.buildHttpMessage(headers, body) |
构建 HTTP 消息 (请求或响应) |
helpers.stringToBytes(string) |
将字符串转换为字节数组 |
helpers.bytesToString(bytes) |
将字节数组转换为字符串 |
messageInfo.getRequest() |
获取原始 HTTP 请求字节数组 |
messageInfo.getResponse() |
获取原始 HTTP 响应字节数组 |
messageInfo.setRequest() |
设置 HTTP 请求字节数组 |
messageInfo.setResponse() |
设置 HTTP 响应字节数组 |
requestInfo.getHeaders() |
获取请求头列表 |
requestInfo.getUrl() |
获取 URL 对象 |
requestInfo.getBodyOffset() |
获取请求体在原始请求中的起始位置 |
responseInfo.getHeaders() |
获取响应头列表 |
responseInfo.getBodyOffset() |
获取响应体在原始响应中的起始位置 |
四、 Python requests 结合代理池:爬虫的利器
Python 的 requests
库是爬虫的标配,结合代理池,可以让你更高效地抓取数据。
1. 基本用法
import requests
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
try:
response = requests.get('https://www.example.com', proxies=proxies, timeout=5)
response.raise_for_status() # 检查请求是否成功
print(response.text)
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
2. 代理池的实现
import requests
import random
# 代理列表,可以从免费代理网站获取,或者购买付费代理
proxy_list = [
'http://10.10.1.10:3128',
'http://10.10.1.11:3128',
'http://10.10.1.12:3128',
# ... 更多代理
]
def get_random_proxy():
"""从代理列表中随机选择一个代理"""
return {'http': random.choice(proxy_list), 'https': random.choice(proxy_list)}
def fetch_data(url):
"""使用代理抓取数据"""
try:
proxy = get_random_proxy()
response = requests.get(url, proxies=proxy, timeout=5)
response.raise_for_status()
return response.text
except requests.exceptions.RequestException as e:
print(f"使用代理 {proxy} 请求失败: {e}")
return None
# 示例
data = fetch_data('https://www.example.com')
if data:
print(data)
3. 代理验证
代理池中的代理可能不稳定,需要定期验证可用性。
import requests
import random
proxy_list = [
'http://10.10.1.10:3128',
'http://10.10.1.11:3128',
'http://10.10.1.12:3128',
# ... 更多代理
]
valid_proxies = []
def validate_proxy(proxy):
"""验证代理是否可用"""
try:
response = requests.get('https://www.example.com', proxies={'http': proxy, 'https': proxy}, timeout=5)
response.raise_for_status()
return True
except requests.exceptions.RequestException:
return False
# 验证代理列表
for proxy in proxy_list:
if validate_proxy(proxy):
valid_proxies.append(proxy)
print(f"代理 {proxy} 可用")
else:
print(f"代理 {proxy} 不可用")
def get_random_valid_proxy():
"""从可用代理列表中随机选择一个代理"""
if valid_proxies:
return {'http': random.choice(valid_proxies), 'https': random.choice(valid_proxies)}
else:
return None
# 使用可用代理抓取数据
def fetch_data_with_validated_proxy(url):
"""使用可用代理抓取数据"""
proxy = get_random_valid_proxy()
if proxy:
try:
response = requests.get(url, proxies=proxy, timeout=5)
response.raise_for_status()
return response.text
except requests.exceptions.RequestException as e:
print(f"使用代理 {proxy} 请求失败: {e}")
return None
else:
print("没有可用代理")
return None
data = fetch_data_with_validated_proxy('https://www.example.com')
if data:
print(data)
五、一些进阶技巧
- 模拟浏览器指纹: 除了 User-Agent,还可以修改其他请求头,比如 Accept、Accept-Language、Cookie 等,更逼真地模拟浏览器行为。
- 使用 Tor 代理: Tor 是一个匿名网络,可以提供更高级别的匿名性。
- 动态代理 IP: 购买动态代理 IP 服务,定期更换 IP 地址。
- 分布式代理: 搭建自己的代理服务器集群,提高代理的可用性和稳定性。
- 反爬虫策略: 了解目标网站的反爬虫策略,针对性地制定代理规则。比如,有些网站会检测请求的来源 IP 地址,如果短时间内来自同一个 IP 地址的请求过多,就会封禁该 IP 地址。
六、总结
自定义代理规则是一项非常有用的技能,可以让你更好地控制网络请求,提高爬虫的效率,增强 Web 应用的安全性,以及实现各种各样的自动化测试场景。无论是使用 JS FiddlerScript、Burp Extensions Python API,还是 Python requests 结合代理池,都可以实现自定义代理规则,关键在于理解其原理,灵活运用各种工具和技术。
好了,今天的讲座就到这里,希望对你有所帮助。记住,技术是把双刃剑,请合理使用,不要用于非法用途。下次有机会再见!