it-swarm-es.com

¿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é 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 indexaría <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?

692
luisfarzati

Actualización de mayo de 2014

Los rastreadores de Google ahora ejecutan javascript - puede usar Google Webmaster Tools para entender 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 ajax y javascript-heavy aquí .

Si esta es una opción, recomendaría leer este artículo sobre cómo hacer SEO para Angular con representación del lado del servidor.

No estoy seguro de lo que hace el rastreador cuando encuentra etiquetas personalizadas.

402
joakimbl

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. Angular el enrutamiento lo hará automáticamente.

Precomposición

Hay dos formas de golpear una aplicación de página única PushState (SPA)

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

El golpe inicial en el sitio implicará golpear la URL directamente. Los impactos subsiguientes simplemente AJAX en el contenido a medida que PushState actualice la URL.

Los rastreadores recolectan 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 genere la página sin ejecutar la llamada AJAX.

Hay algunas pruebas que sugieren que Google podría no ejecutar las 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 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.

Google

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

http://youtu.be/yiAF9VdvRPw

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 sugeriría 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 retrocederá 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.

470
superluminary

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 la mayoría de las veces tienen 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 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 a ser #! en lugar de simplemente #, entonces los motores de búsqueda modernos cambiarán la solicitud para usar _escaped_fragment_ en 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 backend).

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 incorporado 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 HTML estática 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 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 son buenos ejemplos de estos que alojará 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 sobre este tema en http://www.ng-newsletter.com/posts/serious-angular-seo.htmland lo detallamos aún más en nuestro libro ng-book: The Complete Book on AngularJS. Compruébelo en ng-book.com .

106
auser

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.

56
Brad Green

Esto ha cambiado drásticamente.

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

Si usa: $ locationProvider.html5Mode (true); estas listo.

No más páginas de renderizado.

41
user3330270

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 serviciohttp://prerender.iofree que generará las páginas de crwalable para usted y las entregará 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.

17
Ketan

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 la aplicación Angular está consumiendo una API JSON basada en Node.js/Express, como /api/path/to/resource. Quizás podría redirigir cualquier solicitud con ?_escaped_fragment_ a /api/path/to/resource.html, y usar negociación de contenido para representar una plantilla HTML del contenido, en lugar de devolver los datos JSON.

Lo único es que sus Angular rutas deberían coincidir 1: 1 con su REST API.

EDIT: Me doy cuenta de que esto tiene el potencial de enturbiar realmente su REST api 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 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.

9
Kevin C.
8
pixparker

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

Los tiempos han cambiado. Hoy en día, 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 recomiendan la AJAX propuesta de rastreo [Google] realizada en 2009.

7
Thor

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 un 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.

6
Robert AJS

He encontrado una solución elegante que cubriría la mayoría de sus bases. Escribí sobre esto inicialmente aquí y respondí a otra pregunta similar de StackOverflow aquí 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 que sea compatible con la 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!

4
Andrew

Con Angular Universal, puede generar páginas de aterrizaje para la aplicación que se parecen a la aplicación completa y luego cargar su Angular aplicación detrás.
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 tengan 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-

2
erginduran

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

2
NicoJuicy

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 se necesita un tiempo para representar la página y mostrar 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 representar 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 .

1
Rubi saini

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: a 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 agrega una pequeña vista frontal del servidor usando la misma API

0
pykiss