Làm thế nào để tạo một SEO SEO thu thập dữ liệu?


143

Tôi đã nghiên cứu cách tạo một thu thập thông tin SPA bằng cách dựa trên hướng dẫn của google . Mặc dù có khá nhiều giải thích chung, tôi không thể tìm thấy bất cứ nơi nào một hướng dẫn từng bước kỹ lưỡng hơn với các ví dụ thực tế. Sau khi hoàn thành việc này, tôi muốn chia sẻ giải pháp của mình để những người khác cũng có thể sử dụng nó và có thể cải thiện nó hơn nữa.
Tôi đang sử dụng MVCvới Webapibộ điều khiển và Phantomjs ở phía máy chủ và Durandal ở phía máy khách push-stateđược bật; Tôi cũng sử dụng Breezejs để tương tác dữ liệu giữa máy khách và máy chủ, tất cả những gì tôi đặc biệt khuyên dùng, nhưng tôi sẽ cố gắng đưa ra một lời giải thích đủ chung chung cũng sẽ giúp mọi người sử dụng các nền tảng khác.


40
liên quan đến "lạc đề" - một lập trình viên ứng dụng web phải tìm cách làm cho ứng dụng của mình có thể thu thập dữ liệu để SEO, đây là một yêu cầu cơ bản trên web. Làm điều này không phải là về lập trình, nhưng nó có liên quan đến chủ đề "các vấn đề thực tế, có thể trả lời, là duy nhất cho nghề lập trình" như được mô tả trong stackoverflow.com/help/on-topic . Đó là một vấn đề đối với nhiều lập trình viên không có giải pháp rõ ràng trên toàn bộ web. Tôi đã hy vọng giúp đỡ người khác và đầu tư hàng giờ chỉ để mô tả nó ở đây, nhận được những điểm tiêu cực chắc chắn không thúc đẩy tôi giúp đỡ một lần nữa.
rạng rỡ

3
Nếu trọng tâm là lập trình và không phải dầu rắn / nước sốt bí mật SEO voodoo / spam thì nó có thể là chủ đề hoàn hảo. Chúng tôi cũng thích tự trả lời khi chúng có tiềm năng hữu ích cho độc giả tương lai lâu dài. Cặp câu hỏi và câu trả lời này dường như vượt qua cả hai bài kiểm tra đó. (Một số chi tiết nền có thể đưa ra câu hỏi tốt hơn thay vì được giới thiệu trong câu trả lời nhưng điều đó khá nhỏ)
Flexo

6
+1 để giảm bớt phiếu bầu. Bất kể nếu q / a sẽ phù hợp hơn với bài đăng trên blog, câu hỏi có liên quan đến Durandal và câu trả lời được nghiên cứu kỹ lưỡng.
RainerAtSprite

2
Tôi đồng ý rằng SEO là một phần quan trọng hiện nay của các nhà phát triển trong cuộc sống hàng ngày và chắc chắn nên được coi là một chủ đề trong stackoverflow!
Kim D.

Ngoài việc tự mình thực hiện toàn bộ quá trình, bạn có thể thử SnapSearch snapsearch.io về cơ bản giải quyết vấn đề này như một dịch vụ.
CMCDragonkai

Câu trả lời:


121

Trước khi bắt đầu, hãy chắc chắn rằng bạn hiểu những gì google yêu cầu , đặc biệt là việc sử dụng các URL đẹpxấu . Bây giờ hãy xem việc thực hiện:

Phía khách hàng

Về phía máy khách, bạn chỉ có một trang html duy nhất tương tác với máy chủ một cách linh hoạt thông qua các cuộc gọi AJAX. đó là những gì SPA nói về. Tất cả các athẻ ở phía máy khách được tạo động trong ứng dụng của tôi, sau này chúng ta sẽ xem cách làm cho các liên kết này hiển thị với bot của google trong máy chủ. Mỗi ví dụ anhu cầu thẻ để có thể có một pretty URLtrong các hreftừ khóa để bot của google sẽ bóc tách nó. Bạn không muốn hrefphần này được sử dụng khi khách hàng nhấp vào nó (mặc dù bạn muốn máy chủ có thể phân tích cú pháp, chúng ta sẽ thấy phần đó sau), vì chúng tôi có thể không muốn tải trang mới, chỉ để thực hiện cuộc gọi AJAX nhận được một số dữ liệu được hiển thị trong một phần của trang và thay đổi URL qua javascript (ví dụ: sử dụng HTML5 pushstatehoặc với Durandaljs). Vì vậy, chúng tôi có cả mộthrefthuộc tính cho google cũng như trên onclickđó thực hiện công việc khi người dùng nhấp vào liên kết. Bây giờ, vì tôi sử dụng push-statenên tôi không muốn bất kỳ #URL nào, vì vậy một athẻ thông thường có thể trông như thế này:
<a href="http://www.xyz.com/#!/category/subCategory/product111" onClick="loadProduct('category','subCategory','product111')>see product111...</a>

