Life is Like a Boat

忘備録や経済、投資、プログラミングに関するメモやtipsなど

Yahoo Financeのmyポートフォリオから銘柄コードをスクレイピングする

Yahooファイナンスポートフォリオ機能を使って過去取引した銘柄やWatch銘柄を管理しています。

YFでは1pfあたり管理できる銘柄数が最大50なので、監視銘柄が増えるほど新規に作らないといけません。

私は、例えば四季報を読んで、気になる銘柄をNotepadやiPhoneでメモして、"四季報18年春_1"みたいなポートフォリオを作って管理するやり方をしています。

これだとポートフォリオ自体の数が増えると、いざ分析でコードだけキーに使いたい時に、いちいちコピペしていくのがかなり面倒です。(私の場合、直近だと15pfあります)、

そこで、Nightmare.jsを使い、ユーザの全ポートフォリオから一括で銘柄コードを取得するjavascriptを書きました。

  1. 適当にfolderを作って下記のソースからpackage.jsonを作成
  2. そのfolder下で.evn.jsonを作成。YahooのログインID、パスワードを書く
  3. npm install
  4. node run.js false してやれば、スクレイピング結果を反映したdata.jsonが作成されるはずです。


//run.js
var env = require('gulp-env');
var Nightmare = require('nightmare');
var vo = require('vo');
const {promisify} = require('util');
var fs = require("fs");
const writeFileAsync = promisify(fs.writeFile);

const FAKE_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/41.0.2228.0 Safari/537.36';
const YAHOO_FINANCE_URL = 'http://finance.yahoo.co.jp/'
const JSON_FILE = './data.json'

env({
    file: './.env.json'
});

let nightmare = Nightmare({show: true});

const YahooFinanceLogin = (nightmare) => {
    return nightmare
        .useragent(FAKE_USER_AGENT)
        .goto(YAHOO_FINANCE_URL)
        .click('ul.portFolioIn li.help a')
        .wait('div#idWrap')
        .type('input#username', process.env.USER_ID)
        .click('button#btnNext')
        .wait(2000)
        .type('input#passwd', process.env.PASSWORD)
        .wait(1000)
        .click('#btnSubmit')
        .wait(3000)
        .wait('span.portFolio')
}

const getIdxOfPortfolio = (nightmare, portFolioName) => {
    return nightmare.evaluate((portFolioName) => {
        return Array.from(document.querySelectorAll('ul.portFolioIn > li')).map((e) => {
            return e.textContent
        }).indexOf(portFolioName)
    }, portFolioName).then((idx) => {
        return idx
    });
}

const getListOfPortfolios = (nightmare) => {
    return nightmare.wait('ul.portFolioIn').evaluate(() => {
        return Array.from(document.querySelectorAll('ul.portFolioIn > li')).map((e, idx) => {
            return {'name': e.textContent, 'idx': idx}
        });
    })
}

const getSharesFromPortfolio = (nightmare, idxOfPortfolio) => {
    return nightmare
        .click('ul.portFolioIn > li:nth-child(' + idxOfPortfolio + ') a')
        .wait('table.smallText')
        .wait(500)
        .evaluate(() => {
            return Array.from(document.querySelectorAll('div.pfListView table tbody#tbotyPortfolioList > tr > td:nth-child(2)')).map((e) => {
                return e.innerText.replace('\n', '')
            });
        })
}

const writeToJsonFile = (o) => {
    return writeFileAsync(JSON_FILE, JSON.stringify(o), (err) => {
        if (err) {
            console.error(err);
            return;
        };
        console.log("File has been created");
    });
}


vo(function* () {
    const testRun = process.argv[process.argv.length-1];;
    let nightmare = Nightmare({show: false})
    yield YahooFinanceLogin(nightmare);     //Login
    let code = '';
    let jsonObj = [];
    if (testRun) {
        code = yield getSharesFromPortfolio(nightmare, 1)
    } else {
        let listOfPortfolios = yield getListOfPortfolios(nightmare);
        for (var i = 0, len = listOfPortfolios.length; i < len; i++) {
            let codes = yield getSharesFromPortfolio(nightmare, listOfPortfolios[i].idx + 1)
            console.log('-----')
            console.log(listOfPortfolios[i].name);
            console.log('-----')
            var t = {'name': listOfPortfolios[i].name, 'code': codes}
            jsonObj.push(t);
        }
        yield writeToJsonFile(jsonObj);
    }

    yield nightmare.end();
    if (testRun) {
        return code
    } else {
        return jsonObj
    }

})((err, result) => {
    if (err) return console.log(err);
    console.log(result);
});
//package.json
{
  "name": "yahoofinancenightmare",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "testRun": "node run.js true",
    "prd": "node run.js false"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "argv": "0.0.2",
    "csv-write-stream": "^2.0.0",
    "fs": "0.0.1-security",
    "gulp-env": "^0.4.0",
    "nightmare": "^2.10.0",
    "vo": "^4.0.2"
  }
}
//.env.json
{
  "USER_ID": "YOUR_USER_ID",
  "PASSWORD": "YOUR_PASSWORD"
}