Skip to content

Instantly share code, notes, and snippets.

@toofusan
Created October 8, 2016 06:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toofusan/3d3a67a9a3c9aa4e45583b9bf77d45f7 to your computer and use it in GitHub Desktop.
Save toofusan/3d3a67a9a3c9aa4e45583b9bf77d45f7 to your computer and use it in GitHub Desktop.
Webサイト内で「あるURLにどのURLからリンクしているか」抽出する
"use strict";
const client = require("cheerio-httpcli");
const URL = require("url");
const fs = require("fs");
// 共通変数
const MAX_LEVEL = 5; // 最大遷移回数
// URL
if (!process.argv[2]) console.log("No argument");
let TARGET_URL = process.argv[2];
let startURL = checkIndex(TARGET_URL);
let savepath = checkDir(TARGET_URL);
// 一時格納
let alreadyList = {}; // すでにクロールしたページ
let refList = {}; // あるページからの遷移先一覧
let refSourceList = {}; // あるページへの遷移元一覧
let alreadySourceList = {}; // すでにリンク元を抽出したページ
let crawlURL = []; // 各遷移回数ごとのクロールURL一覧
crawlURL[0] = [startURL];
// 遷移回数分クローリング
console.log("crawling START")
for(let i=0;i < MAX_LEVEL; i++) {
if(!crawlURL[i]) continue;
console.log("crawlURL[" + i + "]: " + crawlURL[i]);
crawlURL[i+1] = [];
crawlURL[i].forEach(function(val) {
crawl(val, i);
});
}
fs.writeFileSync(savepath + "/linkList.json", JSON.stringify(refList));
console.log("crawl DONE");
// クロール結果から被リンク元抽出
console.log("ref Search START")
Object.keys(refList).forEach(function(source) {
for(val of this[key]) {
refSource(href);
}
}, refList);
fs.writeFileSync(savepath + "/linkSource.json", JSON.stringify(refSourceList));
console.log("ref Search DONE")
// ウェブクロール処理
function crawl(url, level) {
console.log("crawling : " + url);
// exit処理
if (level > MAX_LEVEL) return console.log("Link level over"); // 最大遷移回数で終了
let urlExtention = url.slice(url.length-4, url.length);
if (urlExtention === ".pdf" || urlExtention === ".jpg" || urlExtention === ".png") return console.log("Not HTML"); // HTMLではない場合終了
if (alreadyList[url]) return console.log("Already checked"); // すでにクロールしたページの場合は終了
alreadyList[url] = true;
if (!url.match(TARGET_URL)) return console.log("Different domain"); // ドメインが変わった場合は終了
// 初期化
refList[url] = [];
// ページ内リンク抽出
const fetchResult = client.fetchSync(url);
if (fetchResult.error) return console.log("Fetch Error");
fetchResult.$("a").each(function(idx) {
var href = this.attribs.href;
if(!href || href == "javascript:void(0)" || href == "javascript:void(0);") return true; // リンク設定が無い or javascript呼び出しの場合はスルー
href = checkURL(url, href);
if(href === "") return true;
crawlURL[level+1].push(href); // 次にクロールするURLリストに追加
refList[url].push(href); // クロール中のページからのリンク先一覧に追加
});
refList[url] = Array.from(new Set(refList[url])); // リンク先の重複を削除
}
// リンクURL有効化
function checkURL(url, href) {
href = URL.resolve(url, href); // 相対パスを絶対パスに変更
href = href.replace(/\#.+$/, ""); // 末尾の"#"以降は無視
href = href.replace(/\#$/, "");
href = checkIndex(href);
return href;
}
// 被リンク元URL抽出処理
function refSource(url) {
// exit処理
if (alreadySourceList[url]) return; // すでに抽出したページの場合は終了
alreadySourceList[url] = true;
// 初期化
refSourceList[url] = [];
// リンク元抽出
const keys = Object.keys(refList);
for (let i = 0; i < keys.length; i++) {
if (refList[keys[i]].indexOf(url) >= 0) {
refSourceList[url].push(keys[i]);
}
}
}
// index.htmlをつける
function checkIndex(url) {
if(url.charAt(url.length - 1) == "/") {
return url + "index.html";
} else {
return url;
}
}
// ディレクトリ作成
function checkDir(url) {
let path = "result/" + url.split("/")[2];
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
return path;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment