JavaScript:使用含有Iframe的Xpath定位网页元素(非跨域)

一、实现思路

1.1 在任意Document对象中使用Xpath定位

注:如果是Iframe,需要用[elem].contentWindow.document获取Document对象

function $x(str_xpath, doc=document) {
	var xresult = doc.evaluate(str_xpath, doc, null, XPathResult.ANY_TYPE, null);
	var xnodes = [], xres;
	while (xres = xresult.iterateNext()) {
		xnodes.push(xres);
	}
	return xnodes;
}

1.2 针对Xpath语句按照Iframe进行分段

情况1://iframe[@id=“test”]//input 拆分成 //iframe[@id=“test”]//input
情况2://something::iframe//input 拆分成 //something::iframe//input
注:因为可能存在多个Iframe层级,所以需要用递归进行拆分

// 将Xpath语句按照Iframe进行分段
function spilt_xpath_by_iframe(str_xpath) {
    let iframeRegex = /(?:\/+iframe|\/\/.*?::iframe)(\[.*?\])?/;
    let iframeMatch = str_xpath.match(iframeRegex);
    if (!iframeMatch) return str_xpath ? [str_xpath] : [];
    let iframeXpath = str_xpath.substring(0, str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
    let innerXpath = str_xpath.substring(str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
    return [iframeXpath].concat(spilt_xpath_by_iframe(innerXpath));
}

二、整合功能(适配多级Iframe结构的Xpath查找)

2.1 完整代码

// Xpath查找方法(默认在当前document查找)
function $x(str_xpath, doc=document) {
    // 匹配Xpath中的Iframe节点
    let iframeMatch = str_xpath.match(/(?:\/+iframe|\/\/.*?::iframe)(\[.*?\])?/);
    // 实际执行的Xpath、递归执行的Xpath
    let exec_xpath = str_xpath, inner_xpath = '';
    // 判断是否匹配iframe
    if (iframeMatch) {
        exec_xpath = str_xpath.substring(0, str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
        inner_xpath = str_xpath.substring(str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
    }
    // 如果执行的Xpath语句为空,则直接返回空数组
    if (!doc || !exec_xpath) return [];
    // 执行Xpath匹配
    let xresult = doc.evaluate(exec_xpath, doc, null, XPathResult.ANY_TYPE, null);
    // 迭代匹配结果
    let xnodes = [], xres;
    while (xres = xresult.iterateNext()) {
        // 判断是否为Iframe节点,且需要继续匹配
        if (inner_xpath && xres.contentWindow) {
            // 以Iframe的contentWindow.document作为参数,递归进行匹配
            xnodes = xnodes.concat($x(inner_xpath, xres.contentWindow.document));
        } else {
            // 保存匹配结果
            xnodes.push(xres);
        }
    }
    // 返回匹配结果
    return xnodes;
}

三、实战案例(以获取QQ邮箱中收件列表为例)

3.1 编写定位Iframe元素的Xpath语句

通过Xpath语句定位Iframe://iframe[@id=‘mainFrame’]

3.2 编写定位所有邮件的Xpath语句

通过Xpath获取所有邮件://table[contains(@class, ‘i’) and not(contains(@class, ‘bold’))]

3.3 合并Xpath语句,并使用新封装的Xpath查找方法

完整Xpath://iframe[@id=‘mainFrame’]//table[contains(@class, ‘i’) and not(contains(@class, ‘bold’))]

// 使用Xpath获取所有邮件
$x("//iframe[@id='mainFrame']//table[contains(@class, 'i') and not(contains(@class, 'bold'))]");
// 封装获取邮件信息方法
function get_email_infos(){
	var email_infos = [];
	var emails = $x("//iframe[@id='mainFrame']//table[contains(@class, 'i') and not(contains(@class, 'bold'))]");	
	for(var k in emails){
		var email_title = emails[k].getElementsByClassName("tt")[0].textContent;
		var email_desc = emails[k].getElementsByClassName("no")[0].textContent;
		email_infos.push({'title': email_title, 'desc': email_desc});
	}
	return email_infos;
}

3.4 完整案例(可直接在控制台运行)

// Xpath查找方法(默认在当前document查找)
function $x(str_xpath, doc=document) {
    // 匹配Xpath中的Iframe节点
    let iframeMatch = str_xpath.match(/(?:\/+iframe|\/\/.*?::iframe)(\[.*?\])?/);
    // 实际执行的Xpath、递归执行的Xpath
    let exec_xpath = str_xpath, inner_xpath = '';
    // 判断是否匹配iframe
    if (iframeMatch) {
        exec_xpath = str_xpath.substring(0, str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
        inner_xpath = str_xpath.substring(str_xpath.indexOf(iframeMatch[0]) + iframeMatch[0].length);
    }
    // 如果执行的Xpath语句为空,则直接返回空数组
    if (!doc || !exec_xpath) return [];
    // 执行Xpath匹配
    let xresult = doc.evaluate(exec_xpath, doc, null, XPathResult.ANY_TYPE, null);
    // 迭代匹配结果
    let xnodes = [], xres;
    while (xres = xresult.iterateNext()) {
        // 判断是否为Iframe节点,且需要继续匹配
        if (inner_xpath && xres.contentWindow) {
            // 以Iframe的contentWindow.document作为参数,递归进行匹配
            xnodes = xnodes.concat($x(inner_xpath, xres.contentWindow.document));
        } else {
            // 保存匹配结果
            xnodes.push(xres);
        }
    }
    // 返回匹配结果
    return xnodes;
}

// 封装获取邮件信息方法
function get_email_infos(){
	var email_infos = [];
	var emails = $x("//iframe[@id='mainFrame']//table[contains(@class, 'i') and not(contains(@class, 'bold'))]");	
	for(var k in emails){
		var email_title = emails[k].getElementsByClassName("tt")[0].textContent;
		var email_desc = emails[k].getElementsByClassName("no")[0].textContent;
		email_infos.push({'title': email_title, 'desc': email_desc});
	}
	return email_infos;
}

get_email_infos()
  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值