用Selenium和Python捕获AJAX响应

24 投票
3 回答
35900 浏览
提问于 2025-04-28 18:02

我在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点击它,这样就能在新窗口中打开“新网站”。但我不知道怎么才能获取服务器的响应。

暂无标签

3 个回答

12

我在尝试捕捉基于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
..
21

我之前用selenium拦截了一些ajax请求,并在页面上注入了javascript代码。不过,selenium有时候会有点不稳定,导致我在进行注入时遇到了一些异常。

我的想法是拦截XHR请求,然后把它的响应设置为我自己创建的一个新的DOM元素,这样我就可以通过selenium来操作它。在拦截的条件中,你甚至可以使用发起请求的url,这样就能只拦截你真正想要的那个请求(self._url)。

顺便说一下,这个想法是从拦截所有ajax请求?这个问题中得到的。

希望这对你有帮助。

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);
""")
2

我在用selenium抓取AJAX响应时遇到了问题,不过这里有个方法可以做到,虽然不需要selenium:

1- 首先,通过浏览器的网络监控工具找到XML请求。

2- 一旦你找到了这个请求,就可以用Python的requests或者urllib2模块重新生成它。我个人推荐使用requests,因为它有更多的功能,其中对我来说最重要的是requests.Session。

关于这两个步骤,你可以找到很多帮助和相关的帖子。

希望这能在某一天帮助到某个人。

撰写回答