web-dev-qa-db-pt.com

Como os mecanismos de pesquisa lidam com aplicativos AngularJS?

Eu vejo dois problemas com o aplicativo AngularJS em relação aos mecanismos de pesquisa e SEO:

1) O que acontece com as tags personalizadas? Os mecanismos de pesquisa ignoram todo o conteúdo dessas tags? ou seja, suponho que eu tenha

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

o <h1> seria indexado apesar de estar dentro de tags personalizadas?


2) Existe uma maneira de evitar os motores de busca de indexação {{}} binds literalmente? isto é.

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

Eu sei que eu poderia fazer algo parecido

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

mas e se eu quiser realmente deixar o rastreador "ver" o título? A renderização do lado do servidor é a única solução?

692
luisfarzati

Atualização de maio de 2014

Google crawlers agora executa javascript - você pode usar o Google Webmaster Tools para entender melhor como seus sites são processados ​​pelo Google.

resposta original
Se você deseja otimizar seu aplicativo para mecanismos de pesquisa, infelizmente não há como distribuir uma versão pré-renderizada para o rastreador. Você pode ler mais sobre as recomendações do Google para sites pesados ​​ajax e javascript aqui .

Se esta é uma opção, eu recomendo ler este artigo sobre como fazer SEO para Angular com a renderização do lado do servidor.

Não tenho certeza do que o rastreador faz quando encontra tags personalizadas.

402
joakimbl

Use o PushState e a pré-composição

A maneira atual (2015) de fazer isso é usar o método pushState do JavaScript.

O PushState altera o URL na barra superior do navegador sem recarregar a página. Digamos que você tenha uma página contendo guias. As abas escondem e mostram conteúdo, e o conteúdo é inserido dinamicamente, usando AJAX ou simplesmente configurando display: none e display: block para esconder e mostrar o conteúdo correto da aba.

Quando as guias forem clicadas, use o pushState para atualizar o URL na barra de endereço. Quando a página é renderizada, use o valor na barra de endereços para determinar qual guia exibir. Angular roteamento fará isso para você automaticamente.

Pré-composição

Há duas maneiras de acessar um aplicativo de página única (SPA) do PushState

  1. Via PushState, onde o usuário clica em um link PushState e o conteúdo é AJAXado em.
  2. Ao atingir o URL diretamente.

O hit inicial no site envolverá o acesso direto ao URL. Os acessos subseqüentes serão simplesmente AJAX no conteúdo, pois o PushState atualiza o URL.

Os rastreadores coletam links de uma página e os adicionam a uma fila para processamento posterior. Isso significa que, para um rastreador, todos os hits no servidor são um impacto direto, eles não navegam pelo Pushstate.

A pré-composição agrupa a carga inicial na primeira resposta do servidor, possivelmente como um objeto JSON. Isso permite que o mecanismo de pesquisa renderize a página sem executar a chamada AJAX.

Há algumas evidências que sugerem que o Google pode não executar solicitações AJAX. Mais sobre isso aqui:

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

Os mecanismos de pesquisa podem ler e executar JavaScript

O Google tem sido capaz de analisar JavaScript por algum tempo agora, e é por isso que eles originalmente desenvolveram o Chrome, para atuar como um navegador sem cabeçalho completo para a aranha do Google. Se um link tiver um atributo href válido, o novo URL poderá ser indexado. Não há mais nada a fazer.

Se clicar em um link, além disso, aciona uma chamada pushState, o site pode ser navegado pelo usuário via PushState.

Suporte do mecanismo de pesquisa para URLs do PushState

Atualmente, o PushState é suportado pelo Google e pelo Bing.

Google

Aqui está Matt Cutts respondendo à pergunta de Paul Irish sobre o PushState para SEO:

http://youtu.be/yiAF9VdvRPw

Aqui está o Google anunciando o suporte total do JavaScript para a aranha:

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

O resultado é que o Google suporta o PushState e indexará URLs do PushState.

Veja também as ferramentas do Google para webmasters como "Googlebot". Você verá seu JavaScript (incluindo o Angular) executado.

Bing

Aqui está o anúncio do Bing sobre suporte para URLs do PushState datados de março de 2013:

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

Não use HashBangs #!

