网站自动化锚文本的实现逻辑

news2024/12/25 13:04:33

锚文本,‌即超链接的文本部分,‌它在网页中扮演着至关重要的角色。‌通过点击锚文本,‌用户可以方便地在网页间进行跳转,‌从而极大地提升了用户体验。‌同时,‌在搜索引擎优化(‌SEO)‌领域,‌锚文本也发挥着不可忽视的作用。‌搜索引擎会通过分析锚文本的内容,‌来判断链接页面的主题和相关性,‌进而影响页面的排名。‌因此,‌合理地设置锚文本,‌对于提升网站的SEO效果具有重要意义。‌

自动化锚文本实现的背景和需求

随着网站内容的不断增多,‌手动设置锚文本变得愈发繁琐和耗时。‌为了提高工作效率,‌减少人力成本,‌自动化锚文本的实现成为了迫切的需求。‌通过自动化手段,‌可以快速地生成大量的锚文本,‌提高网站的内链建设效率,‌进而提升网站的SEO效果。‌

锚文本的收集

在实现自动化锚文本之前,‌首先需要收集网站中的文本内容。‌下面以安企CMS的自动化锚文本功能为例,‌介绍锚文本的收集策略。‌

安企CMS提供了自动提取锚文本和手动提取锚文本两种收集锚文本的方式。如果选择了自动提取锚文本,那么程序就会在用户添加文章的时候,自动解析文章的关键词,并将关键词自动添加为当前文章的锚文本。手动处理的话,则提供了逐个关键词填写以及批量导入关键词的两种方式。
请添加图片描述

自动化锚文本的策略

制定自动化锚文本的策略是关键步骤之一。‌这包括确定锚文本的生成规则,‌如关键词的选择、‌锚文本的长度、‌出现的位置等。
请添加图片描述

  • 自定义锚文本密度
    安企CMS在处理锚文本的生成策略时,‌提供了自定义锚文本密度的选项,用户可以自主选择锚文本的密度。

  • 按关键词由长到短匹配
    安企CMS采用了长度优先的策略,就是说,如果内容中不同锚文本,优先使用长度最长的锚文本。内容里出现AAB这样的关键词时,锚文本会给AAB,而不是AA,或AB

  • 仅匹配一次
    如果文章中有多个相同的锚文本关键词,则只给第一个关键词添加上锚文本,而后续的关键词只进行加粗处理,保证一个内容里同一个关键词锚文本仅出现一次,同一个URL也只做一次锚文本,其它的则会加粗显示。

  • 锚文本生成方式
    安企CMS采用了长度优先的策略。就是说,如果有相同链接的不同锚文本,优先使用长度最长的锚文本。如果文章中有多个相同的锚文本关键词,则只给第一个关键词添加上锚文本,而后续的关键词只进行加粗处理。

安企CMS采用了自动插入关键词以及手动批量更新关键词两种方式,如果选择了自动插入关键词,则会在发布文章的时候,自动将文章中合适的关键词用锚文本来替代,实现锚文本的生成。如果选择了手动批量更新关键词,则会在锚文本页面中,提供批量更新锚文本的功能,用户可以按照自己的需求,手动更新锚文本。

自动化锚文本的实现代码

说明:由于安企CMS 使用的是 GoLang 开发,因此以下代码为 GoLang 语言的实现方式。

