纯净模式之页面内容识别

99 阅读5分钟

Web页面内容识别提取

背景

平台类App(夸克、QQ、厂商浏览器、百度、头条...)通过对三方页面内容识别-提取-整合-布局,实现纯净模式,为用户提供统一的更好的用户体验,常见于影视、小说等业务场景。 相对于一般的爬虫,这种业务场景需要对页面内容进行更加全面、详细的识别提取。而三方站点不甘于为他人做嫁衣、避免广告收入损失,也会主动进行技术对抗。

技术难点

多样、低质、变化、对抗等

内容多样性

  • 目录页面可能包含:全部目录、部分最新目录、首页目录、第二页目录(第一页目录在详情页内)、头尾目录、无目录、倒序目录,新书目录少...
  • 翻页加载目录,分组加载目录,折叠展开目录,tab切换目录
  • 目录列表名称(纯数字、英文+数字、无数字、大写数字、重复名称、章节名包含推荐收藏等文字,章节篇集部页等单位)
  • 对话式内容,分页内容(尾页可能非常少)
  • 上下章(链接、按钮,文字、符号、图片...)

结构不规范

  • 大块文本内容不是用article或p标签,而是用a标签等,br换行
  • 目录列表是嵌套标签
  • meta在body里
  • css控制内容
<div class="novelcontent" data-txt="武天不仅没有生江媛媛的气,而且还心情极好的哼着小曲。"></div>
<style>
.novelcontent::after {
    content: attr(data-txt);
}
</style>
  • button fromaction
<button fromaction="/3214/~%50290442-4.html">第一千四百九十五章 神战</button>

杂质内容

  • 随机标签、空标签
  • 隐藏章节(内容页隐藏章节、详情页隐藏部分章节)
  • 大量简介、大量预览内容,可能会被识别为内容页面
  • 大量推荐列表、榜单页,包含大量书名、章节信息(每本书的最新章节),可能会被识别为列表页面
  • 引导内容(引导收藏网站、引导下载app...)
  • 广告内容

低质

  • 高峰期服务稳定性低
  • 无内容、js错误
  • 缺失部分内容

乱码

  • 定制字体
<!-- 第一十八章 抓人 -->
<!-- 十八章 抓 -->
<a><i>&#xe848;</i><i>&#xe801;</i>十八章&#8192;<i>&#xe806;</i></a>

image.png

  • 同站点的不同页面使用不同编码
  • 整页用图片,个别字用图片
  • 加解密

乱序

  • js排序
  • css排序

URL

API重写

  • 重写replaceAll方法
  • 无URL对象

跨域

动态

js生成(目录、内容)、异步加载、iframe、

(function(){
    for(var i=1;i<=16;i++){
        if(i==1){
            document.writeln('<option value="" selected>select</option><option value="dir_'+i+'.html" selected>第 '+((i - 1) * 50 + 1) +' -- '+(i * 50)+' 章</option>');
        }else{
            document.writeln('<option value="dir_'+i+'.html">第 '+((i - 1) * 50+1) +' -- '+(i * 50)+' 章</option>');
        }
    }
})();

技术实现(平台攻)

站点识别

离线分析站点,识别站点类型,常见影视、动漫、小说、文学、教育(作文)、新闻咨询、

页面识别

以小说详情页、目录页面、内容页为例页面的主要特征, 1、目录页,大量连续、相同目标页面、标题中包含大小写数字/'章节篇部'等字样 2、内容页,一大块文本内容,连续性

根据这些特征,,优先固有特征,,排除情况,识别出页面类型

内容识别

1、过程

  1. 选取(body内容、head内容)
  2. 去杂(不相关内容,script/style/input/img/video/ul/ol/selct)
  3. 识别(固有特征、识别特征,提取多个符合特征的内容)
  4. 提取,根据特征进行加、降权得出可能性最高的一个,获得内容
  5. 动态提取
  6. 反推提取,通过正则反向推断进行内容提取
  7. 编码
  8. 过滤(主动屏蔽,因为版权、突发舆情等原因
  9. 排序(order)
  10. 过滤(定制字体通过配置映射关系进行矫正、黄反、内容杂质、去广告)
  11. 渲染

2、固有特征

  • 标签(使用贪心逻辑,仅排除明确不可能的标签)
  • 是否展示、位置、尺寸、长度、内容
  • 内容(特定文字,如书名号、数字、章节篇部页、上下)

3、识别特征

  • 相似度(通过将页面内的url正则,推断出最多的url正则)
  • 上下文(前后文字、
  • 连续性(段落文字,应该有上下段落)
  • 文本内容长度、子节点类型(一般段落内仅文字)、子节点数量

例:url相似度,找到页面内目录的链接特征

function url2Reg(url: string, hasParam: boolean = true, hasHost: boolean = false) {
    if (!url) {
        return url;
    }
    const pagename = decodeURIComponent(getPagename(url));
    const urlObj = new URL(url);
    url = decodeURIComponent(((hasHost ? urlObj.origin : '') + urlObj.pathname).replace(/\//g, '\\/'));
    if (pagename) {
        let pathStr = pagename;
        let regStr = '';
        while (pathStr) {
            const num = parseInt(pathStr, 10);
            if (!isNaN(num) && num > 9) {
                const numLength = num.toString().length;
                regStr += '\\d' + (num > 1000 ? `{${numLength - 1},${numLength + 1}}` : '+');
                pathStr = pathStr.substring(numLength);
                continue;
            }
            const charMatch = /^[a-zA-Z]+/.exec(pathStr);
            if (charMatch) {
                regStr += '\\w{' + charMatch[0].length + '}';
                pathStr = pathStr.substring(charMatch[0].length);
                continue;
            }
            regStr += pathStr.substring(0, 1);
            pathStr = pathStr.substring(1);
        }
        url = url.replace(pagename, regStr);
    }
    if (hasParam) {
        url += urlObj.search.replace('?', '\\?').replace(/\??\w+=(\w+)&?/g, (a, b) => {
            // 固定词
            if ('article,list,chapter,'.indexOf(b) >= 0) {
                return a;
            }
            if (parseInt(b, 10) === +b) {
                return a.replace(b, '\\d+');
            }
            return a.replace(b, '\\w+');
        });
    }
    return url;
}
  1. 内容节点,分析节点内容、子节点数量找到内容父节点

image.png

内容整合

  • 识别最新内容
  • 当前页面仅包含部分内容,给用户提供完整相关内容
  • 识别上下页地址

广告屏蔽

  • App广告模型(移除dom、拦截请求)
  • js清除、clearTimer
  • dom清理、层级控制
  • 事件覆盖

监控

访问、识别、提取、质量(乱码、乱序、缺内容...)

屏蔽提取(站长防)

避免识别提取到页面内容、相关页面链接

动态化

  • js动态绑定事件,不要直接用a标签加url,避免提取到相关页面
  • js动态生成内容(seo不友好)
  • 重写api(开发体验不好)

防访问、分析

  • 宿主对抗,引导出宿主App进微信群等
  • 拒绝对应ip访问
  • 防止打开调试工具,打开后直接进入debuger状态