Os URLs do Hashbang eram um substituto feio que exigia que o desenvolvedor fornecesse uma versão pré-renderizada do site em um local especial. Eles ainda funcionam, mas você não precisa usá-los.

URLs de hashbang são assim:

domain.com/#!path/to/resource

Isso seria emparelhado com uma metatag como esta:

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

O Google não os indexará neste formulário, mas, em vez disso, extrairá uma versão estática do site do URL _escaped_fragments_ e o indexará.

Os URLs pushstate parecem com qualquer URL comum:

domain.com/path/to/resource

A diferença é que Angular lida com eles interceptando a mudança para document.location lidando com isso em JavaScript.

Se você quiser usar URLs PushState (e provavelmente você faz) retire todas as antigas URLs e metatags de estilo de hash e simplesmente ative o modo HTML5 em seu bloco de configuração.

Testando seu site

As ferramentas do Google para webmasters agora contêm uma ferramenta que permite buscar um URL como o google e renderizar o JavaScript conforme o Google o renderiza.

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

Gerando URLs do PushState no Angular

Para gerar URLs reais em Angular, em vez de # pré-fixados, defina o modo HTML5 no seu objeto $ locationProvider.

$locationProvider.html5Mode(true);

Lado do servidor

Como você está usando URLs reais, você precisará garantir que o mesmo modelo (mais algum conteúdo pré-configurado) seja enviado pelo seu servidor para todos os URLs válidos. Como você faz isso irá variar dependendo da arquitetura do seu servidor.

Mapa do Site

Seu aplicativo pode usar formas incomuns de navegação, por exemplo, passar o mouse ou rolar. Para garantir que o Google possa direcionar seu aplicativo, eu provavelmente sugeriria criar um sitemap, uma lista simples de todos os URLs que seu aplicativo responde. Você pode colocar isso no local padrão (/ sitemap ou /sitemap.xml) ou informar ao Google sobre isso usando as ferramentas do webmaster.

É uma boa ideia ter um sitemap de qualquer maneira.

Suporte de Navegador

Pushstate funciona no IE10. Em navegadores mais antigos, Angular retornará automaticamente para URLs de estilo hash

Uma página de demonstração

O conteúdo a seguir é renderizado usando um URL de pushstate com pré-composição:

http://html5.gingerhost.com/london

Como pode ser verificado, em este link , o conteúdo é indexado e está aparecendo no Google.

Servindo códigos de status do cabeçalho 404 e 301

Como o mecanismo de pesquisa sempre atingirá o servidor para cada solicitação, você poderá exibir códigos de status do cabeçalho do servidor e esperar que o Google os veja.

470
superluminary

Vamos ser definitivos sobre AngularJS e SEO

Google, Yahoo, Bing e outros mecanismos de pesquisa rastreiam a Web de maneiras tradicionais usando rastreadores tradicionais. Eles rodam robôsque rastreiam o HTML em páginas da web, coletando informações ao longo do caminho. Eles mantêm palavras interessantes e buscam outros links para outras páginas (esses links, a quantidade deles e o número deles entram em jogo com SEO).

Então, por que os mecanismos de busca não lidam com sites de javascript?

A resposta tem a ver com o fato de que os robôs do mecanismo de pesquisa funcionam em navegadores sem cabeçalho e na maioria das vezes fazem nãopossuem um mecanismo de renderização de javascript para renderizar o javascript de uma página. Isso funciona para a maioria das páginas não se preocupam com JavaScript renderizando sua página, já que seu conteúdo já está disponível.

O que pode ser feito sobre isso?

Felizmente, os rastreadores dos sites maiores começaram a implementar um mecanismo que nos permite tornar os sites JavaScript rastreáveis, mas exige que implementemos uma alteração em nosso site .

Se alterarmos a variável hashPrefix para #! em vez de simplesmente #, os mecanismos de pesquisa modernos alterarão a solicitação para usar _escaped_fragment_ em vez de #!. (Com o modo HTML5, ou seja, onde temos links sem o prefixo hash, podemos implementar esse mesmo recurso observando o cabeçalho User Agent em nosso backend).

Isto é, em vez de um pedido de um navegador normal que se parece com:

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

Um mecanismo de pesquisa pesquisará a página com:

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

Podemos definir o prefixo hash de nossos aplicativos Angular usando um método interno de ngRoute:

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