'thể loại' và 'Danh mục con' có thể là các cụm từ khác, chẳng hạn như 'giao tiếp' và 'điện thoại' hoặc 'máy tính' và 'máy tính xách tay' cho một cửa hàng thiết bị điện. Rõ ràng sẽ có nhiều danh mục và danh mục phụ khác nhau. Như bạn có thể thấy, liên kết trực tiếp đến danh mục, danh mục phụ và sản phẩm, không phải là tham số phụ cho trang 'cửa hàng' cụ thể, chẳng hạn như http://www.xyz.com/store/category/subCategory/product111. Điều này là do tôi thích các liên kết ngắn hơn và đơn giản hơn. Nó ngụ ý rằng tôi sẽ không có một danh mục có cùng tên với một trong những 'trang' của tôi, tức là '
Tôi sẽ không đi sâu vào cách tải dữ liệu qua AJAX ( onclickphần), tìm kiếm nó trên google, có nhiều lời giải thích hay. Điều quan trọng duy nhất ở đây mà tôi muốn đề cập là khi người dùng nhấp vào liên kết này, tôi muốn URL trong trình duyệt trông như thế này:
http://www.xyz.com/category/subCategory/product111. Và đây là URL không được gửi đến máy chủ! hãy nhớ rằng, đây là một SPA nơi tất cả các tương tác giữa máy khách và máy chủ được thực hiện thông qua AJAX, không có liên kết nào cả! tất cả 'trang' được triển khai ở phía máy khách và URL khác nhau không thực hiện cuộc gọi đến máy chủ (máy chủ cần biết cách xử lý các URL này trong trường hợp chúng được sử dụng làm liên kết ngoài từ trang web khác đến trang web của bạn, chúng ta sẽ thấy điều đó sau trong phần phía máy chủ). Bây giờ, điều này được Durandal xử lý tuyệt vời. Tôi thực sự khuyên bạn nên dùng nó, nhưng bạn cũng có thể bỏ qua phần này nếu bạn thích các công nghệ khác. Nếu bạn chọn nó và bạn cũng đang sử dụng MS Visual Studio Express 2012 cho Web như tôi, bạn có thể cài đặt Durandal Starter Kit , và ở đó shell.js, sử dụng một cái gì đó như thế này:

define(['plugins/router', 'durandal/app'], function (router, app) {
    return {
        router: router,
        activate: function () {
            router.map([
                { route: '', title: 'Store', moduleId: 'viewmodels/store', nav: true },
                { route: 'about', moduleId: 'viewmodels/about', nav: true }
            ])
                .buildNavigationModel()
                .mapUnknownRoutes(function (instruction) {
                    instruction.config.moduleId = 'viewmodels/store';
                    instruction.fragment = instruction.fragment.replace("!/", ""); // for pretty-URLs, '#' already removed because of push-state, only ! remains
                    return instruction;
                });
            return router.activate({ pushState: true });
        }
    };
});

