フロントエンドデベロッパーのメモ

スキル: HTML/Jade/Jinja2, CSS/SCSS, JavaScript(ES6), Angular, React,Next, Redux, Node, Express, Python, Flask, Postgres, Redis, MongoDB, Kafka, Knex, SQLAlchemy, React Native, EXPO, GraphQL/Apollo, REST, AWS, Heroku, Docker, CircleCI, SCRUM, XP, Vim, TDD

クローラーの写経してみた

前からクローラー作ってみたいなって思ってたけど、なかなか余裕がないし設計アイデアが浮かばなかったからとりあえずググってみたらわかりやすいのが見つかった。 How to make a web crawler in JavaScript / Node.js とりあえず完璧に写経しただけやけど、非常にシンプルで考え方がわかりやすかった。 ここからさらに外部リンクまで検索してくれるようにアップデートしてみたいな。

var request = require("request");
var cheerio = require("cheerio");
var URL = require("url-parse");

var START_URL = "http://www.arstechnica.com";
var SEARCH_WORD = "stemming";
var MAX_PAGES_TO_VISIT = 10;

var pagesVisited = {};
var numPagesVisited = 0;
var pagesToVisit = [];
var url = new URL(START_URL);
var baseUrl = url.protocol + "//" + url.hostname;

pagesToVisit.push(START_URL);
crawl();

function crawl() {
  if (numPagesVisited >= MAX_PAGES_TO_VISIT) {
    console.log("Reached max limit of number of pages to visit.");
    return;
  }
  var nextPage = pagesToVisit.pop();
  if (nextPage in pagesVisited) {
    // We've already visited this page, so repeat the crawl
    console.log("Run the crawler again");
    crawl();
  } else {
    // new page we haven't visited
    console.log("pagesVisited: ", pagesVisited, nextPage);
    visitPage(nextPage, crawl);
  }
}

function visitPage(url, callback) {
  // add page to our set
  pagesVisited[url] = true;
  numPagesVisited++;
  // make the request
  console.log("candidates... ", pagesVisited);

  console.log("Visiting page " + url);
  request(url, function(error, response, body) {
    // check status code (200 is HTTP OK)
    console.log("Status code : " + response.statusCode);
    if (response.statusCode !== 200) {
      callback();
      return;
    }
    // Parse the document body
    var $ = cheerio.load(body);
    var isWordFound = searchForWord($, SEARCH_WORD);
    if (isWordFound) {
      console.log("Word " + SEARCH_WORD + " found at page " + url);
    } else {
      collectInternalLinks($);
      // in this short program, our callback is just calling crawl();
      callback();
    }
  });
}

function searchForWord($, word) {
  var bodyText = $("html > body").text();
  return bodyText.indexOf(word.toLowerCase()) !== -1;
}

// search internal links
function collectInternalLinks($) {
  var relativeLinks = $("a[href^='/']");
  console.log("Found " + relativeLinks.length + " relative links");
  relativeLinks.each(function() {
    pagesToVisit.push(baseUrl + $(this).attr("href"));
  });
}