大多数网站都会使用某些 JavaScript 来增加交互功能和改善用户体验。有的网站使用 JavaScript 来实现菜单功能,有的使用它来抓取产品或者价格信息,有的使用它从多个源获取内容,在某些情况下,网站会全站使用 JavaScript。当今互联网的现实是:JavaScript 无处不在。
正如 Google 的 John Mueller 所说:
The web has moved from plain HTML — as an SEO you can embrace that. Learn from JS devs & share SEO knowledge with them. JS’s not going away.
— 🍌 John 🍌 (@JohnMu) August 8, 2017
译:互联网已经走过了纯 HTML 的时代 —— 作为一名 SEO 从业人员你已经拥抱新的时代。从 JS 开发人员那里学习,并和他们分享 SEO 的相关知识。JS 不会消失。
我并不是在说 SEO 从业人员应该走出去学习 JavaScript 编程。情况正好相反。SEO 从业人员主要需要知道 Google 是如何处理 JavaScript 的,以及遇到相关问题时如何解决。甚至在极少数情况下,SEO 从业人员才会被允许去碰代码。我的目标是通过这篇文章帮助你学习:
JavaScript SEO 是技术 SEO(搜索引擎优化)的一部分,旨在使包含较多 JavaScript 网站容易被抓取和索引,以及更加搜索引擎友好。目标是为了使这些网站可以被搜索引擎发现,并获得更高的排名。
JavaScript 对 SEO 是有害的吗?JavaScript 是魔鬼吗?完全不是。它只是与许多 SEO 从业人员熟悉的不一样,同时也有一点学习曲线。人们倾向于在一些可能有更好的解决方案的事情上过度使用 JavaScript,但你有时不得不随遇而安。你只需要知道 JavaScript 不是完美的,它不总是适合某项工作的工具。JavaScript 不能像 HTML 和 CSS 那样被逐步解析,它可以很“重”,对页面加载和性能造成影响。许多情况下,你可能在用性能换功能。
在搜索引擎早期,一个下载了的 HTML 响应就足以查看大多数页面的内容。但是随着 JavaScript 的兴起,搜索引擎现在需要像浏览器一样去渲染许多页面,这样他们就能像用户一样查看内容。
Google 用于处理渲染流程的系统叫做网页渲染服务(Web Rendering Service, WRS)。Google 提供了一个简单的图表来展示它的工作原理。
假设我们从某个链接开始这个流程。
1. 爬虫
爬虫向服务器发送 GET 请求。服务器用文件头和内容响应,接着被保存。
因为 Google 现在使用了移动优先索引,所以这个请求很可能来自移动用户代理。你可以通过站长工具中的链接检查工具来了解 Google 是如何抓取你的网站的。当你对某个链接执行这个流程时,查看“当时所用的用户代理”,它可以告诉你索引时使用的是桌面版本还是已经使用移动优先版本了。
这些请求大部分来自美国加州的山景城,但是在抓取一些地区性适应的页面时,这些请求会来自美国以外的地区。我提到这一点是因为有的网站会屏蔽或者区别对待来自特定国家或者使用特定 IP 地址的访客,这会导致 Google 爬虫无法读取你的内容。
有些网站可能还会使用用户代理侦测来向特定的爬虫展示(特定的)内容。尤其是对 JavaScript 站点来说,Google 读取到的内容可能和用户看到的有区别。这就是为什么站长工具中的网址检查工具、移动友好性测试工具和富媒体搜索结果测试工具对解决 JavaScript SEO 问题非常重要。他们可以显示 Google 读取到的内容是什么,这对查看 Google 爬虫是否被屏蔽以及他们是否可以读取网页的内容很有帮助。因为在下载的 GET 请求、渲染的页面、甚至测试工具间存在着一些关键的区别,我将在渲染器一节中介绍如何测试。
同样需要注意的是,虽然上图中 Google 将抓取过程的输出称为“HTML”,但实际上他们抓取并存储了页面生成所需的全部资源,包括 HTML 页面、Javascript 文件、层叠样式表、XHR 请求、应用程序接口端点等等。
2. 处理
许多系统都被图片中的“处理”一词混淆了。这里我介绍几种与 JavaScript 相关的处理。
资源和链接
Google 不会像用户那样从一个页面导航至另一个页面。“处理”的部分工作是检查页面中指向其他页面的链接以及生成页面所需的文件。这些链接被提取并放入抓取队列中,Google 接着会确立优先级并安排页面抓取计划。
Google 会从 <link>
等标签中提取生成页面所需要的资源链接(层叠样式表、JS 等)。然而,指向其他页面的链接必须是特定的格式才能被 Google 视作链接。内部链接和外部链接必须是带有href
属性的 <a>
标签才可以。对于使用了搜索不友好的 JavaScripit 用户来说,有许多方法来使链接工作。
可以:
<a href="/page">简单就好</a> <a href="/page" onclick="goTo(‘page’)">还算行吧</a>
不行:
<a onclick="goTo(‘page’)">不行,没有 href 属性</a> <a href="javascript:goTo(‘page’)">不行,没有链接</a> <a href="javascript:void(0)">不行,没有链接</a>
<span onclick=“goTo(‘page’)”>不是正确的 HTML 元素</span> <option value=“page”>不行,错误的 HTMl 元素</option> <a href=”#”>没有链接</a> Button, ng-click, there are many more ways this can be done incorrectly. 按钮、ng 点击,错误的做法还有很多。
同样值得注意的是使用 JavaScript 添加的内部链接只有渲染后才会被抓取。这个流程相对较快,在大多数情况下不需要担心。
缓存
Google 下载的每一个文件,包括 HTML 页面、JavaScript 文件、层叠样式表文件等,都会被主动缓存。Google 会无视你的缓存时间设置,在需要的时候获取一个副本。后面我将讨论更多这方面的内容,并在渲染器一节讨论它的重要性。
重复剔除
在发送渲染之前,重复内容可能会从下载的 HTML 代码中剔除,或者不优先考虑。对于应用外壳模型来说,只有很少的内容或者代码会在 HTML 反馈中显示。实际上,网站上的每一个页面可能会显示同样的代码,而这些代码与多个网站的代码可能是一样的。有时候这会导致网页被作为重复内容对待而不立刻进行渲染。更糟糕的是,错误的内容甚至错误的网站会显示在搜索结果中。随着时间的推移,这个问题会自己消失,但这依然是有问题的,尤其是对于新网站来说。
最严指令
Google 会在页面的 HTML 和渲染版本中选取最严格的语句。如果 JavaScript 修改了某语句,并且和 HTML 语句冲突,Google 会只遵循最严格的那一个。Noindex 将覆盖 index,同时 HTML 中的 noindex 证据会整个跳过渲染。
3. 渲染队列
现在每一个页面都进入了渲染器。许多和 JavaScript 以及两级索引(先是 HTML,接着是渲染过后的页面)打交道的 SEO 从业人员最大的担忧之一是页面可能几天甚至几周都没有被渲染。在 Google 对此进行调查之后,发现页面进入渲染器时间的中位数为 5 秒钟,而 90% 的时候都是以分钟计算的。因此在大多数情况下,获得页面的 HTML 版本和进行两级索引的时间间隔不是问题。
4. 渲染器
Google 使用渲染器来对网站进行渲染,以了解其在用户眼中的样子。在渲染器中,他们会将 JavaScript 及任何 JavaScript 生成的变化处理进文档对象模型(Document Object Model, DOM)。
为此,Google 使用的一款现在“常青”的无头 Chrome 浏览器,这意味着他应该使用最新的 Chrome 版本,并支持最新的特性。直到最近,Google 还在使用 Chrome 41 进行渲染,众多特性都没有支持。
Google 提供了更多关于网页渲染服务的信息,其中包括了像拒绝权限、无状态、扁平化轻量 DOM 和影子 DOM 这样值得一读的内容。
在全网范围展开渲染可能是世界第八大奇迹。这是一项严肃的任务,需要消耗大量的资源。由于渲染对象体量的关系,Google 为了加快速度在渲染过程中使用了许多捷径。Ahrefs 是唯一能够进行大规模网页渲染的主流 SEO 工具,我们在一天内可以渲染 1.5 亿个网页来使我们的链接索引更加完整。它使我们能够检查 JavaScript 重定向,并展示出我们找到的通过 JavaScript 插入链接,在链接相关报告中,我们会在对应位置加入 JS 标签。
缓存的资源
Google 非常依赖对资源进行缓存。网页被缓存;文件被缓存;应用程序接口请求被缓存;基本上,所有内容在被送进渲染器之前,Google 都会对他们进行缓存。他们不会在每次页面加载的时候重装下载页面,而会使用缓存的资源来加速流程。
这会导致一些罕见的状态:过去版本的文件被用于渲染流程,而索引了的版本可能了包含了部分旧文件。当出现较大修改的时候,你可以使用版本控制或者内容指纹特性来生成新的文件。这样在渲染时 Google 就不得不下载资源的最新版本。
无固定超时
一个常见的 SEO 迷思是渲染器在载入你的网页时仅仅等待 5 分钟。尽管让你的网站加载更快总是好的,但是对于上面提到的 Google 缓存文件的方式,这个迷思没有任意意义。基本上他们载入的内容都是事先缓存好的。这个迷思来自像网址检查工具(URL Inspection Tool)这样的工具,他们实时抓取内容,需要设置一个合理的限制。
对于渲染器来说并没有固定的超时。他们的做法和公共的 Rendertron 相似。他们可能会等待 networkidle0 出现,此时没有更多的网络活动在发生,他们还会设置一个最大时间值以防出现问题或者有人在他们的页面上挖比特币。
看到的内容
Googlebot 不会在网页上采取任何行动。他们不会点击内容,也不会滚动屏幕,但这并不意味着他们没有变通的办法。对于内容来说,只要它是在 DOM 中加载且不需要某个动作,Googlebot 就能看见它。我会在故障排除中介绍更多这方面的内容,但是基本上只要是存在在 DOM 中的非隐藏内容,它就能被 Googlebot 看见。如果只有在点击后,该内容才会被加载进入 DOM,那他们就不会被发现。
因为 Google 有一个聪明的变通方法,所以他们也不需要通过滚动屏幕来查看你的内容。在移动端,他们会以 411x731 的尺寸加载网页,接着将长度修改为 12,140 像素。这就相当于一部相当长的手机,尺寸为 411x12140 像素。在桌面端,他们会进行同样的操作,尺寸由 1024x768 像素变成 1024x9307 像素。
另一个有趣的捷径是 Google 不会在载入过程中渲染像素。它会付出时间和额外的资源来等页面加载完成,同时他们也无需看到像素完全渲染后的最终形态。他们只需要了解页面的结构和而已,为此他们并不需要真的去渲染像素。就如同 Google 的 Martin Splitt 所说:
https://youtube.com/watch?v=Qxd_d9m9vzo%3Fstart%3D154
译:在 Google 搜索中我们并不十分关心像素,因为我们并不需要将它展示给谁看。我们想要处理这些(语义)信息,因此我们需要一些中间态的东西。我们并不需要真的去渲染像素。
可视化信息可能更有助于解释相关原理。在 Chrome 开发者工具中,如果你在性能标签页开展一个测试,可以获得一个载入图表。实绿色部分代表了渲染过程,对 Googlebot 来说,这是不可能发生的,于是他们节省下了资源。
灰色 = 下载
蓝色 = HTML
黄色 = JavaScript
紫色 = 布局
绿色 = 渲染
5. 抓取队列
Google 有一处资源提到了一些抓取预算的内容,但是你应该知道每个网站都有它自己的抓取预算,且每次请求都应该区分优先级。Google 同时需要在对你站点的抓取和互联网其他页面的抓取之间找到平衡。通常来说,抓取较新的网站和包括较多动态页面的网站会比较慢。某些网页的更新频率会比其他页面慢,一些资源的请求频率有时也会较少。
JavaScript 网站的一个“陷阱”是他们只会更新 DOM 的若干部分。以用户身份浏览另外一个页面可能并不会更新 DOM 中像标题标签和权威标签等珍贵的部分,但是这对搜索引擎来说可能并不是一个问题。记住,Google 载入的每个页面是无状态的,所以他们并不保存之前的信息,因此也不会在页面间跳转。我见过有些 SEO 从业人员遇到麻烦,因为他们看到了从一个页面跳转到另外一个页面时发生的时间,如权威标签没有更新等,但是 Google 可能永远也看不到这样的状态。开发者可以通过使用 History API 来更新状态以进行修复,但同样这可能并不是一个问题。刷新页面,查看你看到的内容,或者更好的做法是在 Google 的测试工具中开展测试,了解他们看到的内容。稍后会做详细介绍。
查看源代码 vs. 检查
当你在浏览器窗口右击鼠标时,会看到查看页面源代码和检查页面的两个选项。查看源代码展示的内容与 GET 请求一致。这是页面的原始 HTML。而检查功能展示的是改变已经发生了的处理过后的文档对象模式,它更接近 Googlebot 看到的内容。基本上它是页面的最新版本。在处理 JavaScript 网站时,比起查看源代码功能,你应该更多地使用检查功能。
Google 缓存
使用 Google 缓存来查看 Googlebot 所看到的内容并不是一种可靠的方式。通常情况下,它是初始的 HTML,尽管有时也会是渲染好的 HTML 或者是早先的版本。这套系统的初衷是方便用户在网站已经下线的情况下查看内容。作为调试工具,它并不是特别有用。
Google 的测试工具
来自 Google 的测试工具,像站长工具中的网址检查工具、移动设备适合性测试工具和丰富结果测试工具对于排除故障很有用。尽管如此,这些工具看到的和 Google 看到的内容还是略有不同。我们已经讨论了这些工具中存在的渲染器中不存在的 5 种超时,此外,这些工具的不同之处还在于他们是实时抓取资源,而不像渲染器那样使用缓存版本。这些工具中的截图还展示了经过像素渲染之后的页面,Google 在渲染器中看不到的。
然而,这些工具在查看内容是否为 DOM 加载时很有用。这些工具中显示的 HTML 是渲染后的 DOM。你可以搜索一小段文本来查看它是否默认加载了。
这些工具还可以展示哪些资源可能被屏蔽了,以及对故障排除有用的主机错误信息。
在 Google 中搜索文本
另外一种快速的检查方法是在 Google 中搜索内容的一小段文本。搜索“内容中的几句话”,接着查看该页面是否返回了。如果返回了,那么你的内容就是可见的。请注意默认隐藏的内容可能不会在搜索引擎结果页面中的片段中显示。
Ahrefs
与链接索引渲染页面一起,你可以在 Ahrefs 的网站诊断抓取中激活 JavaScript 以在审计报告中解锁更多数据。
Ahrefs 工具栏也支持 JavaScript,允许你将标签的 HTML 版本和渲染过后的版本进行比较。
在对 JavaScript 渲染时,有很多选项。关于这点,Google 有张很棒的图表,接下来我会展示。对于搜索引擎来说,任何一种服务器端渲染、静态渲染和预加载渲染都是可以的。导致各种问题的主要是完全的客户端加载,这种加载在浏览器中进行。
虽然就算是客户端渲染对 Google 来说可能也没有问题,但最好是能选择一种不同的加载选项以支持其他搜索引擎。Bing 同样支持 JavaScript 渲染,但规模尚不明确。就我所看到的情况,Yandex 和 Baidu 的支持比较有限,而其他许多浏览器几乎不支持 JavaScript。
动态渲染也是一个选项,它为特定的用户代理所用。这基本上是一种变通的办法,但是对于搜索引擎爬虫甚至是社交媒体爬虫来说是有用的。社交媒体爬虫不会运行 JavaScript,因此除非你预先对内容进行渲染,否则像开放图谱标签这样的内容是不可见的。
如果你使用的是老旧的 AJAX 抓取模式,请注意它已经被充用,可能不再受支持。
这里提到的许多步骤,SEO 从业人员已经司空见惯了,但是可能略有不同。
站内 SEO
所有对于内容、标题标签、元描述、替代属性、元爬虫标签等在内的 SEO 规划在这里仍然适用。请查阅我们的站内 SEO 行动指南。
在使用 JavaScript 网站时,我反复发现的问题是标题和描述可能会被复用,而图片的替代属性经常没有添加。
允许抓取
不要屏蔽资源的访问。Google 需要能够访问并下载资源才可以恰当地渲染页面。在 robots.txt 文件中,最简单的允许资源被访问的方式是添加:
User-Agent: Googlebot Allow: .js Allow: .css<
链接
更新内容时更改链接。我已经提到过历史 API,但是你应该知道在 JavaScript 框架中,他们有一张路由表可以让你映射到友好的链接上。你不会想要用井字标签(#)来选择路径的。这对于 Vue 或者一些早期版本的 Angular 来说尤其是个问题。对于像 abc.com/#something 这样的链接来说,所有 # 之后的内容基本会被服务器无视。要在 Vue 中解决这个问题,你可以和开发者一起做以下改变:
Vue router: Use ‘History’ Mode instead of the traditional ‘Hash’ Mode.
const router = new VueRouter ({ mode: ‘history’, router: [] //the array of router links )}
Duplicate content 重复内容
在使用 JavaScript 的情况下,可以会有多个链接指向同一则内容,这就会导致重复内容的问题。这可能是由大写、标识符、带有标识符的变量等引起。因此,以下所有内容都可以存在:
domain.com/Abc
domain.com/abc
domain.com/123
domain.com/?id=123
解决方式很简单。选择一个你想要被索引的版本,并设置权威内容标签。
SEO “插件” 类型选项
对于 JavaScript 框架而言,他们通常被称作模块。通过搜索框架名+模块名,如“React Helmet”,你可以找到像 React, Vue 和 Angular 这样热门框架的许多模块。元标签、Helmet 以及 Head 都是比较流行的模块,他们的功能相似,允许你设置 SEO 所需的热门标签。
错误页面
因为 JavaScript 框架并不是服务器端加载的,他们并不能反馈像 404 页面这样的服务器错误。对于错误页面而言,你会有如果两个不同的选项:
- 使用 JavaScript 重定向到一个确实会返回 404 状态代码的页面。
- 向页面添加一个 noindex 标签,并显示一些错误信息,如“404 页面未找到”。这会被视作一个软 404 页面,返回的实际代码是 200 正常。
Sitemap 网站地图
JavaScript 框架一般都有路由表来映射友好的链接。这些路由表通常都有一个额外的模块,可以用来生成网站地图。你可以通过搜索你的系统名 + router sitemap 来找到这些他们,如“Vue router sitemap”。许多渲染方案可能也会有网站地图选项。同样,只需要找到你使用的系统,并搜索系统名 + sitemap —— 如 “Gatsby sitemap”,你一定可以找到已有的解决方案。
Redirects 重定向
SEO 从业人员对 301/302 重定向很熟悉,他们是服务器端的。但是 JavaScript 一般在客户端运行。这没有什么问题,因为 Google 会循着重定向来处理这个页面。重定向仍然可以传递像佩奇指数这样的信号。你通常可以通过查找 “window.location.href” 来找出代码中的这些重定向。
国际化
不同的框架通常都有若干模块选项支持像 hreflang 这样的国际化需要用到的特性。他们通常被移植到不同的系统中,包含 i18n、intl,或者像 Helmet 这样的模块可以被多次在 header 中使用来增加所需的标签。
懒加载
通常有一些模块可以用来处理懒加载。如果你还没有注意到,在使用 JavaScript 框架的时候,总有一些模块可以用来处理所有你需要做的事情。Lazy 和 Suspense 是最流行的懒加载模块。你会想要懒加载图片,但是注意不要懒加载内容。JavaScript 可以做到(懒加载内容),但是这意味着它不会被搜索引擎正确提取。
结语
JavaScript 是一个需要正确使用的工具,而不是 SEO 从业人员应该害怕的东西。希望这篇文章可以帮助你理解如何更好的使用它,但是不要害怕接触你的开发人员,去和他们一起工作,问他们问题。他们将是帮助你为搜索引擎优化 JavaScript 网站的最大盟友。
遇到问题了?在 Twitter 上告诉我吧。
译者,Alex Wang,Not Soup Yet 创始人