Có một vài điều quan trọng cần chú ý ở đây:

  1. Tuyến đầu tiên (có route:'') dành cho URL không có dữ liệu bổ sung trong đó, nghĩa là http://www.xyz.com. Trong trang này, bạn tải dữ liệu chung bằng AJAX. Thực tế có thể không có athẻ nào trong trang này. Bạn sẽ muốn thêm thẻ sau để bot của google sẽ biết phải làm gì với nó :
    <meta name="fragment" content="!">. Thẻ này sẽ khiến bot của google biến đổi URL www.xyz.com?_escaped_fragment_=mà chúng ta sẽ thấy sau này.
  2. Lộ trình 'about' chỉ là một ví dụ cho một liên kết đến các 'trang' khác mà bạn có thể muốn trên ứng dụng web của mình.
  3. Bây giờ, phần khó khăn là không có tuyến đường 'loại' và có thể có nhiều loại khác nhau - không có loại nào có tuyến đường được xác định trước. Đây là nơi mapUnknownRoutesđến. Nó ánh xạ các tuyến đường không xác định này đến tuyến đường 'cửa hàng' và cũng loại bỏ bất kỳ '!' từ URL trong trường hợp nó pretty URLđược tạo bởi công cụ tìm kiếm của google. Tuyến đường 'cửa hàng' lấy thông tin trong thuộc tính 'mảnh' và thực hiện cuộc gọi AJAX để lấy dữ liệu, hiển thị nó và thay đổi URL cục bộ. Trong ứng dụng của mình, tôi không tải một trang khác cho mỗi cuộc gọi như vậy; Tôi chỉ thay đổi một phần của trang nơi dữ liệu này có liên quan và cũng thay đổi URL cục bộ.
  4. Lưu ý pushState:truehướng dẫn Durandal sử dụng URL trạng thái đẩy.

Đây là tất cả những gì chúng tôi cần ở phía khách hàng. Nó cũng có thể được thực hiện với các URL được băm (trong Durandal, bạn chỉ cần xóa phần pushState:trueđó). Phần phức tạp hơn (ít nhất là đối với tôi ...) là phần máy chủ:

Phía máy chủ

Tôi đang sử dụng MVC 4.5ở phía máy chủ với WebAPIbộ điều khiển. Các máy chủ thực sự cần phải xử lý 3 loại URL: những người được tạo ra bởi google - cả hai prettyuglyvà cũng là một 'đơn giản' URL với định dạng giống như một trong đó sẽ xuất hiện trong trình duyệt của khách hàng. Hãy xem cách làm điều này:

Các URL đẹp và 'đơn giản' trước tiên được máy chủ diễn giải như thể cố gắng tham chiếu bộ điều khiển không tồn tại. Máy chủ nhìn thấy một cái gì đó giống như http://www.xyz.com/category/subCategory/product111và tìm kiếm một bộ điều khiển có tên 'thể loại'. Vì vậy, trong web.configtôi thêm dòng sau để chuyển hướng chúng đến bộ điều khiển xử lý lỗi cụ thể:

<customErrors mode="On" defaultRedirect="Error">
    <error statusCode="404" redirect="Error" />
</customErrors><br/>

Bây giờ, điều này biến đổi URL thành một cái gì đó như : http://www.xyz.com/Error?aspxerrorpath=/category/subCategory/product111. Tôi muốn URL được gửi đến máy khách sẽ tải dữ liệu qua AJAX, vì vậy mẹo ở đây là gọi bộ điều khiển 'index' mặc định như thể không tham chiếu bất kỳ bộ điều khiển nào; Tôi làm điều đó bằng cách thêm một hàm băm vào URL trước tất cả các tham số 'thể loại' và 'danh mục con'; URL băm không yêu cầu bất kỳ bộ điều khiển đặc biệt nào ngoại trừ bộ điều khiển 'index' mặc định và dữ liệu được gửi đến máy khách sau đó loại bỏ hàm băm và sử dụng thông tin sau khi băm để tải dữ liệu qua AJAX. Đây là mã điều khiển xử lý lỗi:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

using System.Web.Routing;