E, se estivermos usando html5Mode, precisaremos implementar isso usando a meta tag:

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

Lembrete, podemos definir a html5Mode() com o serviço $location:

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

Manipulando o mecanismo de pesquisa

Temos muitas oportunidades para determinar como lidaremos com a entrega de conteúdo aos mecanismos de pesquisa como HTML estático. Podemos hospedar um backend nós mesmos, podemos usar um serviço para hospedar um back-end para nós, podemos usar um proxy para entregar o conteúdo, etc. Vamos dar uma olhada em algumas opções:

Auto-hospedado

Podemos criar um serviço para lidar com o rastreamento de nosso próprio site usando um navegador sem cabeçalho, como phantomjs ou zombiejs, tirando um instantâneo da página com dados renderizados e armazenando-os como HTML. Sempre que vemos a string de consulta ?_escaped_fragment_ em uma solicitação de pesquisa, podemos entregar o instantâneo HTML estático que tiramos da página em vez da página pré-renderizada por meio de apenas JS. Isso exige que tenhamos um back-end que entregue nossas páginas com lógica condicional no meio. Podemos usar algo como prerender.io backend como ponto de partida para executar isso sozinhos. É claro que ainda precisamos lidar com o proxy e o processamento de snippets, mas é um bom começo.

Com um serviço pago

A maneira mais fácil e rápida de obter conteúdo no mecanismo de pesquisa é usar um serviço brombone , seo.js , seo4ajax e prerender.io são bons exemplos desses que hospedará a renderização de conteúdo acima para você. Essa é uma boa opção para os momentos em que não queremos lidar com a execução de um servidor/proxy. Além disso, geralmente é super rápido.

Para mais informações sobre Angular e SEO, escrevemos um extenso tutorial sobre isso em http://www.ng-newsletter.com/posts/serious-angular-seo.html e detalhamos ainda mais em nosso livro ng-book: O livro completo sobre AngularJS . Confira em ng-book.com .

106
auser

Você deve realmente verificar o tutorial sobre a construção de um site AngularJS SEO-friendly no ano do blog moo. Ele percorre todos os passos descritos na documentação do Angular. http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

Usando essa técnica, o mecanismo de pesquisa vê o HTML expandido em vez das tags personalizadas.

56
Brad Green

Isso mudou drasticamente.

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

Se você usar: $ locationProvider.html5Mode (true); você está definido.

Não há mais páginas de renderização.

41
user3330270

As coisas mudaram um pouco desde que esta pergunta foi feita. Agora existem opções para permitir que o Google indexe seu site AngularJS. A opção mais fácil que encontrei foi usarhttp://prerender.iofree service que irá gerar as páginas que podem ser movidas para você e servir para os mecanismos de busca. É suportado em quase todas as plataformas web do lado do servidor. Eu comecei recentemente a usá-los e o suporte também é excelente.

Eu não tenho nenhuma afiliação com eles, isso vem de um usuário feliz.

17
Ketan

O site da própria Angular serve conteúdo simplificado para os mecanismos de busca: http://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09

Digamos que seu app Angular esteja consumindo uma API JSON com Node.js/Express, como /api/path/to/resource. Talvez você possa redirecionar qualquer solicitação com ?_escaped_fragment_ para /api/path/to/resource.html e usar negotiation de conteúdo para renderizar um modelo HTML do conteúdo, em vez de retornar os dados JSON.

A única coisa é que as rotas Angular precisariam corresponder a 1: 1 com sua API REST.

EDIT: Estou percebendo que isso tem o potencial de realmente confundir sua REST API e eu não recomendo fazê-lo fora de casos de uso muito simples, onde poderia seja um ajuste natural.

Em vez disso, você pode usar um conjunto totalmente diferente de rotas e controladores para o seu conteúdo amigo do robô. Mas então você está duplicando todas as suas rotas e controladores AngularJS no Node/Express.

Eu decidi gerar snapshots com um navegador sem cabeçalho, embora eu ache que é um pouco menos que ideal.

9
Kevin C.
8
pixparker

A partir de agora, o Google mudou sua proposta de rastreamentoAJAX.

Os tempos mudaram. Hoje, desde que você não esteja impedindo que o Googlebot rastreie seus arquivos JavaScript ou CSS, geralmente somos capazes de processar e entender suas páginas da Web como os navegadores modernos.

