🕶️

よく使うのに毎回書いてるnode.jsのスクレイピングをいい加減テンプレ化した

2020/11/28に公開

node.jsのスクレイピングをテンプレ化した

使っているもの

目的

node.jsでスクレイピングするのに一番直感的に書きやすいのでcheerioを選択。
今回は某エンジニア案件のサイトの投稿をぶん回して
マッチした案件をメールで受信するために使用。

プロジェクト作る

yarn init -y

依存関係

yarn add cheerio nodemailer request-promise

もしくはCloneする

git clone git@github.com:abalol/node-scraping-template.git

package.json

{
    "name": "node-scraping-template",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "mail": "node index.js mail",
        "text": "node index.js text",
        "serve": "node index.js mail 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "cheerio": "^1.0.0-rc.3",
        "nodemailer": "^6.4.16",
        "request": "^2.88.2",
        "request-promise": "^4.2.6",
        "sendmail": "^1.6.1"
    }
}

index.js


const cheerio = require('cheerio');
const fs = require("fs");
const nodemailer = require('nodemailer');
const rp = require('request-promise');

/**
 * 出力先を設定します。true:ファイル false:メール
 * @type {boolean}
 */
const isMakeFile = process.argv[2] === 'text';

/**
 * 繰り返し処理のインターバルを時間単位で指定します
 * 未設定時は1時間置き
 * @type {Number}
 */
const interval = !process.argv[3] ? null : Number(process.argv[3]);

// 複数ページ取得
const promises = [...Array(3)].map((_, i) => {
    return `ここにURL?page=${i + 1}`
}).map(async(url) => {
    const $ = await rp.get(url, {
        transform: (body) => {
            return cheerio.load(body);
        }
    });
    return $('.title').map((i, el) => {
        return `ここで適宜中身をパース`;
    }).get().join(' ');
});

const getNewPosts = async() => {
    await Promise.all(promises).then((result) => {
        if (isMakeFile) {
            const fileName = `${getCurrentTime}_list.tsv`;
            if (isMakeFile && fs.existsSync(fileName)) fs.unlinkSync(fileName);
            fs.writeFile(fileName, result.flat().join('\n'), {
                flag: 'wx'
            }, (err) => {
                if (err) throw err;
                console.log(`${getCurrentTime()}出力`);
            });
        } else {
            // TODO: GMailの送信はセキュリティ弱くなるので非推奨
            const smtpConfig = {
                host: 'smtp.gmail.com',
                port: 465,
                secure: true,
                auth: {
                    user: 'あなたのGMailアカウント',
                    pass: 'GMailのパスワード'
                }
            };
            const transporter = nodemailer.createTransport(smtpConfig);
            transporter.sendMail({
                from: '送信元アドレス',
                to: '送信先アドレス',
                subject: `タイトル ${getCurrentTime()}`,
                text: result.flat().join('\n\n'),
            }, (err, reply) => {
                if (err) console.log(err && err.stack);
                console.dir(reply);
            });
        }
    });
}

// 一回実行 or 繰り返し実行
if (!interval) {
    getNewPosts()
} else {
    // 開始時即時実行
    getNewPosts()
    setInterval(getNewPosts, 1000 * 60 * 60 * interval);
}

const getCurrentTime = () => {
    const n = new Date();
    return `${n.getFullYear()}/${pz(n.getMonth() + 1)}/${pz(n.getDate())} ${pz(n.getHours())}/${pz(n.getMinutes())}`;
}

const pz = (num) => {
    return result = num < 10 ? `${0}${num}` : num;
}

Setup

  • メール送信時はsmtpConfigsendMailを適宜修正する
  • package.jsonの引数で繰り返し時のインターバルの設定を行える

常駐して1時間置きにメール送信させる

yarn run serve

1回実行してローカルに.tsvを作成する

yarn run text

Spreadsheetに送信もそのうち。

Discussion