html5 ng-class - ¿Cómo lidian los motores de búsqueda con las aplicaciones AngularJS?




ngclass ng-cloak (13)

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)

  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 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í:

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

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?



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


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.


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.


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.



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!


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.


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.


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 .


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 .


Solo termina de leer TODO lo anterior, aburrido y somnoliento (lo siento pero es cierto). Muy técnico, en profundidad, detallado y seco. ¿Por qué estoy escribiendo? Debido a que AngularJS es masivo, muchos conceptos interconectados pueden volver loco a cualquiera que se esté volviendo loco. A menudo me preguntaba, ¿no soy lo suficientemente inteligente como para entenderlos? ¡No! ¡Es porque muy pocos pueden explicar la tecnología en un lenguaje para dummie sin todas las terminologías! Está bien, déjame intentarlo:

1) Todas son cosas impulsadas por eventos. (Oigo la risa, pero sigue leyendo)

Si no sabe qué es lo que impulsa el evento. Luego, piense que coloca un botón en la página, conéctelo con una función usando "clic", esperando a que los usuarios hagan clic en él para activar las acciones que usted planta dentro del función. O piense en el "disparador" de SQL Server / Oracle.

2) $ watch es "on-click".

Lo que tiene de especial es que toma 2 funciones como parámetros, la primera da el valor del evento, la segunda toma el valor en consideración ...

3) $ digest es el jefe que revisa incansablemente , bla-bla-bla pero un buen jefe.

4) $ apply te da el camino cuando quieres hacerlo manualmente , como una prueba de fallas (en caso de que al hacer clic no se active, lo obligas a correr).

Ahora, hagámoslo visual. Imagina esto para que sea aún más fácil captar la idea:

En un restaurante,

- Se espera que los WAITERS tomen órdenes de los clientes, esto es

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- EL ADMINISTRADOR corre alrededor para asegurarse de que todos los camareros estén despiertos y respondan a cualquier señal de cambio de los clientes. Esto es $digest()

- El PROPIETARIO tiene el máximo poder para conducir a todos los que lo soliciten, esto es $apply()





html5 angularjs seo search-engine google-search