【问题标题】:Is there any way to start with a POST request using Selenium?有什么方法可以从使用 Selenium 的 POST 请求开始?
【发布时间】:2011-04-14 09:16:43
【问题描述】:

我正在尝试使用对我的应用程序的 POST 请求启动 Selenium 测试。

而不是简单的open(/startpoint)

我想做open(/startpoint, stuff=foo,stuff2=bar)之类的事情

有什么办法吗?

我之所以问这个问题是因为发布到此起点的原始页面取决于通常离线(开发环境)的外部提供商,因此通常会过早失败(并且不是测试的主题)


我想以 GET 方式发送数据也可以。我更喜欢使用 POST 方法。

【问题讨论】:

    标签: selenium


    【解决方案1】:

    如果您使用 Python selenium 绑定,现在有一个扩展名为 selenium - selenium-requests

    扩展 Selenium WebDriver 类以包含请求功能 来自 Requests 库,同时执行所有需要的 cookie 和 请求标头处理。

    例子:

    from seleniumrequests import Firefox
    
    webdriver = Firefox()
    response = webdriver.request('POST', 'url here', data={"param1": "value1"})
    print(response)
    

    【讨论】:

    • 这看起来很有希望,但是有一些问题,首先是如果我使用webdriver.request,它会打开一个新选项卡而不是现有选项卡,并在请求结束时关闭,其次它不会t 呈现预期的页面。例如:假设我发送了一个 GET 请求 webdriver.request('GET', 'http://example.com/some/path', data={'a':1,'b'=2} ,浏览器打开并只显示 http://example.com/ 而不是 http://example.com/some/path?a=1&b=2
    • @bawejakunal 但是发布请求呢?
    • 使用 chrome 发布请求,得到与@bawejakunal 相同的结果。这个答案无法解决我发布参数请求的问题。
    • C#有这样的东西吗?
    【解决方案2】:

    简短回答:不。

    但你也许可以通过一些肮脏的东西来做到这一点。如果您打开一个测试页面(使用 GET)然后评估该页面上的一些 JavaScript,您应该能够复制一个 POST 请求。请参阅 JavaScript post request like a form submit 了解如何在 JavaScript 中复制 POST 请求。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      一个非常实用的方法是为您的测试创建一个虚拟起始页,它只是一个带有 POST 的表单,它有一个“开始测试”按钮和一堆 <input type="hidden"... 带有适当的元素发布数据。

      例如,您可以创建一个包含以下内容的SeleniumTestStart.html 页面:

      <body>
        <form action="/index.php" method="post">
          <input id="starttestbutton" type="submit" value="starttest"/>
          <input type="hidden" name="stageid" value="stage-you-need-your-test-to-start-at"/>
        </form>
      </body>
      

      在本例中,index.php 是您的普通 Web 应用所在的位置。

      测试开始时的 Selenium 代码将包括:

      open /SeleniumTestStart.html
      clickAndWait starttestbutton
      

      这与自动化测试中使用的其他模拟和存根技术非常相似。您只是在模拟 Web 应用程序的入口点。

      显然这种方法有一些限制:

      1. 数据不能太大(例如图像数据)
      2. 安全性可能是个问题,因此您需要确保这些测试文件不会出现在您的生产服务器上
      3. 如果您需要在 Selenium 测试开始之前设置 cookie,您可能需要使用 php 而不是 html 之类的东西来创建入口点
      4. 一些 Web 应用程序会检查引荐来源网址以确保没有人入侵应用程序 - 在这种情况下,这种方法可能不起作用 - 您可以在开发环境中放松此检查,以便允许来自受信任主机的引荐来源网址(不是自己,而是实际的测试主机)

      请考虑阅读我关于Qualities of an Ideal Test的文章

      【讨论】:

      • 比其他答案更像测试。
      【解决方案4】:

      Selenium IDE 允许您使用 storeEval 命令运行 Javascript。如果您有测试页面(HTML,而不是 XML)并且您只需要执行 POST 请求,则上述解决方案可以正常工作。

      如果您需要发出 POST/PUT/DELETE 或任何其他请求,那么您将需要另一种方法:

      XMLHttpRequest

      下面列出的示例已经过测试 - 所有方法 (POST/PUT/DELETE) 都可以正常工作。

      <!--variables-->
      <tr>
          <td>store</td>
          <td>/your/target/script.php</td>
          <td>targetUrl</td>
      </tr>
      <tr>
          <td>store</td>
          <td>user=user1&amp;password</td>
          <td>requestParams</td>
      </tr>
      <tr>
          <td>store</td>
          <td>POST</td>
          <td>requestMethod</td>
      </tr>
      <!--scenario-->
      <tr>
          <td>storeEval</td>
          <td>window.location.host</td>
          <td>host</td>
      </tr>
      <tr>
          <td>store</td>
          <td>http://${host}</td>
          <td>baseUrl</td>
      </tr>
      <tr>
          <td>store</td>
          <td>${baseUrl}${targetUrl}</td>
          <td>absoluteUrl</td>
      </tr>
      <tr>
          <td>store</td>
          <td>${absoluteUrl}?${requestParams}</td>
          <td>requestUrl</td>
      </tr>
      <tr>
          <td>storeEval</td>
          <td>var method=storedVars['requestMethod']; var url = storedVars['requestUrl']; loadXMLDoc(url, method); function loadXMLDoc(url, method) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { if(xmlhttp.status==200) { alert(&quot;Results = &quot; + xmlhttp.responseText);} else { alert(&quot;Error!&quot;+ xmlhttp.responseText); }}};&nbsp;&nbsp;xmlhttp.open(method,url,true); xmlhttp.send(); }</td>
          <td></td>
      </tr>
      

      澄清:

      ${requestParams} - 您要发布的参数(例如 param1=value1&param2=value3&param1=value3) 您可以根据需要指定任意数量的参数

      ${targetUrl} - 脚本的路径(如果您的页面位于 http://domain.com/application/update.php,那么 targetUrl 应该等于 /application/update.php)

      ${requestMethod} - 方法类型(在这种特殊情况下,它应该是“POST”,但可以是“PUT”或“DELETE”或任何其他)

      【讨论】:

        【解决方案5】:

        Selenium 目前不为此提供 API,但有几种方法可以在您的测试中发起 HTTP 请求。这仅取决于您使用的语言。

        例如,在 Java 中,它可能如下所示:

        // setup the request
        String request = "startpoint?stuff1=foo&stuff2=bar";
        URL url = new URL(request);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        
        // get a response - maybe "success" or "true", XML or JSON etc.
        InputStream inputStream = connection.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        StringBuffer response = new StringBuffer();
        while ((line = bufferedReader.readLine()) != null) {
            response.append(line);
            response.append('\r');
        }
        bufferedReader.close();
        
        // continue with test
        if (response.toString().equals("expected response"){
            // do selenium
        }
        

        【讨论】:

        • 小心!。这只会获取页面源。它可能无法获取完全呈现的内容。使用 Selenium 的整个想法是获得完全呈现的页面。
        • @rinjan,同意。我假设OP知道这一点。根据这个问题,听起来他想从服务器获取一些数据或其他东西,然后再进行将使用该数据的实际测试。
        【解决方案6】:

        嗯,我同意@Mishkin Berteig - 敏捷教练的回答。使用表单是使用 POST 功能的快捷方式。

        无论如何,我看到一些关于 javascript 的提及,但没有代码。我有它以满足我自己的需要,其中包括用于简单 POST 的 jquery 以及其他。

        基本上,使用driver.execute_script() 您可以发送任何javascript,包括Ajax 查询。

        #/usr/local/env/python
        # -*- coding: utf8 -*-
        # proxy is used to inspect data involved on the request without so much code.
        # using a basic http written in python. u can found it there: http://voorloopnul.com/blog/a-python-proxy-in-less-than-100-lines-of-code/
        
        import selenium
        from selenium import webdriver
        import requests
        from selenium.webdriver.common.proxy import Proxy, ProxyType
        
        jquery = open("jquery.min.js", "r").read()
        #print jquery
        
        proxy = Proxy()
        proxy.proxy_type = ProxyType.MANUAL
        proxy.http_proxy = "127.0.0.1:3128"
        proxy.socks_proxy = "127.0.0.1:3128"
        proxy.ssl_proxy = "127.0.0.1:3128"
        
        capabilities = webdriver.DesiredCapabilities.PHANTOMJS
        proxy.add_to_capabilities(capabilities)
        
        driver = webdriver.PhantomJS(desired_capabilities=capabilities)
        
        driver.get("http://httpbin.org")
        driver.execute_script(jquery) # ensure we have jquery
        
        ajax_query = '''
                    $.post( "post", {
                        "a" : "%s",
                        "b" : "%s"
                    });
                    ''' % (1,2)
        
        ajax_query = ajax_query.replace(" ", "").replace("\n", "")
        print ajax_query
        
        result = driver.execute_script("return " + ajax_query)
        #print result
        
        #print driver.page_source
        
        driver.close()
        
        # this retuns that from the proxy, and is OK
        '''
        POST http://httpbin.org/post HTTP/1.1
        Accept: */*
        Referer: http://httpbin.org/
        Origin: http://httpbin.org
        X-Requested-With: XMLHttpRequest
        User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.0.0 Safari/538.1
        Content-Type: application/x-www-form-urlencoded; charset=UTF-8
        Content-Length: 7
        Cookie: _ga=GAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; _gat=1
        Connection: Keep-Alive
        Accept-Encoding: gzip, deflate
        Accept-Language: es-ES,en,*
        Host: httpbin.org
        
        
        None
        a=1&b=2  <<---- that is OK, is the data contained into the POST
        None
        '''
        

        【讨论】:

          【解决方案7】:
          from selenium import webdriver
          
          driver = webdriver.Firefox()
          driver.implicitly_wait(12)
          driver.set_page_load_timeout(10)
          
          def _post_selenium(self, url: str, data: dict):
              input_template = '{k} <input type="text" name="{k}" id="{k}" value="{v}"><BR>\n'
              inputs = ""
              if data:
                  for k, v in data.items():
                      inputs += input_template.format(k=k, v=v)
              html = f'<html><body>\n<form action="{url}" method="post" id="formid">\n{inputs}<input type="submit" id="inputbox">\n</form></body></html>'
          
              html_file = os.path.join(os.getcwd(), 'temp.html')
              with open(html_file, "w") as text_file:
                  text_file.write(html)
          
              driver.get(f"file://{html_file}")
              driver.find_element_by_id('inputbox').click()
          
          _post_selenium("post.to.my.site.url", {"field1": "val1"})
          
          driver.close()
          

          【讨论】:

            【解决方案8】:

            我使用driver.execute_script()将html表单注入到页面中,然后提交。它看起来像这样:

                    def post(path, params):
                        driver.execute_script("""
                        function post(path, params, method='post') {
                            const form = document.createElement('form');
                            form.method = method;
                            form.action = path;
                        
                            for (const key in params) {
                                if (params.hasOwnProperty(key)) {
                                const hiddenField = document.createElement('input');
                                hiddenField.type = 'hidden';
                                hiddenField.name = key;
                                hiddenField.value = params[key];
                        
                                form.appendChild(hiddenField);
                            }
                          }
                        
                          document.body.appendChild(form);
                          form.submit();
                        }
                        
                        post(arguments[1], arguments[0]);
                        """, params, path)
            
                    # example 
                    post(path='/submit', params={'name': 'joe'})
            

            如果你愿意,你可以把它添加到\selenium\webdriver\chrome\webdriver.py,然后在你的代码中使用driver.post()

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2023-03-31
              • 2014-04-05
              • 2021-06-26
              • 2019-09-18
              • 1970-01-01
              • 1970-01-01
              • 2017-03-26
              相关资源
              最近更新 更多