jquery逆向css selector path生成

场景:

一般情况我们都是已知css选择器的情况下,去操作dom元素,而在做爬虫时,为了方便的使用可视化的方式,让用户能够快速选区要采集的元素节点,需要在页面上点击某个元素后自动获取其selector。

思路:

从点击元素开始向上(父节点)遍历,若遍历过程中的某个选择器能够唯一确定这个元素,则返回。当遇到有id属性的元素时直接返回。

实现:


/**
 * 获取css path
 * @param callback
 * callback接收两个参数:元素的css路径,选择元素的jq对象
 */
function getCssPath(callback) {
  let all = $('*');
  all.click(function () {
    let path = cssPath($(this));
    if ($(path).hasClass('_selected')) {
      $(path).removeClass('_selected');
    } else {
      $(path).addClass('_selected');
    }
    callback(path, $(this));
    return false;
  })
}

function cssPath(el) {
  let path = [];
  while (el && el[0].tagName !== 'HTML') {
    let selector = el[0].tagName.toLowerCase();
    if (el.attr('id')) {
      selector += '#' + el.attr('id');
      path.unshift(selector);
      break;
    } else {
      if (el.attr('class') && el.attr('class') !== '' && el.attr('class').trim() !== '_selected' && selector !== 'input') {
        let classStr = el.attr('class');
        let cl = '.' + classStr.trim().split(/\s+/).join('.');
        if ($(selector + cl + '>' + (path.length > 0 ? path.join(" > ") : '')).length === 1) {
          path.unshift(selector + cl);
          break;
        }
        let suffixLen = el.nextAll();
        let nth = el.prevAll().length + 1;
        if (nth !== 1 || suffixLen !== 0)
          selector += ":nth-child(" + nth + ")";
      } else if (selector === 'input' && el.attr('name')) {
        if ($(selector + '[name=' + el.attr('name') + ']').length === 1) {
          path.unshift(selector + '[name=' + el.attr('name') + ']');
          break;
        }
      } else {
        let nth = el.prevAll().length + 1;
        if (nth !== 1)
          selector += ":nth-child(" + nth + ")";
      }
    }
    path.unshift(selector);
    el = el.parent();
  }
  return path.join(" > ");
}

其中_selected类如下:

._selected{
  background-color:green !important;
}

使用方式:

$(document).ready(function () {
  setTimeout(function () {
    getCssPath(function (path, el) {
      alert($(path).text() + ':' + el.text())
    });

  }, 2000)
});

结果对比:

浏览器copy selector生成的path:

#app > div > div.app-frame.h-layout.h-layout-has-sider.h-layout-sider-fixed > div.h-layout.h-layout-header-fixed > div.h-layout-content > div.app-frame-content > div > div > div:nth-child(2) > div > div.h-panel-bar > div.h-panel-title._selected

本代码生成的path:

div.h-row > div:nth-child(2) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1)

相对于浏览器生成的来说,更简洁

posted @ 2019-06-08 10:34  SEC.VIP_网络安全服务  阅读(147)  评论(0编辑  收藏  举报