如何使用 Google Apps 脚本检查 Google 表格中的 URL 重定向

How to check for URL redirects in Google Sheets with Google Apps Script

我一直在尝试 运行 使用 Google Apps 脚本在 Google 表格中进行一些 URL 重定向测试,我已经成功获得了响应代码,并且还有一些链接的最终重定向 URL,但大多数链接都不起作用。

我要检查的链接示例:

https://www.airbnb.com/rooms/4606613

https://www.airbnb.com/rooms/4661522

https://www.airbnb.com/rooms/6014647

https://www.airbnb.com/rooms/14452305

https://www.airbnb.com/rooms/15910617

我几乎需要检查这些链接是否会重定向到 https://www.airbnb.com/s/homes

使用下面的脚本,我得到了以下列表,这是不正确的,因为它们都将重定向到 https://www.airbnb.com/s/homes:

https://www.airbnb.com/rooms/4606613

https://www.airbnb.com/s/homes

https://www.airbnb.com/s/homes

https://www.airbnb.com/rooms/14452305

https://www.airbnb.com/rooms/15910617

该网站似乎需要 1 秒来进行重定向,这可能就是问题所在。

代码下方:

function urlProtocol(url){
  return URI(url).protocol()
}

function urlHostname(url){
  return URI(url).hostname()
}

function getRedirects(url) {
  eval(UrlFetchApp.fetch('https://rawgit.com/medialize/URI.js/gh-pages/src/URI.js').getContentText());

  var params = {
    'followRedirects': false,
    'muteHttpExceptions': true
  };

  var baseUrl = urlProtocol(url) + "://" + urlHostname(url),
      response = UrlFetchApp.fetch(url, params),
      responseCode = response.getResponseCode();

  if(response.getHeaders()['Location']){
    var redirectedUrl = getRedirects(baseUrl + response.getHeaders()['Location']);
    return redirectedUrl;
  } else {
    return url;
  }
}

某些 URL 的最终重定向似乎发生在页面加载之后。很可能有一个 client-side 脚本启动 window.location 的更改。因此,您的正确逻辑无法捕获此类页面。

更糟糕的是,after-load 重定向似乎不一致,因为有时您提供的页面没有重定向到 https://www.airbnb.com/s/homes。我能够阻止此重定向的发生,因此该理论得到证实 - 将更新确切的原因。


除此之外,您还可以对脚本进行多项优化:

  1. 去掉 eval,实际上,去掉整个库,除非你真的需要它(看看如何在两行中做同样的事情)。提高安全性是主要好处:没有 eval() 外部脚本意味着破坏的可能性较小。
  2. 在查看 Location header 之前检查 3xx 范围内的状态代码(作为预防措施)。
/**
 * 
 * @param {string} target 
 */
const getRedirects = (target) =>

  /**
   * @param {string}
   * @returns {boolean}
   */
  (url) => {

    if(url === target) {
      return false;
    }

    const response = UrlFetchApp.fetch(url, {
      'followRedirects': false,
      'muteHttpExceptions': true
    });

    const code = response.getResponseCode();

    let { Location } = response.getHeaders();

    if (code < 300 || code >= 400) {
      return true;
    }

    if (!Location) {
      return false;
    }

    if (/^\/\w+/.test(Location)) {
      const [protocol, , base] = url.split("/");
      Location = `${protocol}//${base}${Location}`;
    }

    console.log(Location);
    
    return getRedirects(target)(Location);
  };

const testRedirects = () => {

  const redirectsToHome = getRedirects("https://www.airbnb.com/s/homes");

  const accessible = [
    "https://www.airbnb.com/rooms/23861670",
    "https://www.airbnb.com/rooms/4606613",
    "https://www.airbnb.com/rooms/4661522",
    "https://www.airbnb.com/rooms/6014647",
    "https://www.airbnb.com/rooms/14452305",
    "https://www.airbnb.com/rooms/15910617"
  ].filter(redirectsToHome);

  console.log(accessible);
};

自从澄清该函数是 custom function 后,您可以添加一个包装函数作为 public API,您可以在将调用实用程序,像这样:

const checkIfRedirects = (source, target = "https://www.airbnb.com/s/homes") => getRedirects(target)(source);

然后您可以像使用公式一样使用它:

=checkIfRedirects(A20)