namespace eShop.Controllers
{
    public class ErrorController : ApiController
    {
        [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH"), AllowAnonymous]
        public HttpResponseMessage Handle404()
        {
            string [] parts = Request.RequestUri.OriginalString.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
            string parameters = parts[ 1 ].Replace("aspxerrorpath=","");
            var response = Request.CreateResponse(HttpStatusCode.Redirect);
            response.Headers.Location = new Uri(parts[0].Replace("Error","") + string.Format("#{0}", parameters));
            return response;
        }
    }
}


Nhưng những gì về các URL xấu xí ? Chúng được tạo bởi bot của google và sẽ trả về HTML đơn giản chứa tất cả dữ liệu mà người dùng nhìn thấy trong trình duyệt. Đối với điều này, tôi sử dụng ph Phantomjs . Phantom là một trình duyệt không đầu làm những gì trình duyệt đang làm ở phía máy khách - nhưng ở phía máy chủ. Nói cách khác, ph Phantom biết (trong số những thứ khác) làm thế nào để có được một trang web thông qua một URL, phân tích nó bao gồm chạy tất cả mã javascript trong đó (cũng như nhận dữ liệu qua các cuộc gọi AJAX) và cung cấp cho bạn HTML phản ánh DOM. Nếu bạn đang sử dụng MS Visual Studio Express, nhiều người muốn cài đặt ảo thông qua liên kết này .
Nhưng trước tiên, khi một URL xấu xí được gửi đến máy chủ, chúng ta phải bắt nó; Đối với điều này, tôi đã thêm vào thư mục 'App_start' tệp sau:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace eShop.App_Start
{
    public class AjaxCrawlableAttribute : ActionFilterAttribute
    {
        private const string Fragment = "_escaped_fragment_";

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var request = filterContext.RequestContext.HttpContext.Request;

            if (request.QueryString[Fragment] != null)
            {

                var url = request.Url.ToString().Replace("?_escaped_fragment_=", "#");

                filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary { { "controller", "HtmlSnapshot" }, { "action", "returnHTML" }, { "url", url } });
            }
            return;
        }
    }
}

Điều này được gọi từ 'filterConfig.cs' cũng trong 'App_start':

using System.Web.Mvc;
using eShop.App_Start;

namespace eShop
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new AjaxCrawlableAttribute());
        }
    }
}

Như bạn có thể thấy, 'AjaxCrawlableAttribution' định tuyến các URL xấu đến bộ điều khiển có tên 'HtmlSnapshot' và đây là bộ điều khiển này:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace eShop.Controllers
{
    public class HtmlSnapshotController : Controller
    {
        public ActionResult returnHTML(string url)
        {
            string appRoot = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);

            var startInfo = new ProcessStartInfo
            {
                Arguments = String.Format("{0} {1}", Path.Combine(appRoot, "seo\\createSnapshot.js"), url),
                FileName = Path.Combine(appRoot, "bin\\phantomjs.exe"),
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,
                StandardOutputEncoding = System.Text.Encoding.UTF8
            };
            var p = new Process();
            p.StartInfo = startInfo;
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            ViewData["result"] = output;
            return View();
        }

    }
}

Liên kết viewrất đơn giản, chỉ cần một dòng mã:
@Html.Raw( ViewBag.result )
Như bạn có thể thấy trong bộ điều khiển, ph Phantom tải một tệp javascript có tên createSnapshot.jstrong thư mục mà tôi đã tạo được gọi seo. Đây là tập tin javascript này:

var page = require('webpage').create();
var system = require('system');

var lastReceived = new Date().getTime();
var requestCount = 0;
var responseCount = 0;
var requestIds = [];
var startTime = new Date().getTime();

page.onResourceReceived = function (response) {
    if (requestIds.indexOf(response.id) !== -1) {
        lastReceived = new Date().getTime();
        responseCount++;
        requestIds[requestIds.indexOf(response.id)] = null;
    }
};
page.onResourceRequested = function (request) {
    if (requestIds.indexOf(request.id) === -1) {
        requestIds.push(request.id);
        requestCount++;
    }
};

function checkLoaded() {
    return page.evaluate(function () {
        return document.all["compositionComplete"];
    }) != null;
}
// Open the page
page.open(system.args[1], function () { });

var checkComplete = function () {
    // We don't allow it to take longer than 5 seconds but
    // don't return until all requests are finished
    if ((new Date().getTime() - lastReceived > 300 && requestCount === responseCount) || new Date().getTime() - startTime > 10000 || checkLoaded()) {
        clearInterval(checkCompleteInterval);
        var result = page.content;
        //result = result.substring(0, 10000);
        console.log(result);
        //console.log(results);
        phantom.exit();
    }
}
// Let us check to see if the page is finished rendering
var checkCompleteInterval = setInterval(checkComplete, 300);

