使用Selenium和Python捕获AJAX响应

24

我在Firefox中单击链接,网页使用JavaScript发送请求,然后服务器发送某种响应,其中包括一个网站地址。因此,这个新网站会在一个新窗口中打开。链接背后的HTML代码是(我省略了初始和结束的<span>标签):

> class="taLnk hvrIE6"
> onclick="ta.trackEventOnPage('AttractionContactInfo', 'Website',
> 2316062, 1); ta.util.cookie.setPIDCookie(15190);
> ta.call('ta.util.link.targetBlank', event, this,
> {'aHref':'LqMWJQiMnYQQoqnQQxGEcQQoqnQQWJQzZYUWJQpEcYGII26XombQQoqnQQQQoqnqgoqnQQQQoqnQQQQoqnQQQQoqnqgoqnQQQQoqnQQuuuQQoqnQQQQoqnxioqnQQQQoqnQQJMsVCIpEVMSsVEtHJcSQQoqnQQQQoqnxioqnQQQQoqnQQniaQQoqnQQQQoqnqgoqnQQQQoqnQQWJQzhYmkXHJUokUHnmKTnJXB',
> 'isAsdf':true})">Website

我想使用Python和Selenium获取服务器响应并提取“新网站”。我一直在使用BeautifulSoup进行数据抓取,对Selenium还不太熟悉。

到目前为止,我能够使用Selenium找到这个元素并点击它,在新窗口中打开“新网站”。但我不知道如何捕获来自服务器的响应。


我认为问题的标题有误导性 - beautifulsoup与你的问题无关。"使用Selenium获取AJAX响应"或类似的内容是相关的。 - SiddharthaRT
一位资深成员建议我这样重命名我的问题……我的实际标题确实与Python和Selenium有关。 - Faisal
3个回答

21

我曾经使用selenium拦截一些ajax调用并注入javascript到页面中。不好的一面是selenium有时可能会比较“脆弱”。因此,我在进行这种注入时无缘无故地遇到了selenium异常。

无论如何,我的想法是拦截XHR调用,并将其响应设置为由我创建的新dom元素,我可以从selenium中操作该元素。在拦截的条件中,您甚至可以使用发出请求的url来仅拦截您实际想要的那个(self._url)

顺便说一句,我从intercept all ajax calls?得到了这个想法。

也许这可以帮助你。

browser.execute_script("""
(function(XHR) {
  "use strict";

  var element = document.createElement('div');
  element.id = "interceptedResponse";
  element.appendChild(document.createTextNode(""));
  document.body.appendChild(element);

  var open = XHR.prototype.open;
  var send = XHR.prototype.send;

  XHR.prototype.open = function(method, url, async, user, pass) {
    this._url = url; // want to track the url requested
    open.call(this, method, url, async, user, pass);
  };

  XHR.prototype.send = function(data) {
    var self = this;
    var oldOnReadyStateChange;
    var url = this._url;

    function onReadyStateChange() {
      if(self.status === 200 && self.readyState == 4 /* complete */) {
        document.getElementById("interceptedResponse").innerHTML +=
          '{"data":' + self.responseText + '}*****';
      }
      if(oldOnReadyStateChange) {
        oldOnReadyStateChange();
      }
    }

    if(this.addEventListener) {
      this.addEventListener("readystatechange", onReadyStateChange,
        false);
    } else {
      oldOnReadyStateChange = this.onreadystatechange;
      this.onreadystatechange = onReadyStateChange;
    }
    send.call(this, data);
  }
})(XMLHttpRequest);
""")

感谢您分享您的经验。我对JavaScript没有可行的知识。我只需要收集一些数据,这些数据是网站作为ajax调用响应发送的。解决方案似乎是使用Python自己的模块(如requests或urllib)来识别和模拟调用。这有助于我在没有任何JavaScript的情况下收集数据。 - Faisal
如果您提前知道网站的URL,您就不需要处理JavaScript,但在我的情况下,事先不容易知道URL的某些参数,因此我需要处理js。如果您的问题解决方案是之前发布的内容,请将其标记为问题的答案。 - supita
将近两年过去了,这仍然是正确的方法吗?我需要检索我的网站所做的ajax调用的url,因为我事先不知道某些参数。另外,时间方面怎么样?我如何确保此脚本在任何ajax请求发生之前执行?谢谢。 - Hinrich

11

我试图捕获基于AJAX请求的XHR内容,于是来到了这个页面。最终我找到了这个包。

from seleniumwire import webdriver  # Import from seleniumwire
# Create a new instance of the Firefox driver
driver = webdriver.Firefox()

# Go to the Google home page
driver.get('https://www.google.com')

# Access requests via the `requests` attribute
for request in driver.requests:
    if request.response:
        print(
            request.url,
            request.response.status_code,
            request.response.headers['Content-Type']
        )

该软件包可以获取任何请求的响应内容,例如json:

https://www.google.com/ 200 text/html; charset=UTF-8
https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png 200 image/png
https://consent.google.com/status?continue=https://www.google.com&pc=s&timestamp=1531511954&gl=GB 204 text/html; charset=utf-8
https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png 200 image/png
https://ssl.gstatic.com/gb/images/i2_2ec824b0.png 200 image/png
https://www.google.com/gen_204?s=webaft&t=aft&atyp=csi&ei=kgRJW7DBONKTlwTK77wQ&rt=wsrt.366,aft.58,prt.58 204 text/html; charset=UTF-8
..

2

我无法使用selenium捕获AJAX响应,但以下方法有效,尽管没有使用selenium:

1- 使用浏览器的网络分析工具找出XML请求

2- 一旦你确定了请求,使用Python的requests或urllib2模块重新生成它。我个人推荐使用requests,因为它具有额外的功能,对我来说最重要的是requests.Session。

您可以找到大量有关这两个步骤的帮助和相关帖子。

希望它能帮助某个人。


我为一个我正在爬取的网站做了这件事。花了一些时间才从Chrome的网络工具中找到实际调用是什么,但最终我找到了。然后我在浏览器中测试了响应,最后使用requests进行了测试。效果非常好。在我的情况下,输出似乎是JSON和其他数据的混合 - 所有这些都很容易解析。再次感谢。 - Gabe Spradlin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,