7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

プロトアウトスタジオAdvent Calendar 2019

Day 16

CAMPFIREのページをモニタリングしてクラウドファンディングの状況をウォッチする - スクレイピング編

Last updated at Posted at 2019-12-17

クラウドファンディングプラットフォームの大手CAMPFIREさんのWebサイトをスクレイピングして、ファンディング中のプロジェクトの現在の進捗や、パトロン数などをウォッチしたいと思います。

今回はスクレイピング編です。

対象とするSPARKSチャンネル

今回はCAMPFIREの中でも、プロトアウトスタジオ x CAMPFIREで現在開催中のSPARKS by BOOSTER STUDIOのチャンネルを対象にスクレイピングしてみます。

Sparks - https://camp-fire.jp/channels/sparks

スクリーンショット 2019-12-18 1.49.15.png

環境など

  • Node.js 13.3.0
  • axios 0.19.0

Node.js 13.3.0で試してみていて、ES Modulesな記述(import)にしてみています。
もし真似しようとしてエラーが出る人は冒頭のimport文をconst axios = require('axios');に書き換えて従来の読み込みにしましょう。

npm init -y
npm i axios

こんな感じで事前に準備はしておきます。

まずは要素の特定

Chromeのディベロッパーツール(右クリック->検証)で各要素の抜き出しをしてみます。

スクリーンショット 2019-12-18 1.48.49.png

何となく、class="box"やdata_project_idの辺りの記述で引っ張ってこれるかもしれないとアタリを付けてみます。

campfire.js
'use strict';

import axios from 'axios';

const CF_URL = `https://camp-fire.jp/channels/sparks`;

axios.get(CF_URL).then(res => {
    const bodyall = res.data;
    let parts = bodyall.split('data_project_id='); // `data_project_id=`の箇所でスプリット
    parts.shift(); //HTML全体の最初を削除
    console.log(parts[0]);
})

この時点でこんなHTMLが取得できます。

"210634"><div class="box-in"><div class="box-thumbnail"><a href="/projects/view/210634?list=channel_sparks"><img class="lazyload" data-srcset="https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=320&amp;h=213&amp;fit=clip&amp;auto=format 320w, https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=414&amp;h=276&amp;fit=clip&amp;auto=format 414w, https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=768&amp;h=512&amp;fit=clip&amp;auto=format 768w, https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=960&amp;h=639&amp;fit=clip&amp;auto=format 960w, https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=1024&amp;h=682&amp;fit=clip&amp;auto=format 1024w" data-sizes="100vw" data-src="https://static.camp-fire.jp/uploads/project_version/image/329602/f8330bbc-b104-437f-a1b0-773052ddd9d6.png?ixlib=rails-2.1.4&amp;w=1120&amp;h=746&amp;fit=clip&amp;auto=format"></a></div><div class="box-title"><a title="EZ-Lapse いつでもどこでも気軽にタイムラプス動画を撮影できるカメラ" href="/projects/view/210634?list=channel_sparks"><h4>EZ-Lapse いつでもどこでも気軽にタイムラプス動画を撮影できるカメラ</h4></a><div class="sub"><p>「いつでもどこでも気軽にタイムラプス動画を。」タイムラプス動画を撮影したことはありますか?確かに素敵な動画が撮れますが、撮影中ずっとスマホが使えず、気軽に撮るこ...</p></div></div><div class="box-date sp-none"><div class="category"><a href="/projects/category/technology"><i class="fa fa-tag"></i> テクノロジー・ガジェット</a></div><div class="ownner"><a href="/profile/takeaship"><i class="fa fa-user"></i> takeaship</a></div></div><div class="meter">
<div class="meter-in"><div class="bar" style="width: 0%;"><span>0%</span></div></div>
<span>0%</span>
</div><div class="overview">
<div class="total" data-js="money-unit">
<small>現在</small>0円</div>
<div class="rest">
<small>パトロン</small>0人</div>
<div class="per">
<small>残り</small>9日</div>
</div></div></div><div class="box  " 

細々と情報を抜き出し

<small>残り</small>9日</div>

9の部分だったり

<small>パトロン</small>0人</div>

0の部分だったりを正規表現で抜き出します。

campfire.js
'use strict';

import axios from 'axios';

