All Downloads are FREE. Search and download functionalities are using the official Maven repository.

starSpider.parser.HTMLParser Maven / Gradle / Ivy

package starSpider.parser;

import starSpider.ConstantRegion;
import starSpider.container.Container;
import starSpider.container.HTMLDocument;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * HTML解析器,同时也可以作为XML的解析器,在该解析器中,您可以使用节点,节点路径,节点属性的信息获取到某一个节点的数据对象。
 * 

* An HTML parser can also be used as an XML parser. In this parser, you can use the node, node path, and node attribute information to obtain the data object of a node. * * @author zhao */ public class HTMLParser extends LABELParser { protected final static Pattern ATTRIBUTE_PATTEN = Pattern.compile("<.*?(?=>)"); public HTMLParser() { super.childrenClass = true; } /** * @return 解析器的名称,用于区别解析器之间的联系 */ @Override public String getName() { return ConstantRegion.PARSER_NAME_HTML; } /** * 按照节点解析功能,针对每一个节点进行解析,并获取到数据 * * @param data 需要被解析的标签文档数据 * @param args 节点集合,存在于集合中的节点都会被解析出来,其中从索引1开始就是待解析节点了,0 索引位的数据不做限制 * @return 存在于集合中的所有节点的数据。 */ @Override public Container[] getDocumentByNodeName(String data, String... args) { return getDocumentByNodeName(data, false, args); } /** * 按照节点解析功能,针对每一个节点进行解析,并获取到数据 * * @param data 需要被解析的标签文档数据 * @param isGreedy 如果为true,代表使用贪婪模式匹配标签,这样匹配的标签会很大 * @param args 节点集合,存在于集合中的节点都会被解析出来,其中从索引1开始就是待解析节点了,0 索引位的数据不做限制 * @return 存在于集合中的所有节点的数据。 */ public Container[] getDocumentByNodeName(String data, boolean isGreedy, String... args) { ArrayList arrayList = new ArrayList<>(); for (int i = 1; i < args.length; i++) { String node = args[i]; Pattern compile = Pattern.compile(getNodeRex(node, isGreedy)); Matcher matcher = compile.matcher(data); while (matcher.find()) { arrayList.add(getHtmlDocument(node, matcher)); } } return arrayList.toArray(new HTMLDocument[0]); } /** * 获取到指定的一个节点 * * @param data 需要被解析的HTML文本数据 * @param nodeName 需要获取的节点名称 * @param index 获取第几个索引处的节点数据 * @return 如果指定索引处有数据,会返回一个HTML文档对象,反之会返回null */ public Container ANodeParse(String data, String nodeName, int index) { Pattern compile = Pattern.compile(getNodeRex(nodeName, true)); Matcher matcher = compile.matcher(data); if (matcher.find(index)) { return getHtmlDocument(nodeName, matcher); } return null; } /** * 按照节点的属性,获取到指定节点数据 * * @param data 需要被解析的HTML文本数据 * @param args 0-预置位 * 1-attribsName 需要被获取目标节点的属性key * 2-attribsValue 需要被获取目标节点的属性value * @return 具有属性 attribsName=attribsValue 的节点的所有数据 */ public Container[] getDocumentByNodeAttrib(String data, String... args) { if (args.length >= 3) { Matcher matcher = Pattern.compile(getAttrRex(args[1], args[2])).matcher(data); ArrayList arrayList = new ArrayList<>(); if (matcher.find()) { arrayList.add(getHtmlDocument(matcher.group(1), matcher)); } return arrayList.toArray(new HTMLDocument[0]); } else { return new HTMLDocument[0]; } } /** * 生成一个文档对象 * * @param nodeName 节点名称 * @param matcher 节点匹配的正则对象 * @return 一个符合条件的文档对象 */ private HTMLDocument getHtmlDocument(String nodeName, Matcher matcher) { // 获取到当前节点的标签文本 String group = matcher.group(); // 提取出当前节点的标签属性 HashMap hashMap = new HashMap<>(); Matcher matcher1 = ATTRIBUTE_PATTEN.matcher(group); if (matcher1.find()) { for (String s : REGEXP_SPACE_ALL_PATTERN.split(matcher1.group())) { String[] split = REGEXP_LABEL_ATTRIBUTE_SEGMENTATION.split(s); if (split.length >= 2) { hashMap.put(split[0], split[1]); } } } String[] split = REGEXP_LABEL_REGULARITY_PATTERN.split(group); ArrayList arrayList = new ArrayList<>(split.length + 16); for (String s : split) { String trim = s.trim(); if (trim.length() != 0) arrayList.add(trim); } return new HTMLDocument(arrayList.toArray(new String[0]), hashMap, nodeName, group); } /** * 按照节点路径解析功能,针对每一个路径进行节点的数据查找并获取到节点文档对象 * * @param data 需要被解析的标签文档数据 * @param args 节点路径,每一个元素是一个节点路径,最后一个节点也就是目标节点。 * @return 符合路径的所有节点的数据。 */ @Override public Container[] NodePathParse(String data, String... args) { final StringBuilder stringBuilder = new StringBuilder(args.length << 4); stringBuilder.append("[\\s\\S]*"); // ?[\s\S]*??|[\s\S]* // ?| for (int i = 1, len = args.length - 1, len1 = len - 1; i < len; i++) { stringBuilder.append(ConstantRegion.LESS_THAN_SIGN_CHAR) .append(args[i]) .append(ConstantRegion.REGEXP_MATCH_ALL1) .append(ConstantRegion.GREATER_THAN_SIGN_CHAR) .append(ConstantRegion.REGEXP_GREEDY_SYMBOL); if (i != len1) { stringBuilder.append(ConstantRegion.REGEXP_MATCH_ALL2) .append(ConstantRegion.REGEXP_GREEDY_SYMBOL); } } stringBuilder.append(ConstantRegion.REGEXP_OR); for (int length = args.length - 2; length > 0; length--) { stringBuilder.append(ConstantRegion.End_Label1) .append(args[length]).append(ConstantRegion.GREATER_THAN_SIGN_CHAR); if (length != 1) stringBuilder.append(ConstantRegion.REGEXP_MATCH_ALL2); } stringBuilder.append("[\\s\\S]*"); return getDocumentByNodeName(data.replaceFirst(stringBuilder.toString(), ""), false, ConstantRegion.PARSER_NAME_HTML, args[args.length - 1]); } /** * 根据节点名称获取到适合的节点正则表达式 * * @param node 需要获取的节点名称 * @param isGreedy 是否使用贪婪匹配,贪婪模式下会获取到尽可能大范围的节点 * @return 节点正则表达式 */ public String getNodeRex(String node, boolean isGreedy) { if (isGreedy) { return ConstantRegion.LESS_THAN_SIGN_CHAR + node + ".*?>?[\\s\\S]*?[\\s\\S]*?[\\s\\S]*?"; } /** * 解析一个LABEL页面 * * @param data 需要被解析的数据 * @param args 解析器需要使用到的参数 * 索引0应为 您解析数据使用的手段 * node:按照节点解析所有节点文档数据 * 如果选择此方式进行文档解析,那么您需要在从1开始的位置书写所有需要被解析的节点名称 * nodePath:按照节点路径解析所有节点文档数据 * 如果选择此方式进行文档解析,那么您需要在从1开始的位置书写路径,符合路径描述的所有节点都会被解析 * attr:按照节点属性解析所有节点的文档数据 * 如果选择此当时进行文档解析,那么您需要在1号索引书写属性名称,2号索引书写属性的数值 * @return 解析器解析之后的结果数值 */ @Override public Container[] parse(String data, String... args) { Container[] parse = super.parse(data, args); if (parse != null) return parse; else { String arg = args[0]; if ("attr".equalsIgnoreCase(arg)) { return getDocumentByNodeAttrib(data, args); } else { throw new RuntimeException("您的解析模式【" + arg + "】在HTMLParser中并没有实现,因此无法进行指定数据的解析。\n" + "Your parsing mode [" + arg + "] is not implemented in HTMLParser, so you cannot parse the specified data."); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy