FreeBSD Sitemap XML Checker dengan NPM dan Go Lang

· 2 min read

Dengan adanya sitemap, kita akan lebih mudah dalam melakukan teknik SEO. Karena sitemap merupakan bagian penting dari SEO dan kita perlu memastikannya

Jika Anda ingin membuat file sitemap, Anda harus memperhatikan protokol sitemap. Format umum protokol sitemap terdiri dari tag XML. Semua nilai data dalam sitemap harus di-escape dari entitas. File itu sendiri harus dikodekan UTF-8. Biasanya saat membuat sitemap, dimulai dengan tag pembuka <urlset> dan diakhiri dengan tag penutup </urlset>.

Fungsi utama sitemap adalah sebagai cara untuk memberi tahu mesin pencari seperti Google Search Console halaman mana di situs Anda yang harus di-crawl dan seberapa sering halaman tersebut di-crawl oleh mesin pencari. Jika format sitemap yang Anda tulis salah atau tidak valid, jangan harap mesin pencari akan meng-crawl konten situs web Anda.

Sitemap merupakan bagian yang cukup krusial dari struktur utama situs web. Jika Anda ingin situs web Anda mendapatkan peringkat tinggi di SERP, sitemap juga dapat berkontribusi pada strategi SEO yang Anda terapkan. Sebab, informasi berupa kategori, postingan, halaman, gambar, dan tag, semuanya tercantum di halaman sitemap.

Dalam artikel ini kita akan membuat aplikasi pemeriksa URL peta situs menggunakan GO dan NPM. Penulisan dan penerapan seluruh konten artikel ini menggunakan FreeBSD 13.2.

Generated by Embed Youtube Video online

Sitemap Checker dengan Go

Pada bagian pertama ini kita akan membuat pemeriksa sitemap dengan bantuan bahasa pemrograman Go. Dengan bantuan Go, membuat peta situs sangatlah mudah dan sangat membantu dalam mengoreksi URL yang rusak atau tidak valid.

Untuk memulainya kita akan membuat direktori kerja yang disebut "FreeBSD_sitemap_checker". Di direktori ini kita akan membuat satu folder dengan nama "build dan sitemap-checker". Di folder ini semua file NPM dan pemeriksa peta situs Go akan ditempatkan. Oke, mari kita jalankan perintahnya.

root@ns3:~ # cd /var
root@ns3:/var # mkdir -p FreeBSD_sitemap_checker
root@ns3:/var # cd FreeBSD_sitemap_checker
root@ns3:/var/FreeBSD_sitemap_checker # mkdir -p sitemap-checker
root@ns3:/var/FreeBSD_sitemap_checker #
Untuk membuat pemeriksa peta situs dengan Go, kita akan menggunakan folder "/var/FreeBSD_sitemap_checker/sitemap-checker". Buat 3 file dalam folder tersebut dengan menjalankan skrip berikut.
root@ns3:/var/FreeBSD_sitemap_checker # cd sitemap-checker
root@ns3:/var/FreeBSD_sitemap_checker/sitemap-checker # touch main.go sitemap.go sitemap_index.go
Pada setiap file ketikkan script dibawah ini, dengan membuka link yang sudah kami tulis dibawah ini

/var/FreeBSD_sitemap_checker/sitemap-checker/main.go

https://raw.githubusercontent.com/unixwinbsd/FreeBSD_sitemap_checker/main/sitemap-checker/main.go

/var/FreeBSD_sitemap_checker/sitemap-checker/sitemap.go

https://raw.githubusercontent.com/unixwinbsd/FreeBSD_sitemap_checker/main/sitemap-checker/sitemap.go

/var/FreeBSD_sitemap_checker/sitemap-checker/sitemap_index.go

https://raw.githubusercontent.com/unixwinbsd/FreeBSD_sitemap_checker/main/sitemap-checker/sitemap_index.go

