¿Cómo manejan los motores de búsqueda las aplicaciones de AngularJS?

Veo dos problemas con la aplicación AngularJS con respecto a los motores de búsqueda y SEO:

1) ¿Qué sucede con las tags personalizadas? ¿Los motores de búsqueda ignoran todo el contenido dentro de esas tags? es decir, supongamos que tengo

 

Hey, this title is important

¿se

a pesar de estar dentro de las tags personalizadas?

2) ¿Hay alguna manera de evitar los motores de búsqueda de la indexación {{}} se une literalmente? es decir

 

{{title}}

Sé que podría hacer algo como

 

pero, ¿y si realmente quiero que el rastreador “vea” el título? ¿La representación del servidor es la única solución?

Actualización mayo de 2014

Los rastreadores de Google ahora ejecutan javascript : puede usar las Herramientas para webmasters de Google para comprender mejor cómo Google procesa sus sitios.

Respuesta original
Si desea optimizar su aplicación para los motores de búsqueda, desafortunadamente no hay forma de que sirva una versión pre-renderizada al rastreador. Puede leer más sobre las recomendaciones de Google para ajax y sitios pesados ​​de javascript aquí .

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 qué hace el rastreador cuando encuentra tags personalizadas.

Use PushState y Precomposition

La forma actual (2015) de hacer esto es usar el método JavaScript pushState.

PushState cambia la URL en la barra superior del navegador sin volver a cargar la página. Supongamos que tiene una página que contiene tabs. Las tabs ocultan y muestran contenido, y el contenido se inserta dinámicamente, ya sea usando AJAX o simplemente configurando display: none y display: block para ocultar y mostrar el contenido correcto de la pestaña.

Cuando se hace clic en las tabs, use pushState para actualizar la url en la barra de direcciones. Cuando se procesa la página, use el valor en la barra de direcciones para determinar qué pestaña mostrar. El enrutamiento angular hará esto por usted automáticamente.

Precomposición

Hay dos formas de presionar una aplicación de una sola página de PushState (SPA)

  1. A través de PushState, donde el usuario hace clic en un enlace PushState y el contenido está AJAXed.
  2. Al golpear la URL directamente.

El golpe inicial en el sitio implicará golpear la URL directamente. Los hits subsecuentes simplemente serán AJAX en el contenido cuando PushState actualice la URL.

Los rastreadores cosechan enlaces de una página y luego los agregan a una cola para su posterior procesamiento. Esto significa que para un rastreador, cada golpe en el servidor es un golpe 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 represente la página sin ejecutar la llamada AJAX.

Existe alguna evidencia que sugiere que Google podría no ejecutar solicitudes AJAX. Más sobre esto aquí:

https://web.archive.org/web/20160318211223/http://www.analog-ni.co/precomposing-a-spa-may-become-the-holy-grail-to-seo

Los motores de búsqueda pueden leer y ejecutar JavaScript

Google ha podido analizar JavaScript desde hace un tiempo, es por eso que originalmente desarrolló Chrome, para actuar como un navegador sin funciones con todas las funciones para la araña de Google. Si un enlace tiene un atributo href válido, la nueva URL puede indexarse. No hay nada más que hacer.

Si al hacer clic en un enlace también se activa una llamada pushState, el usuario puede navegar por el sitio a través de PushState.

Soporte de motor de búsqueda para URL de PushState

PushState es actualmente compatible con Google y Bing.

Google

Aquí está Matt Cutts respondiendo a la pregunta de Paul Irish sobre PushState para SEO:

http://youtu.be/yiAF9VdvRPw

Aquí está Google anunciando el 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 buscar herramientas Google webmaster como Googlebot. Verás que se ejecuta tu JavaScript (incluido Angular).

Bing

Aquí está el anuncio de Bing de soporte para 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 use HashBangs #!

Las URL de Hashbang eran un feo obstáculo que requería que el desarrollador proporcionara una versión pre-renderizada del sitio en una ubicación especial. Aún funcionan, pero no es necesario que los uses.

Las URL de Hashbang se ven así:

domain.com/#!path/to/resource

Esto se emparejaría con una metaetiqueta como esta:

Google no los indexará de esta forma, sino que extraerá una versión estática del sitio de la _escaped_fragments_ URL e indexará eso.

Las URL de Pushstate se parecen a cualquier URL ordinaria:

domain.com/path/to/resource

