最近,我帮助我的一个团队成员诊断一个新的潜在客户站点,以找到一些唾手可得的成果与他们分享。
当我用我们的Chrome扩展查看他们的主页时,我发现一个放错地方的canonical标签。很久以前,当我第一次遇到这个问题时,我们就添加了这种类型的检测。
你可能会问,什么是放错位置的SEO标签?
大多数SEO标签,如标题、元描述、规范等,都属于HTML头。如果它们被放在HTML主体中,谷歌和其他搜索引擎将忽略它们。
如果转到Elements选项卡,您将发现标签内的SEO标签。但是,这些标签应该在!
为什么会发生这样的事情?
如果我们使用VIEW SOURCE检查页面,规范标记就被正确地放置在HTML头部中(第56行,而在第139行)。
这是怎么回事?!
这是谷歌Chrome的问题吗?
规范也被放在Firefox的正文中。
我们对Internet Explorer也有同样的问题。
Edge也不例外。
其他浏览器也有同样的问题。
HTML解析与语法高亮显示
为什么当我们检查查看源时,规范的位置是正确的,而当我们在Elements选项卡中检查时却不正确?
为了理解这一点,我需要介绍几个开发人员的概念:词法分析和语法分析。
当我们使用VIEW source加载一个源页面时,浏览器会自动为编程标记(HTML标签、HTML注释等)着色。
为此,浏览器执行基本的词法分析,将源页面分解为HTML标记。
该任务通常由lexer执行。这是一个简单、低级的任务。
所有编程语言编译器和解释器都使用一个lexer,它可以将源文本分解成语言标记。
当我们用Elements选项卡加载源页面时,浏览器不仅会突出显示语法,而且还会构建一个DOM树。
为了构建DOM树,仅仅了解常规文本中的HTML标记和注释是不够的,还需要知道标记何时打开和关闭,以及它们在树层次结构中的位置。
这种语法分析需要一个解析器。
英语拼写检查器需要对书面文本执行类似的两阶段分析。首先要把文本翻译成名词、代词、副词等。然后,它需要应用语法规则,以确保语音标记部分的顺序正确。
但为什么SEO标签放在HTML主体?
用Python解析HTML
我编写了一个Python脚本来获取和解析一些带有错误的示例页面,在HTML中的任何地方找到规范,并打印找到它的DOM路径。
从requests_html导入HTMLSession
#递归地构建DOM路径
def build_dom_path(元素、路径):
如果元素为None:
返回路径
其他:
path.append (element.tag)
返回build_dom_path (element.getparent(),路径)
def get_canonical_path (url):
打印(url)
会话= HTMLSession ()
r = session.get (url)
打印(r.status_code)
如果r.status_code == 200:
= r.html.xpath(“/ /链接[@rel = ‘标准’]”)
dom_path =列表()
if len(out) >:
dom_path = build_dom_path([0]。元素,dom_path)
dom_path.reverse ()
fixed_dom_path = ” + ” . join (dom_path)
打印(fixed_dom_path)
规范= r.html.xpath (fixed_dom_path)
打印(“发现:”+ str(规范)
url = ” http://www.example.com ”
get_canonical_path (url)
#输出
# http://www.example.com
# 200
# / html /头/链接
#Found: []
解析了在HTML主体中显示错误的SEO标记的同一页面后,我发现它们被正确地放在了HTML head中。
我们遗漏了什么?
HTML头中的无效标记
有些HTML标记只在HTML主体中有效。例如,
和标签在HTML head中是无效的。
当我仔细查看我们示例中的HTML HEAD时,我发现一个带有硬编码的脚本。这意味着,该脚本本应放在中,但用户错误地将其放在了head中。
可能是说明不清楚,供应商忽略了这些信息,或者用户不知道如何在WordPress中做到这一点。
我通过将脚本移动到主体进行测试,但仍然面临规范错位的问题。
经过一些尝试和错误,我找到了另一个脚本,当我把它移到主体,这个问题消失了。
虽然第二个脚本没有任何硬编码的无效标记,但它可能会向DOM写入一个或多个标记。
换句话说,它是动态的。
但是,为什么插入无效标记会导致浏览器将头部的其余HTML推送到body中呢?