html5 - cloak - ngclass angular 5
¿Cómo lidian los motores de búsqueda con las aplicaciones AngularJS? (15)
Veo dos problemas con la aplicación AngularJS con respecto a los motores de búsqueda y SEO:
1) ¿Qué pasa con las etiquetas personalizadas? ¿Los motores de búsqueda ignoran todo el contenido dentro de esas etiquetas? es decir, supongo que tengo
<custom>
<h1>Hey, this title is important</h1>
</custom>
¿Se <h1>
a pesar de estar dentro de etiquetas personalizadas?
2) ¿Hay una manera de evitar que los motores de búsqueda de indexación {{}} se unan literalmente? es decir
<h2>{{title}}</h2>
Sé que podría hacer algo como
<h2 ng-bind="title"></h2>
pero ¿qué pasa si realmente quiero que el rastreador "vea" el título? ¿Es el renderizado del lado del servidor la única solución?
Seamos definitivos sobre AngularJS y SEO
Google, Yahoo, Bing y otros motores de búsqueda rastrean la web de manera tradicional utilizando rastreadores tradicionales. Ejecutan robots que rastrean el HTML en las páginas web y recopilan información a lo largo del camino. Mantienen palabras interesantes y buscan otros enlaces a otras páginas (estos enlaces, la cantidad de ellos y el número de ellos entran en juego con SEO).
Entonces, ¿por qué los motores de búsqueda no se ocupan de los sitios javascript?
La respuesta tiene que ver con el hecho de que los robots de los motores de búsqueda funcionan a través de navegadores sin cabeza y, en la mayoría de los casos, no tienen un motor de renderizado de javascript para representar el javascript de una página. Esto funciona para la mayoría de las páginas, ya que a la mayoría de las páginas estáticas no les importa que JavaScript muestre su página, ya que su contenido ya está disponible.
¿Qué se puede hacer al respecto?
Afortunadamente, los rastreadores de los sitios más grandes han comenzado a implementar un mecanismo que nos permite hacer que nuestros sitios de JavaScript puedan rastrearse, pero nos obliga a implementar un cambio en nuestro sitio .
Si cambiamos nuestro hashPrefix
para ser #!
en lugar de simplemente #
, entonces los motores de búsqueda modernos cambiarán la solicitud para usar _escaped_fragment_
lugar de #!
. (Con el modo HTML5, es decir, donde tenemos enlaces sin el prefijo hash, podemos implementar esta misma función mirando el encabezado del User Agent
en nuestro servidor).
Es decir, en lugar de una solicitud de un navegador normal que se ve así:
http://www.ng-newsletter.com/#!/signup/page
Un motor de búsqueda buscará la página con:
http://www.ng-newsletter.com/?_escaped_fragment_=/signup/page
Podemos establecer el prefijo hash de nuestras aplicaciones Angular usando un método ngRoute
de ngRoute
:
angular.module(''myApp'', [])
.config([''$location'', function($location) {
$location.hashPrefix(''!'');
}]);
Y, si estamos usando html5Mode
, necesitaremos implementar esto usando la etiqueta meta:
<meta name="fragment" content="!">
Recordatorio, podemos configurar html5Mode()
con el servicio $location
:
angular.module(''myApp'', [])
.config([''$location'',
function($location) {
$location.html5Mode(true);
}]);
Manejando el motor de búsqueda.
Tenemos muchas oportunidades para determinar cómo trataremos la entrega de contenido a los motores de búsqueda como HTML estático. Podemos alojar un backend nosotros mismos, podemos usar un servicio para hospedar un back-end para nosotros, podemos usar un proxy para entregar el contenido, etc. Veamos algunas opciones:
Auto alojado
Podemos escribir un servicio para manejar el rastreo de nuestro propio sitio usando un navegador sin cabeza, como phantomjs o zombiejs, tomando una instantánea de la página con datos renderizados y almacenándolos como HTML. Cada vez que vemos la cadena de consulta ?_escaped_fragment_
en una solicitud de búsqueda, podemos entregar la instantánea de HTML estático que tomamos de la página en lugar de la página representada previamente solo a través de JS. Esto requiere que tengamos un backend que entregue nuestras páginas con lógica condicional en el medio. Podemos usar algo como prerender.io''s backend prerender.io''s como punto de partida para ejecutar esto nosotros mismos. Por supuesto, todavía tenemos que manejar el proxy y el manejo de fragmentos, pero es un buen comienzo.
Con un servicio pagado.
La forma más fácil y rápida de obtener contenido en el motor de búsqueda es usar un servicio Brombone , seo.js , seo4ajax y prerender.io''s son buenos ejemplos de estos que albergarán la representación de contenido anterior para usted. Esta es una buena opción para los momentos en que no queremos lidiar con la ejecución de un servidor / proxy. Además, suele ser super rápido.
Para obtener más información sobre Angular y SEO, escribimos un extenso tutorial en http://www.ng-newsletter.com/posts/serious-angular-seo.html y lo detallamos aún más en nuestro libro ng-book: El libro completo en AngularJS . Échale un vistazo a ng-book.com .
Usar PushState y Precomposición
La forma actual (2015) de hacer esto es usar el método pushState de JavaScript.
PushState cambia la URL en la barra superior del navegador sin volver a cargar la página. Digamos que tienes una página que contiene pestañas. Las pestañas ocultan y muestran el contenido, y el contenido se inserta dinámicamente, ya sea utilizando AJAX o simplemente configurando mostrar: ninguno y mostrar: bloquear para ocultar y mostrar el contenido correcto de las pestañas.
Cuando se hace clic en las pestañas, use pushState para actualizar la url en la barra de direcciones. Cuando se representa la página, use el valor en la barra de direcciones para determinar qué pestaña mostrar. El enrutamiento angular lo hará automáticamente.
Precomposición
Hay dos formas de golpear una aplicación de página única PushState (SPA)
- A través de PushState, donde el usuario hace clic en un enlace de PushState y el contenido está en AJAX.
- Al golpear directamente la URL.
El golpe inicial en el sitio implicará golpear la URL directamente. Los impactos subsiguientes serán simplemente AJAX en el contenido a medida que PushState actualice la URL.
Los rastreadores recopilan enlaces de una página y luego los agregan a una cola para procesarlos más tarde. Esto significa que para un rastreador, cada impacto en el servidor es un impacto directo, no navegan a través de Pushstate.
La precomposición agrupa la carga útil inicial en la primera respuesta del servidor, posiblemente como un objeto JSON. Esto permite que el motor de búsqueda rinda la página sin ejecutar la llamada AJAX.
Hay algunas pruebas que sugieren que Google podría no ejecutar solicitudes AJAX. Más sobre esto aquí:
Los motores de búsqueda pueden leer y ejecutar JavaScript
Google ha sido capaz de analizar JavaScript desde hace algún tiempo, es por eso que originalmente desarrollaron Chrome, para actuar como un navegador sin cabeza con todas las funciones para la araña de Google. Si un enlace tiene un atributo href válido, la nueva URL se puede indexar. No hay nada más que hacer.
Si al hacer clic en un enlace además se activa una llamada pushState, el sitio puede ser navegado por el usuario a través de PushState.
Soporte de motor de búsqueda para las URL de PushState
PushState actualmente es compatible con Google y Bing.
Aquí está Matt Cutts respondiendo a la pregunta de Paul Irish sobre PushState para SEO:
Aquí está Google anunciando soporte completo de JavaScript para la araña:
http://googlewebmastercentral.blogspot.de/2014/05/understanding-web-pages-better.html
El resultado es que Google admite PushState e indexará las URL de PushState.
Consulte también las herramientas de webmaster de Google como Googlebot. Verás que se ejecuta tu JavaScript (incluido Angular).
Bing
Aquí está el anuncio de soporte de Bing para las bonitas URL de PushState con fecha de marzo de 2013:
http://blogs.bing.com/webmaster/2013/03/21/search-engine-optimization-best-practices-for-ajax-urls/
¡No uses HashBangs #!
Las URL de Hashbang eran un recurso provisional feo que requería que el desarrollador proporcionara una versión pre-renderizada del sitio en una ubicación especial. Todavía funcionan, pero no necesitas usarlos.
Las URL de Hashbang se ven así:
domain.com/#!path/to/resource
Esto sería emparejado con un metatag como este:
<meta name="fragment" content="!">
Google no los indexará de esta forma, sino que extraerá una versión estática del sitio de la URL _escaped_fragments_ e indexará eso.
Las URL de Pushstate se parecen a cualquier URL ordinaria:
domain.com/path/to/resource
La diferencia es que Angular los maneja por usted al interceptar el cambio en document.location que lo trata en JavaScript.
Si desea usar las URL de PushState (y probablemente lo haga) elimine todas las URL y metatags de estilo hash antiguo y simplemente habilite el modo HTML5 en su bloque de configuración.
Probando tu sitio
Las herramientas para webmasters de Google ahora contienen una herramienta que le permitirá obtener una URL como google y renderizar JavaScript como lo hace Google.
https://www.google.com/webmasters/tools/googlebot-fetch
Generando URLs PushState en Angular
Para generar URL reales en Angular, en lugar de # prefijadas, configure el modo HTML5 en su objeto $ locationProvider.
$locationProvider.html5Mode(true);
Lado del servidor
Dado que está utilizando URL reales, deberá asegurarse de que su servidor le envíe la misma plantilla (más el contenido precompuesto) para todas las URL válidas. La forma de hacerlo variará en función de la arquitectura de su servidor.
Mapa del sitio
Su aplicación puede utilizar formas de navegación inusuales, por ejemplo, desplazarse o desplazarse. Para garantizar que Google pueda manejar su aplicación, probablemente sugiera crear un mapa del sitio, una lista simple de todas las direcciones URL a las que responde su aplicación. Puede colocarlo en la ubicación predeterminada (/ sitemap o /sitemap.xml), o informar a Google sobre ello mediante las herramientas para webmasters.
Es una buena idea tener un mapa del sitio de todos modos.
Soporte del navegador
Pushstate funciona en IE10. En los navegadores más antiguos, Angular volverá automáticamente a las URL de estilo hash
Una página de demostración
El siguiente contenido se representa mediante una URL pushstate con precomposición:
http://html5.gingerhost.com/london
Como se puede verificar, en este enlace , el contenido está indexado y aparece en Google.
Sirviendo los códigos de estado de encabezado 404 y 301
Debido a que el motor de búsqueda siempre llegará a su servidor para cada solicitud, puede proporcionar códigos de estado de encabezado desde su servidor y esperar que Google los vea.
A partir de ahora Google ha cambiado su propuesta de rastreo AJAX.
Los tiempos han cambiado. Hoy, mientras no esté impidiendo que Googlebot rastree sus archivos JavaScript o CSS, generalmente podemos procesar y entender sus páginas web como los navegadores modernos.
tl; dr: [Google] ya no recomienda la propuesta de rastreo de AJAX [Google] realizada en 2009.
Con Angular Universal, puede generar páginas de destino para la aplicación que se parece a la aplicación completa y luego cargar la aplicación Angular detrás de ella.
Angular Universal genera HTML puro significa páginas sin javascript en el lado del servidor y las sirve a los usuarios sin demoras. Por lo tanto, puede lidiar con cualquier rastreador, bot y usuario (que ya tenga una CPU y una velocidad de red bajas). Luego, puede redirigirlos mediante enlaces / botones a su aplicación angular real que ya se cargó detrás. Esta solución es recomendada por el sitio oficial. -Más información sobre SEO y Angular Universal-
El sitio web de Angular sirve contenido simplificado para los motores de búsqueda: http://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09
Supongamos que su aplicación Angular consume una api de JSON controlada por Node.js / Express, como /api/path/to/resource
. Quizás podría redirigir cualquier solicitud con ?_escaped_fragment_
/api/path/to/resource.html
a /api/path/to/resource.html
, y usar la negociación de contenido para representar una plantilla HTML del contenido, en lugar de devolver los datos JSON.
Lo único es que sus rutas angulares deberían coincidir 1: 1 con su API REST.
EDITAR : Me doy cuenta de que esto tiene el potencial de enturbiar realmente su API REST y no recomiendo hacerlo fuera de los casos de uso muy simples donde podría ser un ajuste natural.
En su lugar, puede usar un conjunto completamente diferente de rutas y controladores para su contenido compatible con robots. Pero luego estás duplicando todas tus rutas y controladores de AngularJS en Node / Express.
Me he conformado con generar instantáneas con un navegador sin cabeza, aunque creo que es un poco menos que ideal.
Esto ha cambiado drásticamente.
Si usa: $ locationProvider.html5Mode (true); estas listo
No más páginas de renderizado.
He encontrado una solución elegante que cubriría la mayoría de sus bases. Escribí sobre esto inicialmente here y respondí otra pregunta similar de here que lo refiere.
Para su información, esta solución también incluye etiquetas de respaldo rígidas en caso de que Javascript no sea detectado por el rastreador. No lo he explicado explícitamente, pero vale la pena mencionar que debería activar el modo HTML5 para el correcto soporte de URL.
También tenga en cuenta: estos no son los archivos completos, solo las partes importantes de aquellos que son relevantes. Si necesita ayuda para escribir la placa de calderas para directivas, servicios, etc. que se pueden encontrar en otros lugares. De todos modos, aquí va ...
app.js
Aquí es donde proporciona los metadatos personalizados para cada una de sus rutas (título, descripción, etc.)
$routeProvider
.when(''/'', {
templateUrl: ''views/homepage.html'',
controller: ''HomepageCtrl'',
metadata: {
title: ''The Base Page Title'',
description: ''The Base Page Description'' }
})
.when(''/about'', {
templateUrl: ''views/about.html'',
controller: ''AboutCtrl'',
metadata: {
title: ''The About Page Title'',
description: ''The About Page Description'' }
})
metadata-service.js (servicio)
Establece las opciones de metadatos personalizados o utiliza los valores predeterminados como recursos alternativos.
var self = this;
// Set custom options or use provided fallback (default) options
self.loadMetadata = function(metadata) {
self.title = document.title = metadata.title || ''Fallback Title'';
self.description = metadata.description || ''Fallback Description'';
self.url = metadata.url || $location.absUrl();
self.image = metadata.image || ''fallbackimage.jpg'';
self.ogpType = metadata.ogpType || ''website'';
self.twitterCard = metadata.twitterCard || ''summary_large_image'';
self.twitterSite = metadata.twitterSite || ''@fallback_handle'';
};
// Route change handler, sets the route''s defined metadata
$rootScope.$on(''$routeChangeSuccess'', function (event, newRoute) {
self.loadMetadata(newRoute.metadata);
});
metaproperty.js (directiva)
Empaqueta los resultados del servicio de metadatos para la vista.
return {
restrict: ''A'',
scope: {
metaproperty: ''@''
},
link: function postLink(scope, element, attrs) {
scope.default = element.attr(''content'');
scope.metadata = metadataService;
// Watch for metadata changes and set content
scope.$watch(''metadata'', function (newVal, oldVal) {
setContent(newVal);
}, true);
// Set the content attribute with new metadataService value or back to the default
function setContent(metadata) {
var content = metadata[scope.metaproperty] || scope.default;
element.attr(''content'', content);
}
setContent(scope.metadata);
}
};
index.html
Complete con las etiquetas de respaldo rígidas mencionadas anteriormente, para los rastreadores que no pueden seleccionar ningún Javascript.
<head>
<title>Fallback Title</title>
<meta name="description" metaproperty="description" content="Fallback Description">
<!-- Open Graph Protocol Tags -->
<meta property="og:url" content="fallbackurl.com" metaproperty="url">
<meta property="og:title" content="Fallback Title" metaproperty="title">
<meta property="og:description" content="Fallback Description" metaproperty="description">
<meta property="og:type" content="website" metaproperty="ogpType">
<meta property="og:image" content="fallbackimage.jpg" metaproperty="image">
<!-- Twitter Card Tags -->
<meta name="twitter:card" content="summary_large_image" metaproperty="twitterCard">
<meta name="twitter:title" content="Fallback Title" metaproperty="title">
<meta name="twitter:description" content="Fallback Description" metaproperty="description">
<meta name="twitter:site" content="@fallback_handle" metaproperty="twitterSite">
<meta name="twitter:image:src" content="fallbackimage.jpg" metaproperty="image">
</head>
Esto debería ayudar dramáticamente con la mayoría de los casos de uso de motores de búsqueda. Si desea una representación completamente dinámica para los rastreadores de redes sociales (que son dudosos en la compatibilidad con Javascript), todavía tendrá que usar uno de los servicios de representación previa mencionados en algunas de las otras respuestas.
¡Espero que esto ayude!
La especificación de Ajax rastreable de Google, como se menciona en las otras respuestas aquí, es básicamente la respuesta.
Si está interesado en cómo otros motores de búsqueda y robots sociales tratan los mismos problemas, escribí el estado del arte aquí: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html
Trabajo para una https://ajaxsnapshots.com , una compañía que implementa la especificación de Ajax rastreable como un servicio: la información en ese informe se basa en las observaciones de nuestros registros.
Las cosas han cambiado bastante desde que se hizo esta pregunta. Ahora hay opciones para permitir que Google indexe su sitio AngularJS. La opción más fácil que encontré fue usar el servicio gratuito http://prerender.io que generará las páginas de crwalable para usted y se las dará a los motores de búsqueda. Es compatible con casi todas las plataformas web del lado del servidor. Recientemente he empezado a usarlos y el soporte también es excelente.
No tengo ninguna afiliación con ellos, esto viene de un usuario feliz.
Los rastreadores (o bots) están diseñados para rastrear el contenido HTML de las páginas web, pero debido a las operaciones AJAX para la obtención de datos asíncronos, esto se convirtió en un problema, ya que demora el procesamiento de la página y muestra contenido dinámico. De manera similar, AngularJS
también usa un modelo asíncrono, lo que crea un problema para los rastreadores de Google.
Algunos desarrolladores crean páginas html básicas con datos reales y sirven estas páginas desde el lado del servidor en el momento del rastreo. Podemos renderizar las mismas páginas con PhantomJS
en el lado del servicio que tiene _escaped_fragment_
(porque Google busca #!
En las URL de nuestro sitio y luego toma todo después del #!
Y lo agrega en el parámetro de consulta _escaped_fragment_
). Para más detalles por favor lea este blog .
Realmente deberías revisar el tutorial sobre cómo construir un sitio AngularJS compatible con SEO en el año del blog moo. Te guía a través de todos los pasos descritos en la documentación de Angular. http://www.yearofmoo.com/2012/11/angularjs-and-seo.html
Usando esta técnica, el motor de búsqueda ve el HTML expandido en lugar de las etiquetas personalizadas.
Una buena práctica se puede encontrar aquí:
http://scotch.io/tutorials/javascript/angularjs-seo-with-prerender-io?_escaped_fragment_=tag
Use algo como PreRender, hace páginas estáticas de su sitio para que los motores de búsqueda puedan indexarlo.
Aquí puede averiguar para qué plataformas está disponible: https://prerender.io/documentation/install-middleware#asp-net
Actualización de mayo de 2014
Los rastreadores de Google ahora ejecutan javascript : puede usar las Herramientas para webmasters de Google para comprender mejor cómo Google representa sus sitios.
Respuesta original
Si desea optimizar su aplicación para los motores de búsqueda, lamentablemente no hay forma de servir una versión pre-renderizada al rastreador. Puede leer más sobre las recomendaciones de Google para los sitios de ajax y javascript-heavy here .
Si esta es una opción, recomendaría leer este artículo sobre cómo hacer SEO para Angular con la representación del lado del servidor.
No estoy seguro de lo que hace el rastreador cuando encuentra etiquetas personalizadas.
Los rastreadores no necesitan una interfaz gráfica de usuario de estilo rico, sino que solo quieren ver el contenido , por lo que no es necesario que les brinde una instantánea de una página creada para humanos.
Mi solución: dar al rastreador lo que quiere el rastreador :
Debes pensar en lo que quiere el rastreador y darle solo eso.
SUGERENCIA no te metas con la espalda. Solo agregue una pequeña vista frontal del servidor utilizando la misma API