Agar Anda dapat menjalankan ketiga file ini, gunakan perintah di bawah ini.
root@ns3:/var/FreeBSD_sitemap_checker/sitemap-checker # go mod init sitemap-checker
root@ns3:/var/FreeBSD_sitemap_checker/sitemap-checker # go mod tidy
Setelah itu jalankan perintah "go build", untuk menghasilkan file biner yang nantinya akan kita gunakan untuk menjalankan aplikasi ini.
root@ns3:/var/FreeBSD_sitemap_checker/sitemap-checker # go build -v ./...
Perintah di atas akan menghasilkan file biner yang disebut "sitemap-checker", jalankan file ini untuk memulai aplikasi.
root@ns3:/var/FreeBSD_sitemap_checker/sitemap-checker # ./sitemap-checker -uri=https://www.unixwinbsd.site/sitemap.xml -out=output.xml
Anda dapat melihat hasilnya pada gambar di bawah.


Sitemap Checker dengan GO Lang




Sitemap Checker dengan NPM

Setelah Anda berhasil membuat pemeriksa peta situs dalam bahasa Go. Kita lanjutkan dengan membuat pemeriksa peta situs dengan NPM. Pemeriksa peta situs ini berjalan di Java, di FreeBSD Anda harus menginstal Node dan NPM. Berikut adalah panduan untuk menginstal aplikasi tersebut.
root@ns3:~ # pkg install npm-node21-10.2.5
root@ns3:~ # pkg install node21-21.4.0_1
Dalam pembahasan pemeriksa peta situs dengan NPM, kita akan membuat folder dengan nama "build". Jalankan perintah berikut untuk membuat folder tersebut.
root@ns3:~ # cd /var/FreeBSD_sitemap_checker
root@ns3:/var/FreeBSD_sitemap_checker # mkdir -p build
root@ns3:/var/FreeBSD_sitemap_checker # cd build
root@ns3:/var/FreeBSD_sitemap_checker/build #
Di folder /var/FreeBSD_sitemap_checker/build, buat file bernama "main.js".
root@ns3:/var/FreeBSD_sitemap_checker/build # touch main.js
Pada file "/var/FreeBSD_sitemap_checker/build/main.js, ketik skrip di bawah ini.

#!/usr/bin/env node
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var _this = this;
var chalk = require('chalk');
var axios = require('axios').default;
var parseString = require('xml2js').parseString;
var yargs = require("yargs");
var options = yargs
    .usage("Usage: [options] <URL>")
    .option('t', { alias: 'timeout', describe: "Timeout in seconds for a single URL", type: "number", default: 10 })
    .option('maxPerSitemap', { describe: "Maximum number of URLs to fetch from a single sitemap (default -1: visit all URLs)", type: "number", default: -1 })
    .demandCommand(1)
    .argv;
var log = console.log;
var d = function () {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
    }
    log.apply(void 0, args);
};
var dd = function () {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
    }
    log.apply(void 0, args);
    process.exit();
};
if (isNaN(options.timeout)) {
    log("Invalid value for timeout: " + options.timeout);
    process.exit(1);
}
if (isNaN(options.maxPerSitemap)) {
    log("Invalid value for maxPerSitemap: " + options.maxPerSitemap);
    process.exit(1);
}
axios.defaults.timeout = options.timeout * 1000;
var parseXml = function (xml) {
    return new Promise(function (resolve, reject) {
        parseString(xml, { explicitArray: false }, function (err, ok) {
            if (err)
                return resolve(err);
            return resolve(ok);
        });
    });
};
var isTimeoutError = function (err) {
    return err.code === 'ECONNABORTED' && err.message.indexOf('timeout') !== -1;
};
var headUrl = function (url) { return __awaiter(_this, void 0, void 0, function () {
    var result, err_1, statusOk, statusMsg;
    return __generator(this, function (_a) {
        switch (_a.label) {
            case 0:
                result = null;
                _a.label = 1;
            case 1:
                _a.trys.push([1, 3, , 4]);
                return [4 /*yield*/, axios.head(url)];
            case 2:
                result = _a.sent();
                return [3 /*break*/, 4];
            case 3:
                err_1 = _a.sent();
                result = null;
                return [3 /*break*/, 4];
            case 4:
                statusOk = result && result.status === 200;
                statusMsg = statusOk ? chalk.green('200 OK') : chalk.red('HTTP NOT OK');
                log("URL: " + url + " " + statusMsg);
                return [2 /*return*/];
        }
    });
}); };
var parseSitemap = function (url) { return __awaiter(_this, void 0, void 0, function () {
    var result, hasTimedOut, err_2, statusOk, response, data, err_3, isSitemap, isSitemapList, dataOk, statusMsg, msg, xmlValidMsg, type, urls, _i, urls_1, url_1, urls, _a, urls_2, url_2;
    return __generator(this, function (_b) {
        switch (_b.label) {
            case 0:
                hasTimedOut = false;
                _b.label = 1;
            case 1:
                _b.trys.push([1, 3, , 4]);
                return [4 /*yield*/, axios.get(url)];
            case 2:
                result = _b.sent();
                return [3 /*break*/, 4];
            case 3:
                err_2 = _b.sent();
                hasTimedOut = isTimeoutError(err_2);
                result = null;
                return [3 /*break*/, 4];
            case 4:
                statusOk = result && result.status === 200;
                response = result && result.data;
                _b.label = 5;
            case 5:
                _b.trys.push([5, 7, , 8]);
                return [4 /*yield*/, parseXml(response)];
            case 6:
                data = _b.sent();
                return [3 /*break*/, 8];
            case 7:
                err_3 = _b.sent();
                data = null;
                return [3 /*break*/, 8];
            case 8:
                isSitemap = data && data['urlset'] && data['urlset']['url'];
                isSitemapList = data && data['sitemapindex'] && data['sitemapindex']['sitemap'];
                dataOk = isSitemap || isSitemapList;
                if (statusOk) {
                    statusMsg = chalk.green('Fetched');
                }
                else {
                    msg = 'Not Fetched';
                    if (hasTimedOut) {
                        msg += ' (Timeout)';
                    }
                    statusMsg = chalk.red(msg);
                }
                xmlValidMsg = '';
                if (statusOk) {
                    if (dataOk) {
                        xmlValidMsg = chalk.green('Valid XML');
                    }
                    else {
                        xmlValidMsg = chalk.red('Invalid XML');
                    }
                }
                type = 'URL';
                if (isSitemapList) {
                    type = 'SITEMAP LIST';
                }
                else if (isSitemap) {
                    type = 'SITEMAP';
                }
                type = chalk.blue(type);
                log(type + ": " + url + " " + statusMsg + " " + xmlValidMsg);
                if (!statusOk) return [3 /*break*/, 17];
                if (!isSitemapList) return [3 /*break*/, 13];
                urls = data['sitemapindex']['sitemap'].map(function (el) { return el['loc']; });
                _i = 0, urls_1 = urls;
                _b.label = 9;
            case 9:
                if (!(_i < urls_1.length)) return [3 /*break*/, 12];
                url_1 = urls_1[_i];
                return [4 /*yield*/, parseSitemap(url_1)];
            case 10:
                _b.sent();
                _b.label = 11;
            case 11:
                _i++;
                return [3 /*break*/, 9];
            case 12: return [3 /*break*/, 17];
            case 13:
                if (!isSitemap) return [3 /*break*/, 17];
                urls = data['urlset']['url'].map(function (el) { return el['loc']; });
                if (options.maxPerSitemap > -1) {
                    urls = urls.slice(0, options.maxPerSitemap);
                }
                _a = 0, urls_2 = urls;
                _b.label = 14;
            case 14:
                if (!(_a < urls_2.length)) return [3 /*break*/, 17];
                url_2 = urls_2[_a];
                return [4 /*yield*/, headUrl(url_2)];
            case 15:
                _b.sent();
                _b.label = 16;
            case 16:
                _a++;
                return [3 /*break*/, 14];
            case 17: return [2 /*return*/];
        }
    });
}); };
(function () { return __awaiter(_this, void 0, void 0, function () {
    var url;
    return __generator(this, function (_a) {
        url = options._[0];
        parseSitemap(url);
        return [2 /*return*/];
    });
}); })();

Anda dapat melanjutkan dengan membuat file dengan nama .editorconfig, .gitignore, main.ts, package.json, tsconfig.json.
root@ns3:/var/FreeBSD_sitemap_checker/build # cd ..
root@ns3:/var/FreeBSD_sitemap_checker # touch .editorconfig .gitignore main.ts package.json tsconfig.json
Dalam file "/var/FreeBSD_sitemap_checker/.editorconfig" Anda, ketik skrip di bawah ini.

root = true

[*]
charset = utf-8
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,ts}]
indent_style = space
indent_size = 2

[**.jsx]
indent_style = space
indent_size = 2
quote_type = single
space_after_anon_function = true
curly_bracket_next_line = true
brace_style = end-expand

[**.css]
indent_style = space
indent_size = 4

[**.html]
indent_style = space
indent_size = 4
max_char = 78
brace_style = expand

[node_modules/**.js]
codepaint = false

[*.json]
indent_style = space
indent_size = 2

Dalam file "/var/FreeBSD_sitemap_checker/.gitignore" Anda, ketik skrip di bawah ini.

# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/dist
/tmp
/out-tsc

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# IDEs and editors
.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# misc
.sass-cache
connect.lock
typings

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*


# Dependency directories
node_modules/
jspm_packages/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

# Lerna
lerna-debug.log

# System Files
.DS_Store
Thumbs.db

Dalam berkas "/car/FreeBSD sitemap checker/package.json" Anda, ketik skrip di bawah ini.

{
  "devDependencies": {
    "@types/chalk": "^2.2.0",
    "@types/node": "^15.3.0",
    "@types/yargs": "^16.0.1"
  },
  "dependencies": {
    "@types/xml2js": "^0.4.8",
    "axios": "^1.6.7",
    "chalk": "^4.1.1",
    "xml2js": "^0.6.2",
    "yargs": "^17.0.1"
  },
  "name": "sitemap-check",
  "version": "0.0.2",
  "description": "A tool to parse and check sitemap URLs for problems such as broken XML or 404 errors",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\""
  },
  "bin": {
    "sitemap-check": "./build/main.js"
  },
  "files": [
    ".build/*"
  ],
  "keywords": [
    "sitemap",
    "sitemap-check"
  ],
  "author": "Ahmet Kun",
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/unixwinbsd/FreeBSD_sitemap_checker.git"
  },
  "bugs": {
    "url": "https://github.com/unixwinbsd/FreeBSD_sitemap_checker.git/issues"
  },
  "homepage": "https://github.com/unixwinbsd/FreeBSD_sitemap_checker#readme"
}

Dalam file "/var/FreeBSD_sitemap_checker/tsconfig.json" Anda, ketik skrip di bawah ini.

{
    "compilerOptions": {
      "target": "es5",
      "module": "commonjs",
      "outDir": "build"
    }
  }

Dalam berkas "/car/FreeBSD sitemap checker/main.ts" Anda, ketik skrip di bawah ini.

#!/usr/bin/env node

const chalk = require('chalk');
const axios = require('axios').default;
const parseString = require('xml2js').parseString;
const yargs = require("yargs");

const options = yargs
 .usage("Usage: [options] <URL>")
 .option('t', { alias: 'timeout', describe: "Timeout in seconds for a single URL", type: "number", default: 10 })
 .option('maxPerSitemap', { describe: "Maximum number of URLs to fetch from a single sitemap (default -1: visit all URLs)", type: "number", default: -1 })
 .demandCommand(1)
 .argv;

const log = console.log;
const d = (...args) => {
  log(...args);
};

const dd = (...args) => {
  log(...args);
  process.exit();
};

if (isNaN(options.timeout)) {
  log(`Invalid value for timeout: ${options.timeout}`);
  process.exit(1);
}
if (isNaN(options.maxPerSitemap)) {
  log(`Invalid value for maxPerSitemap: ${options.maxPerSitemap}`);
  process.exit(1);
}
axios.defaults.timeout = options.timeout * 1000;

const parseXml = (xml: string) => {
    return new Promise((resolve, reject) => {
        parseString(xml, {explicitArray: false}, function (err, ok) {
            if (err) return resolve(err);
            return resolve(ok);
        });
    });
};

const isTimeoutError = err => {
  return err.code === 'ECONNABORTED' && err.message.indexOf('timeout')!== -1;
};

const headUrl = async (url: string) => {
  let result = null;
  try {
    result = await axios.head(url);
  } catch (err) {
    result = null;
  }
  const statusOk = result && result.status === 200;
  const statusMsg = statusOk ? chalk.green('200 OK') : chalk.red('HTTP NOT OK');
  log(`URL: ${url} ${statusMsg}`);
};

const parseSitemap = async (url: string) => {
  let result,
    hasTimedOut = false;
  try {
    result = await axios.get(url);
  } catch (err) {
    hasTimedOut = isTimeoutError(err);
    result = null;
  }
  const statusOk = result && result.status === 200;
  const response = result && result.data;
  let data;
  try {
    data = await parseXml(response);
  } catch (err) {
    data = null;
  }
  const isSitemap = data && data['urlset'] && data['urlset']['url'];
  const isSitemapList = data && data['sitemapindex'] && data['sitemapindex']['sitemap'];
  const dataOk = isSitemap || isSitemapList;
  let statusMsg : string;
  if (statusOk) {
    statusMsg = chalk.green('Fetched');
  } else {
    let msg = 'Not Fetched';
    if (hasTimedOut) {
      msg += ' (Timeout)';
    }
    statusMsg = chalk.red(msg);
  }
  let xmlValidMsg = '';
  if (statusOk) {
    if (dataOk) {
      xmlValidMsg = chalk.green('Valid XML');
    } else {
      xmlValidMsg = chalk.red('Invalid XML');
    }
  }
  let type = 'URL';
  if (isSitemapList) {
    type = 'SITEMAP LIST';
  } else if (isSitemap) {
    type = 'SITEMAP';
  }
  type = chalk.blue(type);
  log(`${type}: ${url} ${statusMsg} ${xmlValidMsg}`);
  if (statusOk) {
    if (isSitemapList) {
      const urls = data['sitemapindex']['sitemap'].map(el => el['loc']);
      for (const url of urls) {
        await parseSitemap(url);
      }
    } else if (isSitemap) {
      let urls = data['urlset']['url'].map(el => el['loc']);
      if (options.maxPerSitemap > -1) {
        urls = urls.slice(0, options.maxPerSitemap);
      }
      for (const url of urls) {
        await headUrl(url);
      }
    }
  }
};

(async () => {
  const url = options._[0];
  parseSitemap(url);
})();

Jalankan perintah "npm install" untuk memulai proses instalasi semua file.
root@ns3:/var/FreeBSD_sitemap_checker # npm install sitemap-check --global
After that you can run the application by running the command below.
root@ns3:/var/FreeBSD_sitemap_checker # sitemap-check https://www.unixwinbsd.site/sitemap.xml
Anda dapat melihat hasil pengujian pada gambar di bawah.


Hasil dari FreeBSD Sitemap-checker with NPM


Untuk naskah lengkapnya bisa dilihat di "https://github.com/unixwinbsd/FreeBSD_sitemap_checker.git".

Dengan adanya sitemap, kita akan lebih mudah dalam melakukan teknik SEO. Karena sitemap merupakan bagian penting dari SEO dan kita perlu memastikannya dibuat dengan baik dan valid. Selain itu, sitemap yang valid akan mempercepat proses pengindeksan Google Search Console.
Subscribe on LinkedIn FreeBSD Sitemap XML Checker dengan NPM dan Go Lang

Enclosures Link: FreeBSD Sitemap XML Checker dengan NPM dan Go Lang

Silahkan Berkomentar, Kakak...! Bunda...!

Posting Komentar