func AutoInsertAnchors(anchors []*model.Anchor, content string, link string) string {
	if len(anchors) == 0 {
		//没有关键词,终止执行
		return ""
	}

	//获取纯文本字数
	stripedContent := library.StripTags(content)
	contentLen := len([]rune(stripedContent))
  // 获取锚文本密度
	if PluginAnchor.AnchorDensity < 20 {
		//默认设置200
		PluginAnchor.AnchorDensity = 200
	}

	// 判断是否是Markdown,如果开头是标签,则认为不是Markdown
	isMarkdown := false
	if !strings.HasPrefix(strings.TrimSpace(content), "<") {
		isMarkdown = true
	}
	//计算最大可以替换的数量
	maxAnchorNum := int(math.Ceil(float64(contentLen) / float64(PluginAnchor.AnchorDensity)))
  // 定义一个替换结构体,用于存储替换的内容
	type replaceType struct {
		Key   string
		Value string
	}
  // 记录已存在的关键词和链接
	existsKeywords := map[string]bool{}
	existsLinks := map[string]bool{}

	var replacedMatch []*replaceType
	numCount := 0
	//所有的a标签计数,并临时替换掉,防止后续替换影响
	reg, _ := regexp.Compile("(?i)<a[^>]*>(.*?)</a>")
	content = reg.ReplaceAllStringFunc(content, func(s string) string {

		reg := regexp.MustCompile("(?i)<a\\s*[^>]*href=[\"']?([^\"']*)[\"']?[^>]*>(.*?)</a>")
		match := reg.FindStringSubmatch(s)
		if len(match) > 2 {
			existsKeywords[strings.ToLower(match[2])] = true
			existsLinks[strings.ToLower(match[1])] = true
		}

		key := fmt.Sprintf("{$%d}", numCount)
		replacedMatch = append(replacedMatch, &replaceType{
			Key:   key,
			Value: s,
		})
		numCount++

		return key
	})
	//所有的strong标签替换掉
	reg, _ = regexp.Compile("(?i)<strong[^>]*>(.*?)</strong>")
	content = reg.ReplaceAllStringFunc(content, func(s string) string {
		key := fmt.Sprintf("{$%d}", numCount)
		replacedMatch = append(replacedMatch, &replaceType{
			Key:   key,
			Value: s,
		})
		numCount++

		return key
	})
  // 匹配 Markdown 格式的锚文本,同时要考虑别替换掉图片
	// [keyword](url)
	reg, _ = regexp.Compile(`(?i)(.?)\[(.*?)]\((.*?)\)`)
	content = reg.ReplaceAllStringFunc(content, func(s string) string {
		match := reg.FindStringSubmatch(s)
		if len(match) > 2 && match[1] != "!" {
			existsKeywords[strings.ToLower(match[2])] = true
			existsLinks[strings.ToLower(match[3])] = true
		}

		key := fmt.Sprintf("{$%d}", numCount)
		replacedMatch = append(replacedMatch, &replaceType{
			Key:   key,
			Value: s,
		})
		numCount++

		return key
	})
  // Markdown 格式的加粗
	// **Keyword**
	reg, _ = regexp.Compile(`(?i)\*\*(.*?)\*\*`)
	content = reg.ReplaceAllStringFunc(content, func(s string) string {
		key := fmt.Sprintf("{$%d}", numCount)
		replacedMatch = append(replacedMatch, &replaceType{
			Key:   key,
			Value: s,
		})
		numCount++

		return key
	})
	//过滤所有属性,防止在自动锚文本的时候,会将标签属性也替换
	reg, _ = regexp.Compile("(?i)</?[a-z0-9]+(\\s+[^>]+)>")
	content = reg.ReplaceAllStringFunc(content, func(s string) string {
		key := fmt.Sprintf("{$%d}", numCount)
		replacedMatch = append(replacedMatch, &replaceType{
			Key:   key,
			Value: s,
		})
		numCount++

		return key
	})

	if len(existsLinks) < maxAnchorNum {
		//开始替换关键词
		for _, anchor := range anchors {
			if anchor.Title == "" {
				continue
			}
			if strings.HasSuffix(anchor.Link, link) {
				//遇到当前url,跳过
				continue
			}
			//已经存在存在的关键词,或者链接,跳过
			if existsKeywords[strings.ToLower(anchor.Title)] || existsLinks[strings.ToLower(anchor.Link)] {
				continue
			}
			//开始替换
			replaceNum := 0
			replacer := strings.NewReplacer("\\", "\\\\", "/", "\\/", "{", "\\{", "}", "\\}", "^", "\\^", "$", "\\$", "*", "\\*", "+", "\\+", "?", "\\?", ".", "\\.", "|", "\\|", "-", "\\-", "[", "\\[", "]", "\\]", "(", "\\(", ")", "\\)")
			matchName := replacer.Replace(anchor.Title)

			reg, _ = regexp.Compile(fmt.Sprintf("(?i)%s", matchName))
			content = reg.ReplaceAllStringFunc(content, func(s string) string {
				replaceHtml := ""
				key := ""
				if replaceNum == 0 {
					//第一条替换为锚文本
					if isMarkdown {
						replaceHtml = fmt.Sprintf("[%s](%s)", s, anchor.Link)
					} else {
						replaceHtml = fmt.Sprintf("<a href=\"%s\" data-anchor=\"%d\">%s</a>", anchor.Link, anchor.Id, s)
					}
					key = fmt.Sprintf("{$%d}", numCount)

					//加入计数
					existsLinks[anchor.Link] = true
					existsKeywords[anchor.Title] = true
				} else {
					//其他则加粗
					if isMarkdown {
						replaceHtml = fmt.Sprintf("**%s**", s)
					} else {
						replaceHtml = fmt.Sprintf("<strong data-anchor=\"%d\">%s</strong>", anchor.Id, s)
					}
					key = fmt.Sprintf("{$%d}", numCount)
				}
				replaceNum++

				replacedMatch = append(replacedMatch, &replaceType{
					Key:   key,
					Value: replaceHtml,
				})
				numCount++

				return key
			})

			//判断数量是否达到了,达到了就跳出
			if len(existsLinks) >= maxAnchorNum {
				break
			}
		}
	}

	//关键词替换完毕,将原来替换的重新替换回去,需要倒序
	for i := len(replacedMatch) - 1; i >= 0; i-- {
		content = strings.Replace(content, replacedMatch[i].Key, replacedMatch[i].Value, 1)
	}

  // 返回替换后的内容
	return content
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea 修改背景图片教程

&#x1f30f;个人博客主页&#xff1a;意疏-CSDN博客 希望文章能够给到初学的你一些启发&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏支持一下笔者吧&#xff5e; 阅读指南&#xff1a; 开篇说明修改背景图片 开篇说明 给小白看得懂的修改图片教程&…

Spring项目:文字花园(三)

一.实现博客详情 1.后端逻辑代码 controller层添加方法&#xff08;根据博客id查看博客详情&#xff09; RequestMapping("/getBlogDetail")public Result<BlogInfo> getBlogDetail(Integer blogId){log.info("getBlogDetail, blogId: {}", blogId…

并发编程 | Future是如何优化程序性能

在初识Future一文中介绍了Future的核心方法。本文中接着介绍如何用Future优化我们的程序性能。 在此之前&#xff0c;有必要介绍Future接口的一个实现类FutureTask。 FutureTask介绍 FutureTask继承结构 首先我们看一下FutureTask的继承结构&#xff1a; public class Futur…

JUC阻塞队列(二):LinkedBlockingQueue

1、LinkedBlockingQueue 介绍 LinkedBlockingQueue 也是接口BlockingQueue的一个实现类&#xff0c;与 ArrrayBlockingQueue基于 数组实现不同的是&#xff0c;LinkedBlockingQueue是基于单项链表实现的&#xff0c;在LinkedBlockingQueue 内部维护了一个单向链表来存储数据&am…

探索深度学习的力量:从人工智能到计算机视觉的未来科技革命

目录 1. 引言 2. 人工智能的历史背景 3. 深度学习的崛起 3.1 深度神经网络的基本原理 4. 计算机视觉的发展现状 4.1 传统计算机视觉与深度学习的结合 5. 深度学习在计算机视觉中的应用 5.1 图像分类 5.2 目标检测 6. 深度学习引领的未来科技创新与变革 7. 结论 引言…

opencv cv.findContours 函数图像轮廓层级(记录)

opencv cv.findContours 函数详解 图像轮廓层级 图像轮廓检索方式 cv.findContours contours, hierarchy cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] ) 参数1&#xff1a;源图像 参数2&#xff1a;轮廓的检索方式&#xff0c;主要参数 参数3…

