请求拦截
很多时候,我们其实需要对请求进行拦截,比如添加自定义请求头等操作,但是,Selenium 原生不提供请求拦截功能。因此,我们只能另辟渠道。
目前使用最多的应该是通过代理服务器对请求进行拦截,因为 Selenium 提供了设置代理的功能,这样就很好地对请求,甚至是响应(其实通过代理基本上什么都能弄,包括上面讲述的 巧用 Cookie _)进行拦截修改。
这里本人使用的代理库为:BrowserMob Proxy。
将 BMP 设置为浏览器代理,这样 BMP 就可以对浏览器的所有请求和响应进行捕获,并且也可以将捕获的数据保存到 HAR 文件中,方便查看全部请求过程。
同时,BMP 提供了独立的代理服务,我们可以通过 RESTful API 设置代理服务器。
而如果想扩展更多的功能,BMP 还可以嵌入到我们的代码中进行调用,尤其是结合到 Selenium 代码中非常好用。
这里我们就直接以例子进行讲解,介绍下如何为 Selenium 请求添加自定义头部。
为了能有更大的扩展性,我们就通过代码来进行实现。
注:BMP 的独立使用方法可以移步到 附录 区进行查看。
注:由于 BMP 是采用 Java 代码进行编写,而我们这里是使用 Python 代码,所以我们这里无法直接将 BMP 嵌入到我们代码中使用。
我这边的做法是新开一个 Java 工程,然后调用 BMP 接口,创建一个代理服务器,具体过程如下所示:
- 首先创建一个普通的 Maven Java 工程,如下图所示:
2.在 pom.xml 中导入 BMP 依赖,如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0"> <!-- ... --> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>net.lightbody.bmp</groupId> <artifactId>browsermob-core</artifactId> <version>2.1.5</version> </dependency> </dependencies> </project>
3.使用以下代码生成证书、密钥和公钥(为了支持 HTTPS 代理):
// 证书存放在 E:\\cert 目录中 private static void generateRootCertificate(){ // create a CA Root Certificate using default settings RootCertificateGenerator rootCertificateGenerator = RootCertificateGenerator.builder().build(); // save the newly-generated Root Certificate and Private Key -- the .cer file can be imported // directly into a browser rootCertificateGenerator.saveRootCertificateAsPemFile(new File("E:\\cert\\certificate.cer")); rootCertificateGenerator.savePrivateKeyAsPemFile(new File("E:\\cert\\private-key.pem"), "password"); // or save the certificate and private key as a PKCS12 keystore, for later use rootCertificateGenerator.saveRootCertificateAndKey("PKCS12", new File("E:\\cert\\keystore.p12"), "privateKeyAlias", "password"); }
-
注:代码生成证书的详细内容,请参考:mitm module
注:也可以直接下载 BMP 提供的证书:ca-certificate-rsa.cer
但是还是建议使用代码生成证书,这样更加安全。
4.为 Chrome 浏览器添加上一步生成的证书,具体步骤如下所示:
- 打开页面:
chrome://settings/?search=certificate
,找到Manage certificates
条目 - 点击
Manage certificates
条目,弹出证书导入框,选择Trusted Root Certification Authorities
标签 - 选择
Import
按钮,导入我们生成的证书。
对于上述代码,我们生成的证书路径为:E:\cert\certificate.cer
5.编写代码,创建代理服务器,具体代码如下:
public class ProxyServer { public static void main(String[] args) { // ProxyServer.generateRootCertificate(); BrowserMobProxy proxy = new BrowserMobProxyServer(); // 代理服务器配置证书公钥(不是代码自动生成的证书可以不用进行设置) proxy.setMitmManager(ProxyServer.configKeystore()); // 全局自定义请求头 proxy.addHeader("MyHeader", "This is a customed global header"); // 请求拦截器 proxy.addRequestFilter(new RequestFilter() { @Override public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) { System.out.println("filter Reqeust => " + messageInfo.getOriginalUrl()); // 拦截请求,添加请求头 request.headers().add("FilterHeader", "This is a filter header"); return null; } }); // 响应拦截器 proxy.addResponseFilter(new ResponseFilter() { @Override public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) { System.out.println("filter rEsponse......"); } }); // 启动代理服务器 proxy.start(0); // 获取代理服务器端口 int port = proxy.getPort(); // get the JVM-assigned port System.out.println("proxy server running on port " + port); } // 获取公钥内容 private static ImpersonatingMitmManager configKeystore() { CertificateAndKeySource existingCertificateSource = new KeyStoreFileCertificateSource("PKCS12", new File("E:\\cert\\keystore.p12"), "privateKeyAlias", "password"); // configure the MitmManager to use the custom KeyStore source ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder() .rootCertificateSource(existingCertificateSource) .build(); return mitmManager; } }
-
注:上述代码我们通过
proxy.addHeader(..)
增加了一个全局请求头:MyHeader: This is a customed global header
,
通过在请求拦截器中增加了一个请求头:FilterHeader: This is a filter header
6.执行上述代码,启动代理服务器,从输入内容中可以查看到代理服务器的端口号,如下图所示:
7.Selenium 配置代理,如下代码所示:
# 注意端口号 PROXY = '127.0.0.1:3582' # 设置代理 webdriver.DesiredCapabilities.CHROME['proxy'] = { 'httpProxy': PROXY, 'sslProxy': PROXY, "proxyType": "MANUAL", } driver = webdriver.Chrome() driver.get('https://httpbin.org/headers') print(driver.page_source)
https://www.jianshu.com/p/0356a7bf833a