java处理Html标签以及图片链接的逻辑代码 青旅半醒 2022-10-16 06:04 3阅读 0赞 # 前言: # 需要针对新闻里面的图片链接地址进行抓取替换处理,所以需要手写java工具类进行正则抓取网址链接 # java工具类使用正则 # 具体详情代码: import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringEscapeUtils; import org.springframework.util.CollectionUtils; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @Slf4j public class HtmlTagUtils { /** js标签 */ private static final String REG_EX_SCRIPT = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?/[\\s]*?script[\\s]*?>"; /** css标签 */ private static final String REG_EX_STYLE = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?/[\\s]*?style[\\s]*?>"; /** 特殊嵌套标签需要优先去掉 */ private static final String REG_EX_HTML_SP_START = "<d class=[^>]+>"; /** 特殊嵌套标签需要优先去掉 */ private static final String REG_EX_HTML_SP_END = "</d>"; /** html标签 */ private static final String REG_EX_HTML = "<[^>]+>"; /** {@code <blockquote>标签} */ private static final String REG_EX_HTML_BLOCKQUOTE = "</?blockquote>"; /** 其他html转义符 */ private static final String REG_EX_SPECIAL = "&[a-zA-Z]{1,10};"; /** 正文声明内容匹配 */ private static final String REG_EX_STATEMENT = "(<font[^>]*?>|<span[^>]*?>|<p[^>]*?>)\\s*([(|(|【]?(免责声明|图片声明|责编|责任编辑|声明|来源链接|资料来源|文章来源|编辑|头图来源|图片来源|转载声明|风险提示|郑重声明)\\s?[::】]).*?(</font>|</span>|</p>)"; /** 记者声明内容匹配 */ private static final String REG_EX_REPORTER = "<p>\\s*(本报记者|本报见习记者|见习记者|每经记者).*?</p>"; /** HTML图片标签正则匹配 */ private static final Pattern HTML_IMG_PATTERN = Pattern.compile("<img.*?\"\\s*/?\\s*>", Pattern.CASE_INSENSITIVE); /** HTML图片标签路径正则匹配 */ private static final Pattern HTML_IMG_SRC_PATTERN = Pattern.compile("\\s+src\\s*=\\s*\"?(.*?)(\"\\s*/?\\s*>|\\s+)", Pattern.CASE_INSENSITIVE); /** BASE64编码图片前缀 */ private static final String HTML_IMG_BASE_64_PREFIX = "data:"; private static final String HTML_FORMAT_STYLE = "\n<style>\n" + " .paragraphFormat{\n" + " text-indent: 2em;\n" + " margin-top: 6px;\n" + " margin-bottom: 6px;\n" + " }\n" + " img{\n" + " display: block;\n" + " margin: 0 auto;\n" + " }\n" + " table{\n" + " border: 1px solid black;\n" + " border-collapse: collapse;\n" + " }\n" + " table td{\n" + " border: 1px solid black;\n" + " }\n" + "</style>"; /** * 删除html标签 * @param srcStr 原资讯正文内容 * @return 过滤后的资讯正文内容 */ public static String removeHtmlTag(String srcStr) { return StringUtils.isBlank(srcStr) ? StringUtils.EMPTY : unescape(srcStr) .replaceAll(REG_EX_SCRIPT, "").replaceAll(REG_EX_STYLE, "") .replaceAll(REG_EX_HTML, "").replaceAll(REG_EX_SPECIAL, ""); } /** * 删除HTML标签并格式化 * <li>去除特殊空格、全角空格、换行符、制表符、空格</li> * <li>去除多余空行</li> * <li>首行缩进,换行缩进</li> * <li>去除js标签、html标签</li> * @param srcStr 原始资讯正文内容(带HTML格式) * @return 删除HTML标签后的正文内容 */ public static String removeHtmlAndFormat(String srcStr) { return StringUtils.isBlank(srcStr) ? StringUtils.EMPTY : unescape(srcStr) // 去除特殊空格 .replaceAll("\\u00A0", "") // 去除全角空格 .replaceAll("\\u3000", "") // 去除换行符、制表符 .replaceAll("[\\t\\n\\r]", "") // 删除首行空格 .replaceFirst("\\s+", "") // 删除2个以上的空格 .replaceAll("\\s{2,}", "") // 首行缩进 .replaceFirst("", " ") // 去掉图片标签,排除干扰 .replaceAll("<(?i)img.*?\"\\s*/?\\s*>", "") // 去除多余空行 .replaceAll("<(?i)p>\\s*</(?i)p>", "") // 换行缩进(p标签) .replaceAll("<(?i)p>", "<p>\r\n ") // 换行缩进(p标签) .replaceAll("</(?i)p>", "<p>\r\n ") // 换行缩进(br标签) .replaceAll("</?(?i)br\\s?/?>", "\r\n ") // 换行缩进(tr标签) .replaceAll("</(?i)tr>", "\r\n ") // 空格(td标签) .replaceAll("</(?i)td>", " ") // 换行缩进(section标签) .replaceAll("</(?i)section>", "\r\n ") // 特殊嵌套标签需要优先去掉 .replaceAll(REG_EX_HTML_SP_START, "").replaceAll(REG_EX_HTML_SP_END, "") // 去除js标签 .replaceAll(REG_EX_SCRIPT, "").replaceAll(REG_EX_STYLE, "") // 去除html标签 .replaceAll(REG_EX_HTML, "").replaceAll(REG_EX_SPECIAL, "") // 去除多余空行 .replaceAll("\r\n\\s+\r\n", "\r\n"); } /** * 删除正文声明和记者声明 * @param srcStr 原资讯正文内容 * @return 过滤后的资讯正文内容 */ public static String removeStatementAndReporter(String srcStr) { return StringUtils.isBlank(srcStr) ? StringUtils.EMPTY : unescape(srcStr) .replaceAll(REG_EX_HTML_BLOCKQUOTE, "") .replaceAll(REG_EX_STATEMENT, "") .replaceAll(REG_EX_REPORTER, ""); } /** * HTML内容进行HTML标签转义 * <li>HTML标签转义举例:{@code <p> -> <p>}</li> * @param srcStr 原始内容 * @return 转码后的HTML内容 */ public static String unescape(String srcStr) { if (StringUtils.isBlank(srcStr)) { return StringUtils.EMPTY; } return StringEscapeUtils.unescapeHtml4(srcStr); } /** * 判断资讯正文是否包含图片 * @param content 资讯正文 * @return true-包含,false-不包含 */ public static boolean hasImg(String content) { if (StringUtils.isBlank(content)) { return false; } return extractImgPath(content).size() > 0; } /** * 抽取正文中的图片标签 * @param content 资讯正文 * @return 图片标签列表 */ public static List<String> extractImg(String content) { if (StringUtils.isBlank(content)) { return Collections.emptyList(); } Matcher matcher = HTML_IMG_PATTERN.matcher(content); List<String> result = new ArrayList<>(); while (matcher.find()) { result.add(matcher.group()); } return result; } /** * 抽取正文中的图片路径 * @param content 资讯正文 * @return 图片路径列表 */ public static List<String> extractImgPath(String content) { List<String> imgTags = extractImg(content); if (CollectionUtils.isEmpty(imgTags)) { return Collections.emptyList(); } List<String> result = new ArrayList<>(); for (String img : imgTags) { Matcher matcher = HTML_IMG_SRC_PATTERN.matcher(img); if (matcher.find()) { String url = extractUrl(matcher.group()); if (StringUtils.isNotBlank(url) && !url.startsWith(HTML_IMG_BASE_64_PREFIX)) { result.add(url); } } } return result.stream().distinct().collect(Collectors.toList()); } /** * 抽取图片链接 * @param src 图片src路径 * @return 图片链接 */ public static String extractUrl(String src) { try { return unescape(URLDecoder.decode(src.substring(src.indexOf("\"") + 1, src.lastIndexOf("\"")), "UTF8")); } catch (Exception e) { log.error("图片URL解码失败,原图片链接:{}", src); log.error(e.getMessage(), e); return StringUtils.EMPTY; } } /** * 替换正文OSS配图 * @param content 替换前正文内容 * @param imgList 正文OSS图片列表 * @return 替换后正文内容 */ public static String replaceImgPath(String content, List<UnifyImg> imgList) { if (hasImg(content) && !CollectionUtils.isEmpty(imgList)) { // 正文包含图片 Map<String, String> imgMap = imgList.stream().collect(Collectors.toMap(UnifyImg::getSrcImgUrl, UnifyImg::getFilePath)); Matcher matcher = HTML_IMG_PATTERN.matcher(content); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { // imgTag为完整img标签:<img src="https://n.sinaimg.cn/tech/transform/703/w630h73/20200804/3492-ixeeisa0456891.png"> String imgTag = matcher.group(); Matcher imgMatcher = HTML_IMG_SRC_PATTERN.matcher(imgTag); imgTag = imgTag.replaceFirst(" (?i)src", " data-src"); if (imgMatcher.find()) { String srcUrl = imgMatcher.group(); // imgUrl为图片链接:https://n.sinaimg.cn/tech/transform/703/w630h73/20200804/3492-ixeeisa0456891.png String imgUrl = srcUrl.substring(srcUrl.indexOf("\"") + 1, srcUrl.lastIndexOf("\"")); if (imgMap.containsKey(extractUrl(srcUrl))) { String imgRep = imgTag.replace(imgUrl, "/" + imgMap.getOrDefault(extractUrl(srcUrl), StringUtils.EMPTY)); matcher.appendReplacement(buffer, imgRep); } } else { matcher.appendReplacement(buffer, imgTag); } } matcher.appendTail(buffer); return buffer.toString(); } else { return content; } } /** * 格式化资讯html格式正文 * @param content 资讯html格式正文 * @return 格式化后的资讯正文 */ public static String formatHtml(String content) { return content + HTML_FORMAT_STYLE; } } 总结:使用正则匹配效果很好但是效率真的很低,因为全文匹配导致效率很慢,如果1万字的新闻内容,结果下来可能需要好几分钟!
还没有评论,来说两句吧...