網(wǎng)站自動化錨文本實現(xiàn)的邏輯

錨文本,即超鏈接的文本部分,它在網(wǎng)頁中扮演著至關(guān)重要的角色。通過點擊錨文本,用戶可以方便地在網(wǎng)頁間進(jìn)行跳轉(zhuǎn),從而極大地提升了用戶體驗。同時,在搜索引擎優(yōu)化(SEO)領(lǐng)域,錨文本也發(fā)揮著不可忽視的作用。搜索引擎會通過分析錨文本的內(nèi)容,來判斷鏈接頁面的主題和相關(guān)性,進(jìn)而影響頁面的排名。因此,合理地設(shè)置錨文本,對于提升網(wǎng)站的SEO效果具有重要意義。

自動化錨文本實現(xiàn)的背景和需求

隨著網(wǎng)站內(nèi)容的不斷增多,手動設(shè)置錨文本變得愈發(fā)繁瑣和耗時。為了提高工作效率,減少人力成本,自動化錨文本的實現(xiàn)成為了迫切的需求。通過自動化手段,可以快速地生成大量的錨文本,提高網(wǎng)站的內(nèi)鏈建設(shè)效率,進(jìn)而提升網(wǎng)站的SEO效果。

錨文本的收集

在實現(xiàn)自動化錨文本之前,首先需要收集網(wǎng)站中的文本內(nèi)容。下面以安企CMS的自動化錨文本功能為例,介紹錨文本的收集策略。

安企CMS提供了自動提取錨文本和手動提取錨文本兩種收集錨文本的方式。如果選擇了自動提取錨文本,那么程序就會在用戶添加文章的時候,自動解析文章的關(guān)鍵詞,并將關(guān)鍵詞自動添加為當(dāng)前文章的錨文本。手動處理的話,則提供了逐個關(guān)鍵詞填寫以及批量導(dǎo)入關(guān)鍵詞的兩種方式。


anchor1.png

自動化錨文本的策略

制定自動化錨文本的策略是關(guān)鍵步驟之一。這包括確定錨文本的生成規(guī)則,如關(guān)鍵詞的選擇、錨文本的長度、出現(xiàn)的位置等。


anchor2.png
  • 自定義錨文本密度
    安企CMS在處理錨文本的生成策略時,提供了自定義錨文本密度的選項,用戶可以自主選擇錨文本的密度。

  • 按關(guān)鍵詞由長到短匹配
    安企CMS采用了長度優(yōu)先的策略,就是說,如果內(nèi)容中不同錨文本,優(yōu)先使用長度最長的錨文本。內(nèi)容里出現(xiàn)AAB這樣的關(guān)鍵詞時,錨文本會給AAB,而不是AA,或AB

  • 僅匹配一次
    如果文章中有多個相同的錨文本關(guān)鍵詞,則只給第一個關(guān)鍵詞添加上錨文本,而后續(xù)的關(guān)鍵詞只進(jìn)行加粗處理,保證一個內(nèi)容里同一個關(guān)鍵詞錨文本僅出現(xiàn)一次,同一個URL也只做一次錨文本,其它的則會加粗顯示。

  • 錨文本生成方式
    安企CMS采用了長度優(yōu)先的策略。就是說,如果有相同鏈接的不同錨文本,優(yōu)先使用長度最長的錨文本。如果文章中有多個相同的錨文本關(guān)鍵詞,則只給第一個關(guān)鍵詞添加上錨文本,而后續(xù)的關(guān)鍵詞只進(jìn)行加粗處理。

安企CMS采用了自動插入關(guān)鍵詞以及手動批量更新關(guān)鍵詞兩種方式,如果選擇了自動插入關(guān)鍵詞,則會在發(fā)布文章的時候,自動將文章中合適的關(guān)鍵詞用錨文本來替代,實現(xiàn)錨文本的生成。如果選擇了手動批量更新關(guān)鍵詞,則會在錨文本頁面中,提供批量更新錨文本的功能,用戶可以按照自己的需求,手動更新錨文本。

自動化錨文本的實現(xiàn)代碼

說明:由于安企CMS 使用的是 GoLang 開發(fā),因此以下代碼為 GoLang 語言的實現(xiàn)方式。

func AutoInsertAnchors(anchors []*model.Anchor, content string, link string) string {
    if len(anchors) == 0 {
        //沒有關(guān)鍵詞,終止執(zhí)行
        return ""
    }

    //獲取純文本字?jǐn)?shù)
    stripedContent := library.StripTags(content)
    contentLen := len([]rune(stripedContent))
  // 獲取錨文本密度
    if PluginAnchor.AnchorDensity < 20 {
        //默認(rèn)設(shè)置200
        PluginAnchor.AnchorDensity = 200
    }

    // 判斷是否是Markdown,如果開頭是標(biāo)簽,則認(rèn)為不是Markdown
    isMarkdown := false
    if !strings.HasPrefix(strings.TrimSpace(content), "<") {
        isMarkdown = true
    }
    //計算最大可以替換的數(shù)量
    maxAnchorNum := int(math.Ceil(float64(contentLen) / float64(PluginAnchor.AnchorDensity)))
  // 定義一個替換結(jié)構(gòu)體,用于存儲替換的內(nèi)容
    type replaceType struct {
        Key   string
        Value string
    }
  // 記錄已存在的關(guān)鍵詞和鏈接
    existsKeywords := map[string]bool{}
    existsLinks := map[string]bool{}

    var replacedMatch []*replaceType
    numCount := 0
    //所有的a標(biāo)簽計數(shù),并臨時替換掉,防止后續(xù)替換影響
    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標(biāo)簽替換掉
    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
    })
    //過濾所有屬性,防止在自動錨文本的時候,會將標(biāo)簽屬性也替換
    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 {
        //開始替換關(guān)鍵詞
        for _, anchor := range anchors {
            if anchor.Title == "" {
                continue
            }
            if strings.HasSuffix(anchor.Link, link) {
                //遇到當(dāng)前url,跳過
                continue
            }
            //已經(jīng)存在存在的關(guān)鍵詞,或者鏈接,跳過
            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)

                    //加入計數(shù)
                    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
            })

            //判斷數(shù)量是否達(dá)到了,達(dá)到了就跳出
            if len(existsLinks) >= maxAnchorNum {
                break
            }
        }
    }

    //關(guān)鍵詞替換完畢,將原來替換的重新替換回去,需要倒序
    for i := len(replacedMatch) - 1; i >= 0; i-- {
        content = strings.Replace(content, replacedMatch[i].Key, replacedMatch[i].Value, 1)
    }

  // 返回替換后的內(nèi)容
    return content
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容