html5 =' - In che modo i motori di ricerca gestiscono le applicazioni AngularJS?




meta name (13)

Vedo due problemi con l'applicazione AngularJS per quanto riguarda i motori di ricerca e SEO:

1) Cosa succede con i tag personalizzati? I motori di ricerca ignorano l'intero contenuto di tali tag? cioè suppongo di averlo

<custom>
  <h1>Hey, this title is important</h1>
</custom>

<h1> dovrebbe essere indicizzato nonostante si trovi all'interno di tag personalizzati?


2) Esiste un modo per evitare che i motori di ricerca dell'indicizzazione {{}} si leghino letteralmente? vale a dire

<h2>{{title}}</h2>

So che potrei fare qualcosa del genere

<h2 ng-bind="title"></h2>

ma cosa succede se voglio davvero lasciare che il crawler "veda" il titolo? Il rendering lato server è l'unica soluzione?


Answers

Ho trovato una soluzione elegante che coprirebbe la maggior parte delle vostre basi. Ne ho scritto inizialmente here e ho risposto ad un'altra domanda simile StackOverflow here che fa riferimento ad essa.

FYI questa soluzione include anche i tag di fallback hardcoded nel caso in cui Javascript non venga prelevato dal crawler. Non l'ho esplicitamente delineato, ma vale la pena ricordare che dovresti attivare la modalità HTML5 per il corretto supporto dell'URL.

Nota anche: questi non sono i file completi, solo le parti importanti di quelli rilevanti. Se hai bisogno di aiuto scrivendo lo standard per direttive, servizi, ecc. Che possono essere trovati altrove. Comunque, ecco qui ...

app.js

Qui è dove fornisci i metadati personalizzati per ognuno dei tuoi percorsi (titolo, descrizione, ecc.)

$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 (servizio)

Imposta le opzioni dei metadati personalizzati o usa i valori predefiniti come fallback.

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 (direttiva)

Pacchetti i risultati del servizio di metadati per 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

Completare con i tag di fallback hardcoded menzionati in precedenza, per i crawler che non possono rilevare alcun 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>

Questo dovrebbe aiutare in modo drammatico con la maggior parte dei casi d'uso dei motori di ricerca. Se si desidera il rendering completamente dinamico per i crawler dei social network (che sono incerti sul supporto Javascript), sarà comunque necessario utilizzare uno dei servizi di pre-rendering menzionati in alcune delle altre risposte.

Spero che questo ti aiuti!


Dovresti davvero dare un'occhiata al tutorial sulla costruzione di un sito AngularJS SEO-friendly nell'anno del blog moo. Ti guida attraverso tutti i passaggi descritti nella documentazione di Angular. http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

Usando questa tecnica, il motore di ricerca vede l'HTML espanso invece dei tag personalizzati.


Usa PushState e Precomposition

Il modo corrente (2015) per farlo è utilizzare il metodo JavaScript pushState.

PushState modifica l'URL nella barra superiore del browser senza ricaricare la pagina. Supponi di avere una pagina contenente schede. Le schede nascondono e mostrano il contenuto, e il contenuto viene inserito dinamicamente, usando AJAX o semplicemente impostando display: none e display: blocco da nascondere e mostrare il contenuto corretto della scheda.

Quando si fa clic sulle schede, utilizzare pushState per aggiornare l'url nella barra degli indirizzi. Quando la pagina viene visualizzata, usa il valore nella barra degli indirizzi per determinare quale scheda mostrare. Il routing angolare lo farà automaticamente.

precomposizione

Esistono due modi per colpire un'applicazione PushState Single Page (SPA)

  1. Tramite PushState, dove l'utente fa clic su un collegamento PushState e il contenuto è AJAXed in.
  2. Colpendo direttamente l'URL.

L'hit iniziale sul sito coinvolgerà direttamente l'URL. Gli hit successivi saranno semplicemente AJAX nel contenuto mentre il PushState aggiorna l'URL.

I crawler raccolgono i link da una pagina e li aggiungono a una coda per l'elaborazione successiva. Ciò significa che per un crawler, ogni hit sul server è un hit diretto, non naviga tramite Pushstate.