const CF_URL = `https://camp-fire.jp/channels/sparks`;

axios.get(CF_URL).then(res => {
    const bodyall = res.data;
    let parts = bodyall.split('data_project_id=');
    parts.shift();

    const part = parts[0]; //0件目

    const project = {};
    project.percentage = part.match(/<span>(.*?)%<\/span>/)[1]; //達成率
    project.yen = part.match(/<\/small>(.*?)円<\/div>/)[1]; //円
    project.patron = part.match(/パトロン<\/small>(.*?)人<\/div>/)[1]; //パトロン数
    project.remaining_days = part.match(/残り<\/small>(.*?)日<\/div>/)[1]; //残り日数
    project.title = part.match(/<a title="(.*?)" href="/)[1]; //タイトル
    project.description = part.match(/<div class="sub"><p>(.*?)...\/p><\/div><\/div>/)[1]; //概要
    project.link = 'https://camp-fire.jp' + part.match(/div class="box-thumbnail"><a href="(.*?)">/)[1]; //リンク

    console.log(project);
})
node campfire.js
(node:2508) ExperimentalWarning: The ESM module loader is experimental.
{
  percentage: '0',
  yen: '0',
  patron: '0',
  remaining_days: '9',
  title: 'EZ-Lapse いつでもどこでも気軽にタイムラプス動画を撮影できるカメラ',
  description: '「いつでもどこでも気軽にタイムラプス動画を。」タイムラプス動画を撮影したことはありますか?確かに素敵な動画が撮れますが、撮影中ずっとスマホが使えず、気軽に撮るこ.',
  link: 'https://camp-fire.jp/projects/view/210634?list=channel_sparks'
}

こんな雰囲気ですね。

あとは複数プロジェクト分処理を回す

campfire.js
'use strict';

import axios from 'axios';

const CF_URL = `https://camp-fire.jp/channels/sparks`;

axios.get(CF_URL).then(res => {
    const bodyall = res.data;
    let parts = bodyall.split('data_project_id=');
    parts.shift();

    for (let i = 0, len = parts.length; i < len; i++) {
        const part = parts[i];
        const project = {};
        project.percentage = part.match(/<span>(.*?)%<\/span>/)[1]; //達成率
        project.yen = part.match(/<\/small>(.*?)円<\/div>/)[1]; //円
        project.patron = part.match(/パトロン<\/small>(.*?)人<\/div>/)[1]; //パトロン数
        project.remaining_days = part.match(/残り<\/small>(.*?)日<\/div>/)[1]; //残り日数
        project.title = part.match(/<a title="(.*?)" href="/)[1]; //タイトル
        project.description = (part.match(/class="sub"><p>(.*?)<\/p>/)) ? (part.match(/class="sub"><p>(.*?)<\/p>/)[1]) : ''; //概要
        project.link = 'https://camp-fire.jp' + part.match(/div class="box-thumbnail"><a href="(.*?)">/)[1]; //リンク
        // project.image = part.match(/class=" lazyloaded" data-srcret="(.*?)">/)[1]; //画像
        console.log(project);      
    }

})
$ node campfire.js

・
・
・
{
  percentage: '56',
  yen: '5,700',
  patron: '7',
  remaining_days: '4',
  title: '【おかたづけ】こどもが自分で片付けしたくなるIoTおもちゃ箱',
  description: 'こどもがおもちゃを散らかしっぱなしにして困っているお母さんお父さん大助かり!おもちゃ箱を電子工作して子供が自分で片付けしたくなります!',
  link: 'https://camp-fire.jp/projects/view/211804?list=channel_sparks'
}
{
  percentage: '10',
  yen: '13,000',
  patron: '11',
  remaining_days: '4',
  title: 'オフィスワーカー向け 座り過ぎを解決するクッション CiliCill シリシル',
  description: '世界一の「座りすぎ大国」日本そんな日本人特有の問題を解決したい!座ってる時間がわかるクッション CiliCill -シリシル-を作りました。一日の中で自分がどの...',
  link: 'https://camp-fire.jp/projects/view/207642?list=channel_sparks'
}

こんな感じでプロジェクトの情報を抜き出せました。

次回

次はこれを定期実行させる&チャット通知させる予定です。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?