La diferencia es que Angular las maneja interceptando el cambio a document.location que trata de él en JavaScript.

Si desea utilizar las URL de PushState (y probablemente lo haga) elimine todas las viejas URL y metatags de estilo hash y simplemente active el modo HTML5 en su bloque de configuración.

Probando su sitio

Las herramientas para webmasters de Google ahora contienen una herramienta que le permitirá buscar una URL como google y renderizar JavaScript a medida que Google lo presente.

https://www.google.com/webmasters/tools/googlebot-fetch

Generando URL PushState en Angular

Para generar URL reales en Angular, en lugar de # con prefijo, configure el modo HTML5 en su objeto $ locationProvider.

 $locationProvider.html5Mode(true); 

Lado del servidor

Dado que está utilizando URL reales, deberá asegurarse de que el servidor envíe la misma plantilla (más contenido precompuesto) para todas las URL válidas. La forma en que lo haga variará según la architecture de su servidor.

Mapa del sitio

Su aplicación puede usar formas de navegación inusuales, por ejemplo, desplazarse o desplazarse. Para garantizar que Google pueda conducir su aplicación, probablemente le sugiera que cree un mapa del sitio, una lista simple de todas las direcciones URL a las que responde su aplicación. Puede colocar esto en la ubicación predeterminada (/ sitemap o /sitemap.xml), o contarle a Google sobre esto usando herramientas de webmaster.

Es una buena idea tener un mapa del sitio de todos modos.

Soporte del navegador

Pushstate funciona en IE10. En navegadores más antiguos, Angular recurrirá automáticamente a las URL de estilo hash

Una página de demostración

El siguiente contenido se representa utilizando una URL de estado de empuje con precomposición:

http://html5.gingerhost.com/london

Como se puede verificar, en este enlace , el contenido está indexado y aparece en Google.

Sirviendo 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 servir códigos de estado de encabezado desde su servidor y esperar que Google los vea.

Seamos definitivos sobre AngularJS y SEO

Google, Yahoo, Bing y otros motores de búsqueda rastrean la web de forma tradicional utilizando rastreadores tradicionales. Ejecutan robots que rastrean el HTML en las páginas web, recostackndo 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 el SEO).

Entonces, ¿por qué los motores de búsqueda no manejan 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 representación 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 represente 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 rastrear nuestros sitios JavaScript, pero nos exige implementar un cambio en nuestro sitio .

Si cambiamos nuestro hashPrefix por ser #! en lugar de simplemente # , 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 característica mirando el encabezado User Agent en nuestro back-end).

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á en la página con:

http://www.ng-newsletter.com/?_escaped_fragment_=/signup/page

Podemos establecer el prefijo hash de nuestras aplicaciones angulares 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 metaetiqueta:

  

Recordatorio, podemos configurar el 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 lidiaremos con la entrega de contenido a los motores de búsqueda como HTML estático. Podemos alojar un servidor nosotros mismos, podemos usar un servicio para alojar un back-end para nosotros, podemos usar un proxy para entregar el contenido, etc. Veamos algunas opciones:

Autohospedado

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ándola como HTML. Cada vez que vemos la cadena de consulta ?_escaped_fragment_ en una solicitud de búsqueda, podemos entregar la instantánea HTML estática que tomamos de la página en lugar de la página pretratada a través de solo JS. Esto requiere que tengamos un backend que entregue nuestras páginas con una lógica condicional en el medio. Podemos utilizar algo como el backend de prerender.io 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 más rápida de obtener contenido en el motor de búsqueda es utilizar un servicio. Brombone , seo.js , seo4ajax y prerender.io son buenos ejemplos de estos que alojarán la representación de contenido anterior para usted. Esta es una buena opción para los momentos en los que no queremos tratar con la ejecución de un servidor / proxy. Además, generalmente es súper rápido.

Para obtener más información acerca de 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 . Compruébelo en ng-book.com .

Deberías echarle un vistazo al tutorial sobre la construcción de un sitio AngularJS compatible con SEO en el año del blog moo. Él lo guiará a través de todos los pasos descritos en la documentación de Angular. http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

Con esta técnica, el motor de búsqueda ve el HTML expandido en lugar de las tags personalizadas.

Esto ha cambiado drásticamente.

http://searchengineland.com/bing-offers-recommendations-for-seo-friendly-ajax-suggests-html5-pushstate-152946