La precomposizione raggruppa il carico utile iniziale nella prima risposta dal server, possibilmente come un oggetto JSON. Ciò consente al motore di ricerca di eseguire il rendering della pagina senza eseguire la chiamata AJAX.

Esistono prove che suggeriscono che Google potrebbe non eseguire richieste AJAX. Maggiori informazioni su questo qui:

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

I motori di ricerca possono leggere ed eseguire JavaScript

Google è stato in grado di analizzare JavaScript per un po 'di tempo, è per questo che ha originariamente sviluppato Chrome, per fungere da browser headless completo per lo spider di Google. Se un link ha un attributo href valido, il nuovo URL può essere indicizzato. Non c'è nient'altro da fare.

Se facendo clic su un collegamento si attiva inoltre una chiamata pushState, il sito può essere navigato dall'utente tramite PushState.

Supporto del motore di ricerca per gli URL PushState

PushState è attualmente supportato da Google e Bing.

Google

Ecco Matt Cutts che risponde alla domanda di Paul Irish su PushState per SEO:

http://youtu.be/yiAF9VdvRPw

Ecco Google che annuncia il supporto JavaScript completo per lo spider:

http://googlewebmastercentral.blogspot.de/2014/05/understanding-web-pages-better.html

Il risultato è che Google supporta PushState e indicizzerà gli URL PushState.

Vedi anche Strumenti per i webmaster di Google 'recupera come Googlebot. Vedrai che il tuo JavaScript (incluso Angular) viene eseguito.

Bing

Ecco l'annuncio di Bing relativo al supporto per URL Pretty PushState datati marzo 2013:

http://blogs.bing.com/webmaster/2013/03/21/search-engine-optimization-best-practices-for-ajax-urls/

Non usare HashBang #!

Gli URL di Hashbang erano un brutto ostacolo che richiedeva allo sviluppatore di fornire una versione pre-renderizzata del sito in una posizione speciale. Funzionano ancora, ma non è necessario usarli.

Gli URL di Hashbang hanno questo aspetto:

domain.com/#!path/to/resource

Questo sarebbe accoppiato con un metatag come questo:

<meta name="fragment" content="!">

Google non li indicizzerà in questo modulo, ma prenderà invece una versione statica del sito dall'URL _escaped_fragments_ e indicizzerà quello.

Gli URL pushstate hanno l'aspetto di un normale URL:

domain.com/path/to/resource

La differenza è che Angular li gestisce per te intercettando la modifica in document.location trattandoci in JavaScript.

Se vuoi utilizzare gli URL di PushState (e probabilmente lo fai) estrai tutti i vecchi URL e metatag di stile hash e abilita semplicemente la modalità HTML5 nel tuo blocco di configurazione.

Test del tuo sito

Gli strumenti per i webmaster di Google ora contengono uno strumento che ti consentirà di recuperare un URL come google e renderizzare JavaScript mentre Google lo esegue.

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

Generazione degli URL PushState in Angolare

Per generare URL reali in Angular anziché in quelli con prefisso #, imposta la modalità HTML5 sull'oggetto $ locationProvider.

$locationProvider.html5Mode(true);

Lato server

Poiché utilizzi URL reali, dovrai assicurarti che lo stesso modello (più alcuni contenuti precomposti) venga spedito dal tuo server per tutti gli URL validi. Il modo in cui lo fai varia in base all'architettura del tuo server.

Mappa del sito

La tua app potrebbe utilizzare forme di navigazione insolite, ad esempio il passaggio del mouse o lo scorrimento. Per assicurarti che Google sia in grado di guidare la tua app, probabilmente suggerirei di creare una sitemap, un semplice elenco di tutti gli URL a cui la tua app risponde. Puoi posizionarlo nella posizione predefinita (/ sitemap o /sitemap.xml) o comunicarlo a Google utilizzando gli strumenti per i webmaster.

È comunque una buona idea avere una mappa del sito.

Supporto per il browser

Pushstate funziona in IE10. Nei browser meno recenti, Angular ricadrà automaticamente sugli URL di stile hash

Una pagina demo

Il seguente contenuto è reso utilizzando un URL pushstate con precomposizione:

http://html5.gingerhost.com/london

Come può essere verificato, a questo link , il contenuto è indicizzato e appare in Google.

Serve 404 e 301 codici di stato dell'intestazione

Poiché il motore di ricerca colpisce sempre il tuo server per ogni richiesta, puoi fornire i codici di stato dell'intestazione dal tuo server e aspettarti che Google li veda.



I crawler (o bot) sono progettati per eseguire la scansione del contenuto HTML delle pagine Web, ma a causa delle operazioni AJAX per il recupero di dati asincroni, questo è diventato un problema poiché richiede un po 'di tempo per eseguire il rendering della pagina e mostrare contenuti dinamici. Analogamente, AngularJS utilizza anche un modello asincrono, che crea problemi ai crawler di Google.

Alcuni sviluppatori creano pagine html di base con dati reali e servono queste pagine dal lato server al momento della scansione. Possiamo eseguire il rendering delle stesse pagine con PhantomJS sul lato servizio che ha _escaped_fragment_ (Perché Google cerca #! Nel nostro sito url e poi prende tutto dopo il #! E lo aggiunge nel parametro query _escaped_fragment_ ). Per maggiori dettagli leggi questo blog .



Lo standard Ajax Crawlable di Google, come riportato nelle altre risposte qui, è fondamentalmente la risposta.

Se sei interessato a come altri motori di ricerca e social bot affrontano gli stessi problemi, ho scritto lo stato dell'arte qui: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

Lavoro per un https://ajaxsnapshots.com , una società che implementa le Specifiche Ajax Crawlable come servizio: le informazioni contenute in tale rapporto si basano sulle osservazioni dei nostri registri.


Diventiamo definitivi su AngularJS e SEO

Google, Yahoo, Bing e altri motori di ricerca eseguono la scansione del Web in modo tradizionale utilizzando i crawler tradizionali. Eseguono robot che eseguono la scansione dell'HTML sulle pagine Web, raccogliendo informazioni lungo il percorso. Mantiene parole interessanti e cercano altri link ad altre pagine (questi link, la quantità di essi e il loro numero entrano in gioco con SEO).

Quindi perché i motori di ricerca non si occupano di siti javascript?

La risposta ha a che fare con il fatto che i robot dei motori di ricerca funzionano tramite browser headless e spesso non hanno un motore di rendering javascript per rendere il javascript di una pagina. Questo funziona per la maggior parte delle pagine poiché la maggior parte delle pagine statiche non si preoccupa del rendering della pagina JavaScript, poiché il loro contenuto è già disponibile.

Cosa si può fare al riguardo?

Fortunatamente, i crawler dei siti più grandi hanno iniziato a implementare un meccanismo che ci consente di effettuare la scansione dei nostri siti JavaScript, ma ci impone di implementare una modifica al nostro sito .

Se cambiamo il nostro hashPrefix per essere #! invece di semplicemente # , i moderni motori di ricerca cambieranno la richiesta per usare _escaped_fragment_ invece di #! . (Con la modalità HTML5, cioè dove abbiamo collegamenti senza il prefisso hash, possiamo implementare questa stessa funzionalità guardando l'intestazione User Agent nel nostro back-end).

Vale a dire, invece di una richiesta da un normale browser che assomiglia a:

http://www.ng-newsletter.com/#!/signup/page

Un motore di ricerca cercherà la pagina con:

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

Possiamo impostare il prefisso hash delle nostre app Angolari utilizzando un metodo ngRoute di ngRoute :

angular.module('myApp', [])
.config(['$location', function($location) {
  $location.hashPrefix('!');
}]);

E, se utilizziamo html5Mode , dovremo implementarlo utilizzando il meta tag:

<meta name="fragment" content="!">

Promemoria, possiamo impostare html5Mode() con il servizio $location :

angular.module('myApp', [])
.config(['$location', 
function($location) {
  $location.html5Mode(true);
}]);

Gestire il motore di ricerca

Abbiamo un sacco di opportunità per determinare in che modo ci occuperemo effettivamente di fornire contenuto ai motori di ricerca come HTML statico. Possiamo ospitare noi stessi un back-end, possiamo usare un servizio per ospitare un back-end per noi, possiamo usare un proxy per consegnare il contenuto, ecc. Vediamo alcune opzioni:

Self-hosted

Possiamo scrivere un servizio per gestire la scansione del nostro sito utilizzando un browser headless, come phantomjs o zombiejs, scattare un'istantanea della pagina con i dati renderizzati e archiviarla come HTML. Ogni volta che vediamo la stringa di query ?_escaped_fragment_ in una richiesta di ricerca, possiamo fornire lo snapshot statico HTML che abbiamo preso sulla pagina invece della pagina pre-renderizzata attraverso solo JS. Questo ci impone di avere un back-end che fornisca le nostre pagine con la logica condizionale nel mezzo. Possiamo usare qualcosa come prerender.io's backend prerender.io's come punto di partenza per gestirlo da soli. Ovviamente, dobbiamo ancora gestire il proxy e la gestione dei frammenti, ma è un buon inizio.

Con un servizio a pagamento

Il modo più semplice e veloce per ottenere contenuti nel motore di ricerca è quello di utilizzare un servizio Brombone , seo.js , seo4ajax e prerender.io's sono buoni esempi di questi che ospiteranno il rendering dei contenuti di cui sopra. Questa è una buona opzione per le volte in cui non vogliamo gestire l'esecuzione di un server / proxy. Inoltre, di solito è super veloce.

Per ulteriori informazioni su Angular e SEO, abbiamo scritto un esauriente tutorial su http://www.ng-newsletter.com/posts/serious-angular-seo.html e lo abbiamo ulteriormente descritto nel nostro libro ng-book: Il libro completo su AngularJS . ng-book.com un'occhiata a ng-book.com .


I crawler non hanno bisogno di una gui in stile piuttosto ricco, vogliono solo vedere il contenuto , quindi non è necessario dare loro un'istantanea di una pagina che è stata costruita per gli umani.

La mia soluzione: dare al crawler ciò che vuole il crawler :

Devi pensare a cosa vuole il crawler e dargli solo questo.

SUGGERIMENTO non scherzare con la schiena. Basta aggiungere un piccolo frontview lato server usando la stessa API


Con Angular Universal, puoi generare pagine di destinazione per l'app che assomigliano all'app completa e quindi caricare la tua app Angular.
Angular Universal genera puro HTML vuol dire pagine non javascript sul lato server e servirle agli utenti senza ritardi. Quindi puoi gestire qualsiasi crawler, bot e utente (che hanno già cpu bassa e velocità di rete). Poi puoi reindirli tramite link / pulsanti alla tua vera app angolare che è già caricata dietro di essa. Questa soluzione è raccomandata dal sito ufficiale. -Ulteriori informazioni su SEO e Angular Universal-



Aggiornamento maggio 2014

I crawler di Google ora eseguono javascript : puoi utilizzare gli Strumenti per i Webmaster di Google per capire meglio come vengono visualizzati i tuoi siti da Google.

Risposta originale
Se desideri ottimizzare la tua app per i motori di ricerca, sfortunatamente non c'è modo di offrire una versione pre-renderizzata al crawler. Puoi leggere ulteriori informazioni sui consigli di Google per i siti jax e javascript-heavy here .

Se questa è un'opzione, ti consiglio di leggere questo articolo su come fare SEO per Angular con rendering lato server.

Non sono sicuro di ciò che fa il crawler quando rileva tag personalizzati.


Le versioni precedenti di Angular (pre 1.0 RC) ti permettevano di usarlo in modo intercambiabile con il metodo $ scope, ma non è più così. All'interno dei metodi definiti sull'ambito questo e $ scope sono intercambiabili (angolare imposta questo a $ scope), ma non altrimenti all'interno del costruttore del controllore.

Per riportare questo comportamento (qualcuno sa perché è stato cambiato?) Puoi aggiungere:

return angular.extend($scope, this);

alla fine della funzione del controller (a condizione che $ scope sia stato iniettato su questa funzione del controller).

Questo ha un buon effetto di avere accesso all'ambito genitore tramite l'oggetto controller che è possibile ottenere in child con require: '^myParentDirective'





html5 angularjs seo search-engine google-search