Trước tiên tôi muốn cảm ơn Thomas Davis cho trang mà tôi đã nhận được mã cơ bản từ :-).
Bạn sẽ nhận thấy một điều kỳ lạ ở đây: ph Phantom tiếp tục tải lại trang cho đến khi checkLoaded()hàm trả về đúng. Tại sao vậy? điều này là do SPA cụ thể của tôi thực hiện một số cuộc gọi AJAX để lấy tất cả dữ liệu và đặt nó vào DOM trên trang của tôi và ảo không thể biết khi nào tất cả các cuộc gọi đã hoàn thành trước khi trả lại cho tôi phản ánh HTML của DOM. Những gì tôi đã làm ở đây là sau cuộc gọi AJAX cuối cùng tôi thêm một <span id='compositionComplete'></span>, để nếu thẻ này tồn tại tôi biết DOM đã hoàn thành. Tôi làm điều này để đáp lại compositionCompletesự kiện của Durandal , xem tại đâyđể biết thêm Nếu điều này không xảy ra trong 10 giây, tôi sẽ bỏ cuộc (chỉ mất một giây để có nhiều nhất). HTML được trả về chứa tất cả các liên kết mà người dùng nhìn thấy trong trình duyệt. Tập lệnh sẽ không hoạt động chính xác vì các <script>thẻ tồn tại trong ảnh chụp nhanh HTML không tham chiếu đúng URL. Điều này cũng có thể được thay đổi trong tệp ảo javascript, nhưng tôi không nghĩ đây là cần thiết vì snapshort HTML chỉ được google sử dụng để lấy các aliên kết và không chạy javascript; các liên kết này tham chiếu một URL đẹp và nếu thực tế, nếu bạn cố gắng xem ảnh chụp nhanh HTML trong trình duyệt, bạn sẽ gặp lỗi javascript nhưng tất cả các liên kết sẽ hoạt động bình thường và đưa bạn đến máy chủ một lần nữa với một URL đẹp nhận được trang làm việc đầy đủ.
Đây là nó. Bây giờ máy chủ đã biết cách xử lý cả URL đẹp và xấu, với trạng thái đẩy được bật trên cả máy chủ và máy khách. Tất cả các URL xấu được xử lý theo cùng một cách sử dụng ảo, do đó không cần phải tạo một bộ điều khiển riêng cho từng loại cuộc gọi.
Một điều bạn có thể muốn thay đổi không phải là thực hiện cuộc gọi 'danh mục / danh mục con / sản phẩm' chung chung mà là thêm một 'cửa hàng' để liên kết sẽ trông giống như : http://www.xyz.com/store/category/subCategory/product111. Điều này sẽ tránh được vấn đề trong giải pháp của tôi là tất cả các URL không hợp lệ được xử lý như thể chúng thực sự được gọi đến bộ điều khiển 'index' và tôi cho rằng chúng có thể được xử lý sau đó trong bộ điều khiển 'store' mà không cần thêm vào trình web.configbày ở trên .


Tôi có một câu hỏi nhanh, tôi nghĩ rằng tôi đã làm việc này ngay bây giờ nhưng khi tôi gửi trang web của mình lên google và cung cấp liên kết đến google, bản đồ trang web, v.v. tôi có cần phải cung cấp cho google mysite.com/# ! hoặc chỉ mysite.com và google sẽ thêm vào escoped_fragment vì tôi có nó trong thẻ meta?
ccorrin

ccorrin - theo hiểu biết tốt nhất của tôi, bạn không cần phải cung cấp cho google bất cứ điều gì; bot của google sẽ tìm thấy trang web của bạn và tìm trong đó các URL đẹp (đừng quên trong trang chủ để thêm thẻ meta, vì nó có thể không chứa bất kỳ URL nào). URL xấu xí chứa escoped_fragment luôn chỉ được thêm bởi google - bạn không bao giờ nên tự đặt nó vào trong HTML của mình. và cảm ơn sự hỗ trợ :-)
rạng rỡ

cảm ơn Bjorn & Sandra :-) Tôi đang làm việc với phiên bản tốt hơn của tài liệu này, nó cũng sẽ bao gồm thông tin về cách lưu trữ các trang để làm cho quá trình nhanh hơn và thực hiện nó trong sử dụng phổ biến hơn nơi url chứa tên người điều khiển; Tôi sẽ đăng nó ngay khi nó sẵn sàng
rạng rỡ

