CRAWL динамічних сторінок для пошуковиків Google і Яндекс (snapshots, _escaped_fragment_, ajax, fragment)

image

Всім мир!

Зміст статті:

1. Що таке CRAWL
2. Динамічний CRAWL
3. Завдання, інструменти, рішення
4. Почитати
5. Висновки



1. Що таке CRAWL



Це сканування пошуковими системами сторінок сайту з метою отримати необхідну інформацію. Результат виконання даного сканування є html подання в кінцевій точці (у кожної пошукової системи свої налаштування, а саме вантажити чи ні js (з запуском або без), css, img і т. д.) або як це ще називають «знімок» сайту.

2. Динамічний CRAWL



Тут мова буде йти про динамічному CRAWL сторінки, а саме коли у вас сайт має динамічний контент (або як це називають Ajax контент). У мене проект з використанням Angular.js + HTML5 Router (це коли без domain.ru#!path, а ось так domain.ru/path ), весь контент змінюється <ng-view></ng-view>і один єдиний index.php і спеціальні настройки .htaccess, для того, щоб після оновлення сторінки все відобразилося як треба.

Це прописано в налаштуваннях роутера angular:
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});


Це прописано в .htaccess:
RewriteEngine on

# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.php [L]


3. Завдання, інструменти, рішення



Завдання:
1. Віддавати динамічний контент сторінки такий, який він стає після закінчення рендеринга і ініціалізації програми
2. Формуємо, Оптимізуємо і Стискаємо html знімок сторінки
3. Віддаємо пошуковій системі html знімок

Інструменти:
1. Встановлена NPM (npm — це пакетний менеджер node.js. З його допомогою можна керувати модулями і залежностями.)
2. Встановлений модуль html-snapshots з допомогою команди:
npm install html-snapshots

3. Правильна конфігурація

Рішення:
Для швидкодії рекомендую виконувати «кравлинг» на localhost (локальному веб-сервері)

Для початку потрібно додати в головний index.php у meta tag в head:
<meta name="fragment" content="!">


Приклад sitemap.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- created with www.mysitemapgenerator.com -->
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>http://localhost/domain.ru/www/product/30</loc>
<lastmod>2016-07-22T19:47:25+01:00</lastmod>
<priority>1.0</priority>
</url>
</urlser>


Конфігурація server.js:

var fs = require("fs");
var path = require("path");
var util = require("util");
var assert = require("assert");
var htmlSnapshots = require("html-snapshots");
var minify = require('html-minifier').minify;