专题--自底向上的计算机网络(物理层)

目录 计算机网络概述 物理层 数据链路层 网络层 运输层 应用层 网络安全 详细见http://t.csdnimg.cn/MY5aI http://t.csdnimg.cn/8Ipa4 http://t.csdnimg.cn/uvMxS

康耐视相机与发那科机器人通过Ethernet I/P直连与程序编写

配置TCP/IP&#xff1a;按MENU—SETUP—NEXT—HOSTCOMM&#xff0c;选择TCP/IP—按ENTER或者F3[DETAIL] Port#1 IP addr&#xff1a;输入机器人IP地址&#xff0c;按ENTER后输入&#xff0c;如192.168.1.11&#xff1b;如果控制柜有2个网络端口&#xff0c;则按F3[PORT]进行切换…

科创中心“核”动力|趋动科技:AI算力界的领跑者

近日&#xff0c;趋动科技与深信服正式推出联合解决方案。联合解决方案将深信服EDS的高性能存储与趋动科技OrionX AI算力资源池化软件、以及GeminiAI训练平台有机结合&#xff0c;整合存力与算力资源的同时&#xff0c;帮助用户建好AI平台、管好AI资源、用好AI服务。 双方已完成…

监控zabbix的安装与使用

文章目录 1.zabbix的安装步骤2.zabbix的主动模式和被动模式简介及实现3.zabbix proxy主动及被动4.自定义监控&#xff0c;监控linux和连接状态&#xff0c;创建email进行基础报警5.部署zabbix agent脚本&#xff0c;适配rocky和ubuntu系统6.使用脚本&#xff0c;基于zabbix api…