Đây là một lời giải thích tuyệt vời !! Tôi đã triển khai nó và hoạt động như một bùa mê trong devbox localhost của tôi. Vấn đề là khi triển khai lên trang web Azure vì trang web bị đóng băng và sau một thời gian tôi gặp lỗi 502. Bạn có ý tưởng nào về cách triển khai ph Phantomjs lên Azure không? ... Cảm ơn ( testypv.azurewebsites.net/?_escoped_fragment_=home/about )
yagopv

Tôi không có kinh nghiệm với các trang web Azure, nhưng điều tôi suy nghĩ là có lẽ quá trình kiểm tra để tải trang đầy đủ không bao giờ được thực hiện nên máy chủ tiếp tục cố gắng tải lại trang này nhiều lần nhưng không thành công. có lẽ đó là vấn đề (mặc dù có giới hạn thời gian cho các kiểm tra này nên có thể không có ở đó)? cố gắng đặt 'trở về đúng;' là dòng đầu tiên trong 'checkLoaded ()' và xem liệu nó có tạo ra sự khác biệt không.
rạng rỡ


4

Đây là một liên kết đến bản ghi âm từ lớp đào tạo Ember.js của tôi, tôi đã tổ chức ở London vào ngày 14 tháng 8. Nó phác thảo một chiến lược cho cả ứng dụng phía khách của bạn và cho ứng dụng phía máy chủ của bạn, cũng như trình diễn trực tiếp về cách triển khai các tính năng này sẽ cung cấp cho Ứng dụng JavaScript một trang của bạn xuống cấp ngay cả đối với người dùng đã tắt JavaScript .

Nó sử dụng PhantomJS để hỗ trợ thu thập dữ liệu trang web của bạn.

Nói tóm lại, các bước cần thiết là:

  • Có phiên bản lưu trữ của ứng dụng web bạn muốn thu thập dữ liệu, trang web này cần phải có TẤT CẢ dữ liệu bạn có trong sản xuất
  • Viết một ứng dụng JavaScript (PhantomJS Script) để tải trang web của bạn
  • Thêm index.html (hoặc tên miền / Lần) vào danh sách URL để thu thập dữ liệu
    • Bật URL đầu tiên được thêm vào danh sách thu thập thông tin
    • Tải trang và hiển thị DOM của nó
    • Tìm bất kỳ liên kết nào trên trang được tải liên kết đến trang web của riêng bạn (lọc URL)
    • Thêm liên kết này vào danh sách các URL URLS có thể thu thập dữ liệu, nếu nó chưa được thu thập thông tin
    • Lưu trữ DOM được kết xuất vào một tệp trên hệ thống tệp, nhưng loại bỏ TẤT CẢ các thẻ script trước
    • Cuối cùng, hãy tạo tệp Sitemap.xml bằng các URL được thu thập thông tin

Khi bước này được thực hiện, tùy thuộc vào phần phụ trợ của bạn để phục vụ phiên bản tĩnh của HTML như một phần của thẻ noscript trên trang đó. Điều này sẽ cho phép Google và các công cụ tìm kiếm khác thu thập dữ liệu từng trang trên trang web của bạn, mặc dù ứng dụng ban đầu của bạn là một ứng dụng một trang.

Liên kết đến screencast với các chi tiết đầy đủ:

http://www.devcasts.io/p/spas-ph Phantomjs-and-seo/#


0

Bạn có thể sử dụng hoặc tạo dịch vụ của riêng mình để giới thiệu SPA của bạn với dịch vụ được gọi là prerender. Bạn có thể kiểm tra nó trên trang web prerender.io của anh ấy và trên dự án github của anh ấy (Nó sử dụng PhantomJS và nó hiển thị trang web của bạn cho bạn).

Nó rất dễ dàng để bắt đầu. Bạn chỉ phải chuyển hướng yêu cầu trình thu thập thông tin đến dịch vụ và họ sẽ nhận được html được kết xuất.


2
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
hồ bấm giờ

2
Bạn đúng rồi. Tôi đã cập nhật nhận xét của mình ... Tôi hy vọng bây giờ nó chính xác hơn.
gabrielperales

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.