htmlSnapshots.run({

//#1 З використанням SITEMAP
//input: "sitemap",
//source: "sitemap_localhost.xml",

//#2 Масив посилань на сторінки сайту
input: "array",
source: ["http://localhost/domain.ru/www/product/30"],
//protocol: "https",

// setup and manage the output
outputDir: path.join(__dirname, "./tmp"),

//Чистить директорію перед збереженням нових копій
outputDirClean: false,
// Селектор будь-якого блоку, який знаходиться всередині <ng-view></ng-view> і відображається після ініціалізації додатка
selector: "#product",
//Обмежити час завантаження до 12 секунд, а можна і більше
timeout: 120000,
//Установки допомагають відображати контент швидше для CRAWL
phantomjsOptions: [
"--ssl-protocol=any",
"--ignore-ssl-errors=true",
"--load-images=false"
]

}, function (err, snapshotsCompleted) {

var body;

console.log("completed snapshots:");

assert.ifError(err);

snapshotsCompleted.forEach(function(snapshotFile) {

body = fs.readFileSync(snapshotFile, { encoding: "utf8"});

//Прибираємо стилі та їх зміст
var regExp = /<style[^>]*?>.*?<\/style>/ig;
var clearBody = body.replace(regExp, ");

//Робимо заміну доменного імені
var domain = /http:\/\/localhost\/domain.ru\/www/ig;
clearBody = clearBody.replace(domain, '//domain.ru');

//Проводимо оптимізацію html файлу
clearBody = minify(clearBody, {
conservativeCollapse: true,
removeComments: true,
removeEmptyAttributes: true,
removeEmptyElements: true,
collapseWhitespace: true
});
//Записуємо в файл
fs.open(snapshotFile, 'w', function(e, fd) {
if (e) return;
fs.write(fd, clearBody);
});

});

});

console.log('FINISH');



Запуск командою:
node server


Розуміння алгоритму:

1. Спочатку він «кравлит всі сторінки
2. Створює файли і називає папки за вашим url: product/30/index.hmtl (index.html, а можна і product/30.html кому як зручніше на швидкість не впливає)
3. Після цього викликає callback -> snapshotsCompleted, де виробляє оптимізацію кожного index.html знімка вашої сторінки

Знімки вашого сайту підготовлені, залишилося віддати їх пошуковому боту при заході:

index.php
if (isset($_GET['_escaped_fragment_'])) {
if ($_GET['_escaped_fragment_'] != "){
$val = $_GET['_escaped_fragment_'];
include_once "snapshots" . $val . '/index.html';
}else{
$url = "https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
$arrUrl = parse_url($url);
$val = $arrUrl['path'];
include_once "snapshots" . $val . '/index.html';
}
}else {
include_once('pages/home.php');
}


Пояснення:

1. html5 push state
If you use html5 push state (recommended):
Just add this meta tag to the head of your pages
<meta name="fragment" content="!"> 


If your URLs look like this:
www.example.com/user/1
Then access your URLs like this:
www.example.com/user/1?_escaped_fragment_=

2. hashbang
If you use the hashbang (#!):
If your URLs look like this:
www.example.com/#!/user/1

Then access your URLs like this:
www.example.com/?_escaped_fragment_=/user/1

Додатково, для тих у кого є знімки, але немає оптимізації:

var fs = require("fs");
var minify = require('html-minifier').minify;
var path = require("path");
var util = require("util");
var assert = require("assert");
var htmlSnapshots = require("html-snapshots");

//Отримання списку тек
var myPath = path.join(__dirname, "./tmp/domain.ua/www/");

function getFiles (dir, files_){
files_ = files_ || [];
var files = fs.readdirSync(dir);
for (var i in files){
var name = dir + '/' + files[i];
if (fs.statSync(name).isDirectory()){
getFiles(name, files_);
} else {
files_.push(name);
}
}
return files_;
}

var allFiles = getFiles(myPath);
//var allFiles = [ 'C:\\xampp\\htdocs\\nodejs\\crawler\\tmp\\domain.ru\\www\\/product/30/index.html' ];
var body;
allFiles.forEach(function(snapshotFile){

body = fs.readFileSync(snapshotFile, { encoding: "utf8"});

var regExp = /<style[^>]*?>.*?<\/style>/ig;
var clearBody = body.replace(regExp, ");

var domain = /http:\/\/localhost\/domain.ru\/www/ig;
clearBody = clearBody.replace(domain, '//domain.ru');

clearBody = minify(clearBody, {
conservativeCollapse: true,
removeComments: true,
removeEmptyAttributes: true,
removeEmptyElements: true,
collapseWhitespace: true
});

var social = /<ul class=\"social-links\">.*?<\/ul>/ig;
clearBody = clearBody.replace(social, ");

fs.open(snapshotFile, 'w', function(e, fd) {
if (e) return;
fs.write(fd, clearBody);
});

});

console.log('COMPLETE');


4. Почитати



stackoverflow.com/questions/2727167/getting-all-filenames-in-a-directory-with-node-js — робота з файлами node.js
github.com/localnerve/html-snapshots — snapshots module doc
perfectionkills.com/experimenting-with-html-minifier — options snapshots module doc

yandex.ru/support/webmaster/robot-workings/ajax-indexing.xml — yandex crawler info
developers.google.com/webmasters/ajax-crawling/docs/specification — google crawler info

www.ng-newsletter.com/posts/serious-angular-seo.html — article
prerender.io/js-seo/angularjs-seo-get-your-site-indexed-and-to-the-top-of-the-search-results — article
prerender.io/documentation — article

regexr.com — regexr
stackoverflow.com/questions/15618005/jquery-regexp-selecting-and-removeclass — regexr

5. Висновки



Тепер сміливо можна писати будь-які SPA програми не турбуючись за їхнє «кравлинг» пошуковим ботом, також ви можете підібрати під свій набір інструментів потрібну конфігурацію як для «сервера», так і для «клієнта»!

Всім професійних успіхів!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.