yolov8旋转框+关键点检测

一、Yolov8obb_kpt -----------------------------------现已在v8官方库上更新旋转框分割算法和旋转框关键点检测算法-------------------------- ------------------------------------------- https://github.com/yzqxy/ultralytics-obb_segment---------------------------…

每天五分钟深度学习框架pytorch:自动求导机制

本文重点 深度学习框架pytorch拥有自动求导的机制,自动求导是 PyTorch 中非常重要的特性,能够让我们避免手动去计算非常复杂的导数,这能够极大地减少了我们构建模型的时间。本文学习的是第10步反向传播,学习路线参考前面一篇文章。 pytorch0.4版本 在pytorch的0.4版本中…

YOLO知识点总结:

分类&#xff1a; 即是将图像结构化为某一类别的信息&#xff0c;用事先确定好的类别(category)或实例ID来描述图片。这一任务是最简单、最基础的图像理解任务&#xff0c;也是深度学习模型最先取得突破和实现大规模应用的任务。其中&#xff0c;ImageNet是最权威的评测集&…

C语言刷题日记(附详解)(1)

一、选择判断部分 第一题&#xff1a; 如下代码是否存在风险&#xff0c;并说明原因和修改方案 #include<stdio.h> int main() {char* str "hello world";*str a;return 0; }思路提示&#xff1a;这种形式的字符串存储在什么区域呢&#xff1f;是否真的有…

【个人笔记公司项目】vue项目配置代理解决跨域问题

前后端分离模式势必会遇到跨域问题&#xff0c;比如我是10.106.46.169:8080要去请求10.114.46.108:9191。下面讲下代理详细步骤。 本文步骤基于本人的项目结构 一般项目结构已支持代理 // 部署时需要将改开关置为false window.isDev trueif (window.isDev) { // Devwindow.l…

计算机网络速成(二)

计算机网络面试&#xff08;二&#xff09;-CSDN博客 OSI七层体系架构 OSI七层模型是什么&#xff1f;每层的功能是什么&#xff1f; OSI七层模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系&#xff0c;它从上到下分别是&am…

揭秘“商业园区综合管理平台”的无代码开发流程!

本文中的素材来自我在某国资投资集团朋友小赵的“有偿”投稿&#xff0c;要知道现在的商业园区也正在经历数字化改造&#xff0c;面对多商场、多店铺的复杂管理需求&#xff0c;各类商管集团纷纷进行线上互联网管理模式的转型。 这份素材有何不同之处呢&#xff1f;因为他们走了…

EthernetIP IO从站设备数据 转IEC61850项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 网关采集ETHERNETIP IO数据 2 5 用IEC61850协议转发数据 4 6 网关使用多个逻辑设备和逻辑节点的方法 6 7 从设备的的EDS文件获取参数信息 8 8 案例总结 10 1 案例说明 设置网关采集EthernetIP IO设备数据把采集的数据…

成功解决:el-popconfirm组件来确认删除、修改等操作无效

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

深入理解java web分层架构的高内聚低耦合

​ 在软件开发中&#xff0c;构建一个高效、可维护且可扩展的应用系统一直是开发者追求的目标。分层架构和依赖注入&#xff08;IOC&#xff09;是实现这一目标的重要策略。本文将深入探讨三层架构的高内聚特性、低耦合的设计原则&#xff0c;以及如何通过IOC&#xff08;控制反…