검색 엔진은 AngularJS 애플리케이션을 어떻게 처리합니까?
검색 엔진 및 SEO와 관련하여 AngularJS 응용 프로그램에 두 가지 문제가 있습니다.
1) 사용자 정의 태그는 어떻게됩니까? 검색 엔진이 해당 태그 내의 전체 콘텐츠를 무시합니까? 즉 내가 가지고 있다고 가정
<custom>
<h1>Hey, this title is important</h1>
</custom>
것이 <h1>
내부의 사용자 정의 태그를 임에도 불구하고 색인?
2) {{}} 바인딩 인덱싱의 검색 엔진을 문자 그대로 피하는 방법이 있습니까? 즉
<h2>{{title}}</h2>
나는 내가 뭔가 할 수 있다는 것을 안다.
<h2 ng-bind="title"></h2>
하지만 실제로 크롤러가 제목을 "보도록"하려면 어떻게해야합니까? 서버 측 렌더링이 유일한 솔루션입니까?
2014 년 5 월 업데이트
이제 Google 크롤러가 자바 스크립트를 실행 합니다. Google 웹 마스터 도구 를 사용하여 Google에서 사이트를 렌더링하는 방법을 더 잘 이해할 수 있습니다.
원래 답변
검색 엔진 용으로 앱을 최적화하려는 경우 불행히도 사전 렌더링 된 버전을 크롤러에 제공 할 방법이 없습니다. 여기 에서 ajax 및 자바 스크립트가 많은 사이트에 대한 Google의 권장 사항에 대해 자세히 알아볼 수 있습니다 .
이것이 옵션이라면 서버 측 렌더링으로 Angular에 대한 SEO를 수행하는 방법에 대한 이 기사 를 읽는 것이 좋습니다 .
크롤러가 사용자 정의 태그를 발견했을 때 무엇을하는지 잘 모르겠습니다.
PushState 및 사전 구성 사용
이를 수행하는 현재 (2015) 방법은 JavaScript pushState 메서드를 사용하는 것입니다.
PushState는 페이지를 다시로드하지 않고 상단 브라우저 표시 줄의 URL을 변경합니다. 탭이 포함 된 페이지가 있다고 가정 해 보겠습니다. 탭은 콘텐츠를 숨기고 표시하며 콘텐츠는 AJAX를 사용하거나 단순히 display : none 및 display : block을 설정하여 올바른 탭 콘텐츠를 숨기고 표시함으로써 동적으로 삽입됩니다.
탭을 클릭하면 pushState를 사용하여 주소 표시 줄의 URL을 업데이트합니다. 페이지가 렌더링되면 주소 표시 줄의 값을 사용하여 표시 할 탭을 결정합니다. 각도 라우팅이 자동으로 수행합니다.
사전 구성
PushState 단일 페이지 앱 (SPA)에 접속하는 방법에는 두 가지가 있습니다.
- PushState를 통해 사용자가 PushState 링크를 클릭하고 콘텐츠가 AJAX에 포함됩니다.
- URL을 직접 누르십시오.
사이트의 초기 히트에는 URL을 직접 히트하는 것이 포함됩니다. PushState가 URL을 업데이트함에 따라 후속 적중은 콘텐츠에서 단순히 AJAX가됩니다.
크롤러는 페이지에서 링크를 수집 한 다음 나중에 처리 할 수 있도록 대기열에 추가합니다. 즉, 크롤러의 경우 서버의 모든 적중은 직접 적중이며 Pushstate를 통해 탐색하지 않습니다.
사전 구성은 초기 페이로드를 서버의 첫 번째 응답 (예 : JSON 개체)에 번들로 제공합니다. 이를 통해 검색 엔진은 AJAX 호출을 실행하지 않고도 페이지를 렌더링 할 수 있습니다.
Google이 AJAX 요청을 실행하지 않을 수 있다는 증거가 있습니다. 여기에 대한 자세한 내용 :
검색 엔진은 JavaScript를 읽고 실행할 수 있습니다.
구글은 한동안 자바 스크립트를 파싱 할 수 있었기 때문에 구글 스파이더의 완전한 기능을 갖춘 헤드리스 브라우저 역할을하는 크롬을 원래 개발했습니다. 링크에 유효한 href 속성이 있으면 새 URL을 색인화 할 수 있습니다. 더 이상 할 일이 없습니다.
추가로 링크를 클릭하면 pushState 호출이 트리거되면 사용자는 PushState를 통해 사이트를 탐색 할 수 있습니다.
PushState URL에 대한 검색 엔진 지원
PushState는 현재 Google과 Bing에서 지원됩니다.
구글
SEO를위한 PushState에 대한 Paul Irish의 질문에 대한 Matt Cutts는 다음과 같습니다.
다음은 스파이더에 대한 완전한 JavaScript 지원을 발표하는 Google입니다.
http://googlewebmastercentral.blogspot.de/2014/05/understanding-web-pages-better.html
결론은 Google이 PushState를 지원하고 PushState URL의 색인을 생성한다는 것입니다.
Google 웹 마스터 도구의 Googlebot으로 가져 오기도 참조하세요. JavaScript (Angular 포함)가 실행되는 것을 볼 수 있습니다.
빙
다음은 2013 년 3 월 날짜의 예쁜 PushState URL에 대한 Bing의 지원 발표입니다.
http://blogs.bing.com/webmaster/2013/03/21/search-engine-optimization-best-practices-for-ajax-urls/
HashBangs #를 사용하지 마십시오!
Hashbang URL은 개발자가 특정 위치에서 사이트의 사전 렌더링 된 버전을 제공해야하는 추악한 임시 방편이었습니다. 여전히 작동하지만 사용할 필요는 없습니다.
Hashbang URL은 다음과 같습니다.
domain.com/#!path/to/resource
이것은 다음과 같은 메타 태그와 쌍을 이룹니다.
<meta name="fragment" content="!">
Google은이 형식으로 색인을 생성하지 않지만 대신 _escaped_fragments_ URL에서 사이트의 정적 버전을 가져와 색인을 생성합니다.
Pushstate URL은 일반 URL과 유사합니다.
domain.com/path/to/resource
차이점은 Angular가 JavaScript에서 처리하는 document.location의 변경 사항을 가로 채서 처리한다는 것입니다.
PushState URL을 사용하려는 경우 (아마도 사용하는 경우) 이전 해시 스타일 URL과 메타 태그를 모두 제거하고 구성 블록에서 HTML5 모드를 활성화하기 만하면됩니다.
사이트 테스트
이제 Google 웹 마스터 도구에는 URL을 Google로 가져오고 Google이 렌더링하는대로 자바 스크립트를 렌더링 할 수있는 도구가 포함되어 있습니다.
https://www.google.com/webmasters/tools/googlebot-fetch
Angular에서 PushState URL 생성
# 접두사가 아닌 Angular에서 실제 URL을 생성하려면 $ locationProvider 개체에 HTML5 모드를 설정하세요.
$locationProvider.html5Mode(true);
서버 측
실제 URL을 사용하고 있으므로 유효한 모든 URL에 대해 동일한 템플릿 (및 미리 구성된 일부 콘텐츠)이 서버에서 제공되는지 확인해야합니다. 이를 수행하는 방법은 서버 아키텍처에 따라 다릅니다.
사이트 맵
앱에서 호버 또는 스크롤과 같은 비정상적인 형태의 탐색을 사용할 수 있습니다. Google이 앱을 구동 할 수 있도록 앱이 응답하는 모든 URL의 간단한 목록 인 사이트 맵을 만드는 것이 좋습니다. 기본 위치 (/ sitemap 또는 /sitemap.xml)에 배치하거나 웹 마스터 도구를 사용하여 Google에 알릴 수 있습니다.
어쨌든 사이트 맵을 만드는 것이 좋습니다.
브라우저 지원
Pushstate는 IE10에서 작동합니다. 이전 브라우저에서 Angular는 자동으로 해시 스타일 URL로 대체됩니다.
데모 페이지
다음 콘텐츠는 사전 구성이 포함 된 pushstate URL을 사용하여 렌더링됩니다.
http://html5.gingerhost.com/london
확인할 수 있듯이이 링크 에서 콘텐츠의 색인이 생성되고 Google에 표시됩니다.
404 및 301 헤더 상태 코드 제공
검색 엔진은 모든 요청에 대해 항상 서버에 도달하므로 서버에서 헤더 상태 코드를 제공하고 Google에서이를 볼 수 있습니다.
AngularJS와 SEO에 대한 결정을 내리자
Google, Yahoo, Bing 및 기타 검색 엔진은 기존 크롤러를 사용하여 기존 방식으로 웹을 크롤링합니다. 그들은 웹 페이지에서 HTML을 크롤링하는 로봇 을 실행 하여 그 과정에서 정보를 수집합니다. 그들은 흥미로운 단어를 유지하고 다른 페이지에 대한 다른 링크를 찾습니다 (이 링크, 그 양 및 그 수가 SEO와 함께 작동합니다).
그렇다면 검색 엔진이 자바 스크립트 사이트를 처리하지 않는 이유는 무엇입니까?
대답은 검색 엔진 로봇이 헤드리스 브라우저를 통해 작동하고 대부분의 경우 페이지의 자바 스크립트를 렌더링하는 자바 스크립트 렌더링 엔진 이 없다는 사실과 관련이 있습니다. 대부분의 정적 페이지는 콘텐츠가 이미 사용 가능하므로 대부분의 정적 페이지에서 페이지를 렌더링하는 JavaScript에 관심이 없으므로 대부분의 페이지에서 작동합니다.
그것에 대해 무엇을 할 수 있습니까?
다행히 더 큰 사이트의 크롤러는 Google에서 자바 스크립트 사이트를 크롤링 할 수 있도록하는 메커니즘을 구현하기 시작했지만,이를 위해서는 사이트를 변경해야합니다 .
우리는 우리가 변경 한 경우 hashPrefix
로 #!
대신 단지의 #
후 현대적인 검색 엔진이 사용하는 요청 변경됩니다 _escaped_fragment_
대신을 #!
. (HTML5 모드, 즉 해시 접두사가없는 링크가있는 경우 User Agent
백엔드 의 헤더 를 확인하여 동일한 기능을 구현할 수 있습니다 ).
즉, 다음과 같은 일반 브라우저의 요청 대신 :
http://www.ng-newsletter.com/#!/signup/page
검색 엔진은 다음을 사용하여 페이지를 검색합니다.
http://www.ng-newsletter.com/?_escaped_fragment_=/signup/page
에서 기본 제공 방법을 사용하여 Angular 앱의 해시 접두사를 설정할 수 있습니다 ngRoute
.
angular.module('myApp', [])
.config(['$location', function($location) {
$location.hashPrefix('!');
}]);
을 html5Mode
사용하는 경우 메타 태그를 사용하여이를 구현해야합니다.
<meta name="fragment" content="!">
알림, 우리는을 설정할 수 있습니다 html5Mode()
과 $location
서비스 :
angular.module('myApp', [])
.config(['$location',
function($location) {
$location.html5Mode(true);
}]);
검색 엔진 다루기
We have a lot of opportunities to determine how we'll deal with actually delivering content to search engines as static HTML. We can host a backend ourselves, we can use a service to host a back-end for us, we can use a proxy to deliver the content, etc. Let's look at a few options:
Self-hosted
We can write a service to handle dealing with crawling our own site using a headless browser, like phantomjs or zombiejs, taking a snapshot of the page with rendered data and storing it as HTML. Whenever we see the query string ?_escaped_fragment_
in a search request, we can deliver the static HTML snapshot we took of the page instead of the pre-rendered page through only JS. This requires us to have a backend that delivers our pages with conditional logic in the middle. We can use something like prerender.io's backend as a starting point to run this ourselves. Of course, we still need to handle the proxying and the snippet handling, but it's a good start.
With a paid service
The easiest and the fastest way to get content into search engine is to use a service Brombone, seo.js, seo4ajax, and prerender.io are good examples of these that will host the above content rendering for you. This is a good option for the times when we don't want to deal with running a server/proxy. Also, it's usually super quick.
For more information about Angular and SEO, we wrote an extensive tutorial on it at http://www.ng-newsletter.com/posts/serious-angular-seo.html and we detailed it even more in our book ng-book: The Complete Book on AngularJS. Check it out at ng-book.com.
You should really check out the tutorial on building an SEO-friendly AngularJS site on the year of moo blog. He walks you through all the steps outlined on Angular's documentation. http://www.yearofmoo.com/2012/11/angularjs-and-seo.html
Using this technique, the search engine sees the expanded HTML instead of the custom tags.
This has drastically changed.
If you use: $locationProvider.html5Mode(true); you are set.
No more rendering pages.
Things have changed quite a bit since this question was asked. There are now options to let Google index your AngularJS site. The easiest option I found was to use http://prerender.io free service that will generate the crwalable pages for you and serve that to the search engines. It is supported on almost all server side web platforms. I have recently started using them and the support is excellent too.
I do not have any affiliation with them, this is coming from a happy user.
Angular's own website serves simplified content to search engines: http://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09
Say your Angular app is consuming a Node.js/Express-driven JSON api, like /api/path/to/resource
. Perhaps you could redirect any requests with ?_escaped_fragment_
to /api/path/to/resource.html
, and use content negotiation to render an HTML template of the content, rather than return the JSON data.
The only thing is, your Angular routes would need to match 1:1 with your REST API.
EDIT: I'm realizing that this has the potential to really muddy up your REST api and I don't recommend doing it outside of very simple use-cases where it might be a natural fit.
Instead, you can use an entirely different set of routes and controllers for your robot-friendly content. But then you're duplicating all of your AngularJS routes and controllers in Node/Express.
I've settled on generating snapshots with a headless browser, even though I feel that's a little less-than-ideal.
A good practice can be found here:
http://scotch.io/tutorials/javascript/angularjs-seo-with-prerender-io?_escaped_fragment_=tag
As of now Google has changed their AJAX crawling proposal.
tl;dr: [Google] are no longer recommending the AJAX crawling proposal [Google] made back in 2009.
Google's Crawlable Ajax Spec, as referenced in the other answers here, is basically the answer.
If you're interested in how other search engines and social bots deal with the same issues I wrote up the state of art here: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html
I work for a https://ajaxsnapshots.com, a company that implements the Crawlable Ajax Spec as a service - the information in that report is based on observations from our logs.
I have found an elegant solution that would cover most of your bases. I wrote about it initially here and answered another similar StackOverflow question here which references it.
FYI this solution also includes hardcoded fallback tags in case Javascript isn't picked up by the crawler. I haven't explicitly outlined it, but it is worth mentioning that you should be activating HTML5 mode for proper URL support.
Also note: these aren't the complete files, just the important parts of those that are relevant. If you need help writing the boilerplate for directives, services, etc. that can be found elsewhere. Anyway, here goes...
app.js
This is where you provide the custom metadata for each of your routes (title, description, 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 (service)
Sets the custom metadata options or use defaults as 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 (directive)
Packages the metadata service results for the view.
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 with the hardcoded fallback tags mentioned earlier, for crawlers that can't pick up any 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>
This should help dramatically with most search engine use cases. If you want fully dynamic rendering for social network crawlers (which are iffy on Javascript support), you'll still have to use one of the pre-rendering services mentioned in some of the other answers.
Hope this helps!
Use something like PreRender, it makes static pages of your site so search engines can index it.
Here you can find out for what platforms it is available: https://prerender.io/documentation/install-middleware#asp-net
With Angular Universal, you can generate landing pages for the app that look like the complete app and then load your Angular app behind it.
Angular Universal generates pure HTML means no-javascript pages in server-side and serve them to users without delaying. So you can deal with any crawler, bot and user (who already have low cpu and network speed).Then you can redirect them by links/buttons to your actual angular app that already loaded behind it. This solution is recommended by official site. -More info about SEO and Angular Universal-
Crawlers (or bots) are designed to crawl HTML content of web pages but due to AJAX operations for asynchronous data fetching, this became a problem as it takes sometime to render page and show dynamic content on it. Similarly, AngularJS
also use asynchronous model, which creates problem for Google crawlers.
Some developers create basic html pages with real data and serve these pages from server side at the time of crawling. We can render same pages with PhantomJS
on serve side which has _escaped_fragment_
(Because Google looks for #!
in our site urls and then takes everything after the #!
and adds it in _escaped_fragment_
query parameter). For more detail please read this blog .
The crawlers do not need a rich featured pretty styled gui, they only want to see the content, so you do not need to give them a snapshot of a page that has been built for humans.
My solution: to give the crawler what the crawler wants:
You must think of what do the crawler want, and give him only that.
TIP don't mess with the back. Just add a little server-sided frontview using the same API
참고URL : https://stackoverflow.com/questions/13499040/how-do-search-engines-deal-with-angularjs-applications
'development' 카테고리의 다른 글
Java / Maven에서 "Xerces hell"을 다루고 있습니까? (0) | 2020.09.30 |
---|---|
스레드를 죽이는 방법이 있습니까? (0) | 2020.09.30 |
PHP를 사용하여 두 날짜의 차이를 계산하는 방법은 무엇입니까? (0) | 2020.09.30 |
git 저장소의 줄 수 계산 (0) | 2020.09.30 |
PHP 객체를 연관 배열로 변환 (0) | 2020.09.30 |