tl; dr: [Google] não está mais recomendando a AJAX proposta de rastreamento [Google] feita em 2009.

7
Thor

A Rastreio Ajax Rastreável do Google, conforme mencionado nas outras respostas aqui, é basicamente a resposta.

Se você estiver interessado em saber como outros mecanismos de pesquisa e bots sociais lidam com os mesmos problemas, escrevi o estado da arte aqui: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification .html

Eu trabalho para um https://ajaxsnapshots.com , uma empresa que implementa o Crawlable Ajax Spec como um serviço - as informações desse relatório são baseadas em observações de nossos registros.

6
Robert AJS

Eu encontrei uma solução elegante que cobriria a maioria de suas bases. Eu escrevi sobre isso inicialmente aqui e respondi a outra pergunta semelhante StackOverflow aqui que faz referência a ele.

Além disso, esta solução também inclui tags de fallback codificados, caso o Javascript não seja selecionado pelo rastreador. Eu não o delineei explicitamente, mas vale a pena mencionar que você deve ativar o modo HTML5 para obter suporte de URL adequado.

Observe também: estes não são os arquivos completos, apenas as partes importantes daquelas que são relevantes. Se você precisar de ajuda para escrever o texto padrão para diretivas, serviços, etc., que podem ser encontrados em outro lugar. Enfim, aqui vai ...

app.js

É aqui que você fornece os metadados personalizados para cada uma das suas rotas (título, descrição 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 (serviço)

Define as opções de metadados personalizados ou usa padrões como fallbacks.

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

Empacota os resultados do serviço de metadados para a visualização.

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

Termine com as tags de fallback codificadas mencionadas anteriormente, para rastreadores que não podem pegar qualquer 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>

Isso deve ajudar dramaticamente na maioria dos casos de uso de mecanismos de pesquisa. Se você quiser renderização totalmente dinâmica para os rastreadores de redes sociais (que são duvidosos no suporte a Javascript), ainda será necessário usar um dos serviços de pré-renderização mencionados em algumas das outras respostas.

Espero que isto ajude!

4
Andrew

Com Angular Universal, você pode gerar páginas de destino para o aplicativo que se parece com o aplicativo completo e, em seguida, carregar seu Angular aplicativo por trás dele.
Angular Universal gera HTML puro significa páginas não-javascript no servidor e as serve aos usuários sem atrasos. Assim, você pode lidar com qualquer rastreador, bot e usuário (que já tem baixa velocidade de CPU e rede). Então você pode redirecioná-los por links/botões para o seu aplicativo angular real que já está carregado por trás dele. Esta solução é recomendada pelo site oficial. -Mais informações sobre SEO e Angular Universal-

2
erginduran

Use algo como PreRender, ele faz páginas estáticas do seu site para que os mecanismos de pesquisa possam indexá-lo.

Aqui você pode descobrir quais plataformas estão disponíveis: https://prerender.io/documentation/install-middleware#asp-net

2
NicoJuicy

Crawlers (ou bots) são projetados para rastrear o conteúdo HTML de páginas da web, mas devido a AJAX operações para obtenção de dados assíncrona, isso se tornou um problema, já que é necessário renderizar uma página e mostrar conteúdo dinâmico nela. Da mesma forma, AngularJS também usa um modelo assíncrono, o que cria um problema para os rastreadores do Google.

Alguns desenvolvedores criam páginas html básicas com dados reais e veiculam essas páginas do lado do servidor no momento do rastreamento. Podemos renderizar as mesmas páginas com PhantomJS no lado do servidor que tenha _escaped_fragment_ (porque o Google procura #! nos URLs do nosso site e depois pega tudo depois do #! e o adiciona no parâmetro de consulta _escaped_fragment_). Para mais detalhes, por favor leia este blog .

1
Rubi saini

Os rastreadores não precisam de um rico gui bem estilizado, eles só querem ver o conteúdo , então você não precisa dar a eles um instantâneo de uma página que foi construída para humanos.

Minha solução: para fornece ao rastreador o que o rastreador deseja :

Você deve pensar no que o rastreador quer e dar a ele apenas isso.

DICA não mexa nas costas. Basta adicionar um pouco de frontview do lado do servidor usando a mesma API

0
pykiss