Si usa: $ locationProvider.html5Mode (true); estás listo.

No más páginas de renderizado.

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 cronables y las enviará a los motores de búsqueda. Es compatible con casi todas las plataformas web del servidor. Recientemente comencé a usarlos y el soporte también es excelente.

No tengo ninguna afiliación con ellos, esto proviene de un usuario feliz.

El propio sitio web de Angular ofrece contenido simplificado a los motores de búsqueda: http://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09

Digamos que su aplicación Angular está consumiendo una api JSON Node.js / Express-driven, 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 ensuciar tu APLIC REST y no recomiendo hacerlo fuera de casos de uso muy simples donde podría ser un ajuste natural.

En su lugar, puede usar un conjunto de rutas y controladores completamente diferentes para su contenido amigable con los robots. Pero luego estás duplicando todas tus rutas y controladores AngularJS en Node / Express.

Me he decidido a generar instantáneas con un navegador sin cabeza, a pesar de que siento que es un poco menos que ideal.

A partir de ahora Google ha cambiado su propuesta de rastreo AJAX.

Los tiempos han cambiado. Hoy en día, siempre y cuando no bloquee el robot de Google para que rastree sus archivos JavaScript o CSS, generalmente podemos representar y entender sus páginas web como los navegadores modernos.

tl; dr: [Google] ya no recomiendan la propuesta de rastreo AJAX [Google] hecha en 2009.

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 bots sociales lidian con los mismos problemas, escribí el estado del arte aquí: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

Trabajo para https://ajaxsnapshots.com , una compañía que implementa la especificación de Ajax rastreable como servicio: la información en ese informe se basa en observaciones de nuestros registros.

He encontrado una solución elegante que cubriría la mayoría de tus bases. Escribí al respecto aquí inicialmente y respondí otra pregunta similar de StackOverflow aquí que hace referencia a ella.

Para su información, esta solución también incluye tags de respaldo codificadas en caso de que JavaScript no sea recogido por el rastreador. No lo he descrito explícitamente, pero vale la pena mencionar que debe activar el modo HTML5 para obtener el soporte adecuado de URL.

También tenga en cuenta: estos no son los archivos completos, solo las partes importantes de los que son relevantes. Si necesita ayuda para redactar el texto estándar para las 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 personalizadas o usa los valores predeterminados como retrocesos.

 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)

Paquetes de 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

Completa con las tags de respaldo codificadas mencionadas anteriormente, para los rastreadores que no pueden recoger ningún Javascript.

  Fallback Title               

Esto debería ayudar dramáticamente con la mayoría de los casos de uso del motor de búsqueda. Si desea una representación completamente dinámica para los rastreadores de redes sociales (que sin embargo son compatibles con Javascript), igual tendrá que usar uno de los servicios de pre representación que se mencionan en algunas de las otras respuestas.

¡Espero que esto ayude!

Use algo como PreRender, crea 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

Con Angular Universal, puede generar páginas de inicio para la aplicación que se parecen a la aplicación completa y luego cargar su aplicación angular detrás de ella.
Angular Universal genera HTML puro significa páginas sin JavaScript en el lado del servidor y les sirve a los usuarios sin demoras. Por lo tanto, puede tratar 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 está cargada detrás de ella. Esta solución es recomendada por el sitio oficial. -Más información sobre SEO y Angular Universal-

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 asíncrona de datos, esto se convirtió en un problema, ya que en algún momento lleva tiempo presentar una página y mostrar contenido dynamic. Del mismo modo, AngularJS también utiliza el modelo asincrónico, lo que crea problemas 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 de rastrear. Podemos renderizar las mismas páginas con PhantomJS en el lado del PhantomJS que tiene _escaped_fragment_ (¡Debido a que Google busca #! En las URL de nuestro sitio y luego toma todo después del #! Y lo agrega en el parámetro _escaped_fragment_ query). Para más detalles, lee este blog .

Los rastreadores no necesitan una interfaz gráfica de usuario muy rica, solo quieren ver el contenido , por lo que no es necesario que les proporciones una instantánea de una página creada para humanos.

Mi solución: para dar al rastreador lo que el rastreador quiere :

Debes pensar en qué quiere el rastreador y darle solo eso.

CONSEJO: no te metas con la parte de atrás. Solo agregue una pequeña vista frontal del lado del servidor con la misma API