请求拦截

很多时候,我们其实需要对请求进行拦截,比如添加自定义请求头等操作,但是,Selenium 原生不提供请求拦截功能。因此,我们只能另辟渠道。

目前使用最多的应该是通过代理服务器对请求进行拦截,因为 Selenium 提供了设置代理的功能,这样就很好地对请求,甚至是响应(其实通过代理基本上什么都能弄,包括上面讲述的 巧用 Cookie _)进行拦截修改。

这里本人使用的代理库为:BrowserMob Proxy

将 BMP 设置为浏览器代理,这样 BMP 就可以对浏览器的所有请求和响应进行捕获,并且也可以将捕获的数据保存到 HAR 文件中,方便查看全部请求过程。
同时,BMP 提供了独立的代理服务,我们可以通过 RESTful API 设置代理服务器。
而如果想扩展更多的功能,BMP 还可以嵌入到我们的代码中进行调用,尤其是结合到 Selenium 代码中非常好用。

这里我们就直接以例子进行讲解,介绍下如何为 Selenium 请求添加自定义头部。

为了能有更大的扩展性,我们就通过代码来进行实现。

:BMP 的独立使用方法可以移步到 附录 区进行查看。

:由于 BMP 是采用 Java 代码进行编写,而我们这里是使用 Python 代码,所以我们这里无法直接将 BMP 嵌入到我们代码中使用。
我这边的做法是新开一个 Java 工程,然后调用 BMP 接口,创建一个代理服务器,具体过程如下所示:

  1. 首先创建一个普通的 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

 

posted @ 2022-08-22 12:54  云long  阅读(607)  评论(0编辑  收藏  举报