本文源地址
页面分析合集地址
页面内容分析之 404 页面检测
先来看看机器人怎么说:
要检测一个网页是否是 404 页面,你可以尝试以下方法:HTTP 状态码检查:发送 HTTP 请求并检查返回的状态码。如果网页是 404 页面,服务器将返回 404 状态码。你可以使用编程语言或工具(如 Python 的 requests 库)发送 HTTP 请求,并检查返回的状态码是否为 404。页面内容检查:发送 HTTP 请求并获取网页内容。然后,检查页面内容是否包含 404 相关的文本或关键词。通常,404 页面会包含类似于"404"、"页面未找到"、"Not Found"等关键词。你可以使用编程语言或工具对获取的页面内容进行文本匹配或关键词搜索,以确定是否为 404 页面。网页截图比对:使用自动化测试工具,如 Selenium,可以模拟浏览器行为打开网页并截取页面截图。然后,你可以比对该截图与预期的 404 页面截图进行比对。如果它们相似度很高,则可能是 404 页面。这些方法可以根据你的需求和技术背景进行选择和实施。需要注意的是,有些网页可能会使用 JavaScript 动态生成内容,这可能需要更高级的技术来处理。
什么是 404 界面
狭义的 404 界面就是 http 响应码返回 404 或 503 等不可达值的网页广义的来说,404 界面是一个统称,指的是协议 404 或者内容 404
404 页面有哪些特征
1、返回的 httpcode 是 404/503/401 等不可达 code2、title 里面有”不存在“、”不可达“等关键词 3、内容里面有“不存在”、“找不到”等关键词 4、链接被重定向到了特定的 404 或 503 域名或页面 5、对于单个网站来说,所有的 404 页面结构比较统一
检测方案
针对上述 404 页面的特征,我们需要逐个实现
响应码返回 404/503 等
public Boolean checkHttpStatusCode(String code) {
if (code.equals("404") || code.equals("503")) {
return true;
}
return false;
}
复制代码
title 里面有”不存在“、”不可达“等关键词
首先,我们使用 jsoup 库解析 html,然后得到 title 标签里面的内容
public static String getHtmlTitle(String html){
try {
// 使用 Jsoup 解析 HTML
Document doc = Jsoup.parse(html);
// 获取 <title> 标签
Element titleElement = doc.select("title").first();
// 检查是否存在 <title> 标签并获取其内容
if (titleElement != null) {
String title = titleElement.text();
return title;
} else {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
复制代码
拿到 title 之后,我们再进行比对即可,利用 java 里面的 contains 方法即可
内容里面有“不存在”、“找不到”等关键词
首先需要获取到 html 里面的内容区,在没有使用智能提取技术之前,我们可以先去除标签获取内容,但是这确实是会带来很大的误报
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlUtil {
public static String delHTMLTag(String htmlStr) {
String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式
Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
Matcher m_script = p_script.matcher(htmlStr);
htmlStr = m_script.replaceAll(""); //过滤script标签
Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
Matcher m_style = p_style.matcher(htmlStr);
htmlStr = m_style.replaceAll(""); //过滤style标签
Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
Matcher m_html = p_html.matcher(htmlStr);
htmlStr = m_html.replaceAll(""); //过滤html标签
return htmlStr.trim();
}
public static String htmlTextFormat(String htmlText) {
htmlText = htmlText
.replaceAll("(\\\\n)+", " ")
.replaceAll("(\\\\t)+"," ")
.replaceAll("(\t)+"," ")
.replaceAll("(\n)+"," ");
htmlText = htmlText.replaceAll(" +"," ");
htmlText = htmlText.replaceAll(" +"," ");
return htmlText;
}
public static String getContent(String html) {
String ans = "";
try {
html = StringEscapeUtils.unescapeHtml4(html);
html = delHTMLTag(html);
html = htmlTextFormat(html);
return html;
} catch (Exception e) {
e.printStackTrace();
}
return ans;
}
}
复制代码
上面的 getContent 方法便是我们获取到 html 内容的方法。
链接被重定向到了特定的 404 或 503 域名或页面
需要传入 url,并对 url 进行解析
public class UrlPattern {
private String pattern; // 正则
private String description; // 描述
private String location; // 位置
}
private Boolean checkOneUrlPattern(UrlPattern urlPattern, String url) {
URL url1 = null;
try {
url1 = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (Objects.isNull(url1)) return false;
Pattern pattern = Pattern.compile(urlPattern.getPattern());
String val = "";
if (urlPattern.getLocation().equalsIgnoreCase("path")) {
val = url1.getPath();
} else if (urlPattern.getLocation().equalsIgnoreCase("query")) {
val = url1.getQuery();
} else if (urlPattern.getLocation().equalsIgnoreCase("host")) {
val = url1.getHost();
}
if (!StringUtils.hasText(val))return false;
Matcher matcher = pattern.matcher(val);
if (matcher.find()) {
return true;
}
return false;
}
复制代码
UrlPattern 是定义的一套检测规则的对象类,以下是大概的格式
- pattern: '\b(404|503)\b'
description: '检测链接的域名部分包含404或503'
location: 'host'
复制代码
上述规则检测域名的 host 部分中是否有 404 或者 503
对比页面结构,判定是否为 404 页面
这里有两个方案方案一:自建 404 页面结构库,让用户调用时与我们的自建库进行比对方案二:用户自己传入 404 页面和一个正常页面,我们利用页面结构相似度比较算法来确定是否为 404 页面
先来看下页面结构的算法
public class PageStructUtil {
public static List<String> getAllLabelsFromHtml(String html) {
Document document = Jsoup.parse(html);
Elements elements = document.getAllElements();
List<String> elementList = new ArrayList<>();
for (Element element : elements) {
elementList.add(element.nodeName());
}
return elementList;
}
/**
* a 基于 base的相似性
*
* @param a
* @param base
* @return
*/
public static Double pageStructScore(List<String> a, List<String> base) {
SequenceUtils<String> stringSequenceUtils = new SequenceUtils<>();
Integer length = stringSequenceUtils.getLongestCommonSequence(a, base);
int n = base.size();
int m = a.size();
// TODO: 2020/5/25 定义:页面结构的相似度为 (2.0*公共序列的长度)/(旧的公共序列的长度+新的公共序列的长度)
Double score = (2 * length) / ((n + m) * 1.0);
return score;
}
public static void main(String[] args) {
}
}
复制代码
页面结构算法我在专栏的另外一篇博客中有专门讲解,请大家移步观看然后,我们来看看调用的方法
/**
* 自出404页面的页面结构分析
*
* @param user404Html
* @param html
* @param score
* @return
*/
public Boolean checkUserPage404Struct(String user404Html, String html, Double score) {
try {
return PageStructUtil.pageStructScore(PageStructUtil.getAllLabelsFromHtml(user404Html), PageStructUtil.getAllLabelsFromHtml(html)) >= score;
} catch (Exception e) {
}
return false;
}
复制代码
优化迭代
检测配置化
由于上述写法中我们都是将检测的东西写死在程序中,不具有可扩展性,所以我们需要对此进行扩展,扩展的思路便是对于所有判断性条件都做成配置形式的,而不是走特判。例如,我们可以对链接里面有 404 或 503 的编写如下的配置
rule_name: '检测链接的域名部分包含404或503'
url_patterns:
- pattern: '\b(404|503)\b'
description: '检测链接的域名部分包含404或503'
location: 'host'
rule_name: '检测到路径中包含404或503'
url_patterns:
- pattern: '\/(?:.*\/)?(404|503)\/'
description: '检测到路径中包含404或503'
location: 'path'
rule_name: '检测到查询字符串中包含404或503'
url_patterns:
- pattern: '[?&](?:[^&=]+=[^&=]+&)*(?:[^&=]+=(404|503))(?:&|$)'
description: '检测到查询字符串中包含404或503'
location: 'query'
复制代码
给 title 添加如下检测配置
404
503
页面未找到
服务不可用
错误
错误页面
访问被拒绝
权限拒绝
页面不存在
链接不存在
不存在
Not Found
复制代码
http 响应码的配置
页面结构的配置
rule_name: 'pan.baidu.com'
rules:
- struct: '#document-html-head-body-meta-title-link-link-style-style-style-div-header-a-nav-a-span-div-a-em-div-div-a-span-span-a-span-span-a-span-span-a-span-span-a-span-span-a-span-span-a-span-span-a-span-span-iframe-div-ul-li-a-li-em-span-div-iframe-em-div-span-a-span-span-a-span-a-span-a-span-a-span-a-span-a-span-a-section-div-div-div-div-h3-div-p-p-p-div-p-a-p-a-style-div'
score: '0.8'
name: '404页面'
- struct: '#document-html-head-body-title-meta-meta-meta-meta-meta-meta-meta-meta-link-link-link-link-link-link-link-link-link-style-link-link-link-link-style-style-style-style-div-div-div-div-dl-dt-a-dd-span-a-span-span-a-span-span-a-span-span-a-span-dl-dt-dd-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-span-a-p-dd-i-i-dd-span-span-i-i-span-a-i-dl-dt-i-i-span-span-i-i-span-span-a-p-i-span-dd-div-a-div-a-a-a-a-a-ul-li-a-li-a-li-a-li-a-span-span-li-a-li-a-i-a-a-i-a-div-div-div-span-a-div-span-dd-a-div-section-section-div-aside-dl-div-dl-div-a-p-p-a-p-p-a-p-p-a-p-p-div-div-div-img-div-section-link-div-div-a-a-a-a-a-a-a-style-div'
score: '0.8'
name: '链接失效页面'
复制代码
接下来做的事儿
1、找到一堆 404 页面,得到其结构、title,响应码特征,丰富我们的上述配置如何快速获取大量的 404 页面?可以找到一堆域名,然后添加一系列后缀(绝不可能存在的),得到的页面大概率就是 404 页面 2、对页面内容做智能解析提取,进而得到内容区的标题和正文,再进行进一步的分析。
评论