IMUZA.com

Xserver<<WordPress(ConoHa)<<はてなブログ

ホーム / javascript / Filmarks の自分の投稿へ飛ぶ疑似ソーシャルボタン

Filmarks の自分の投稿へ飛ぶ疑似ソーシャルボタン

2020/09/27 javascript, Node.js

映画のレビューを書いている別サイト「そんなには褒めないよ。映画評」の各記事から Filmarks の自分の投稿ページに飛ぶリンク、疑似ソーシャルボタンをつくります。

前記事:Node.js でスクレイピングしてクライアントに返す

  • クリックからページ表示までの流れ
  • クライアントサイド
    • HTML(Filmarksボタン)
    • Javascript(openFilmarks)
  • サーバーサイド
  • プログラムのポイント
    • オリジン間リソース共有 (CORS)
    • 非同期処理 Fetch API
    • Nodejs 無料ホスティング

クリックからページ表示までの流れ

  1. Filmarks ボタンをクリックすると関数 openFilmarks を呼ぶ
  2. openFilmarks
    1. ページの title タグから映画タイトルを取得する
    2. filmarks-window 名のサブウィンドウを開いてローディング画像を表示しておく
    3. Filmarks のユーザー名と映画タイトルを Nodejs サーバーに送りレスポンスを待つ
  3. Nodejs サーバー
    1. Filmarks のユーザーページをリクエストする
    2. ユーザーページから最大ページ数を取得する
    3. ページ数分ループさせて各ユーザーページをリクエストする
    4. 各ページ36タイトルを取得しクライアントから送られた映画タイトルと比較する
    5. 合致するタイトルであれば変数 url に投稿ページの URL を代入する
    6. 全ページの照合が終了し、url が空であれば no mark を代入する
    7. url をクライアントに返す
  4. openFilmarks
    1. 返ってきた値が Filmarks の投稿ページ形式の URL であればサブウィンドウを URL 遷移させる
    2. 返ってきた値が no marks であれば、サブウィンドウを閉じて投稿がない旨アラートする

クライアントサイド

HTML(Filmarksボタン)

<!-- filmarks -->
<button type="button" class="filmarks" onclick="javascript:openFilmarks(); return false;">
    <img alt="Filmarks" src="https://d2ueuvlup6lbue.cloudfront.net/assets/pc/project/logo_brand-c14549a90b4abe0a29f4be8b0c5f29f6700c595656d0e3d03dfc7a993d91a4ee.svg">
</button>

ロゴの使用には許可が必要です。

Javascript(openFilmarks)

function openFilmarks(){


  const srv = 'http://localhost:8080'; // テスト用のローカルサーバー
  const user = 'ausnichts'; // Filmarks のユーザー名
  const title = document.title.match(/^「(.+)」.+$/); // 映画タイトル名を取り出す
    
  const url = new URL(srv);
  const params = { user: user, movie: title[1] };
  url.search = new URLSearchParams(params);


  // サブウィンドウを開きローディング画像を表示
  const windowFilmarks = window.open('', 'filmarks-window');
  windowFilmarks.document.write('<html><head><title>Now loading...</title></head>');
  windowFilmarks.document.write('<body>');
  windowFilmarks.document.write('<div style="display: flex; justify-content: center; align-items: center; height: 100%;">');
  windowFilmarks.document.write('<img src="ローディングイメージ">');
  windowFilmarks.document.write('</div>');
  windowFilmarks.document.write('</body></html>');


  fetch(url.toString(), {
    mode: 'cors'
  })
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.text();
    })
  .then(result => {
    const regex = /^https:\/\/filmarks.com\/movies\/\d+\/reviews\/\d+/;
    const found = result.match(regex);
    if(found !== null){
      windowFilmarks.location.href = result;
    }else{
      windowFilmarks.close();
      let intervalId = setInterval(function(){
        if(windowFilmarks.closed){
          clearInterval(intervalId);
          alert('まだこの映画のレビューはありません');
        }
      },10);
    }
  })
  .catch(error => {
    console.error('There has been a problem with your fetch operation:', error);
  });
}

サーバーサイド

const http = require('http');
const server = http.createServer();
const client = require('cheerio-httpcli');
const urlParser = require('url');


const filmarksUrl = 'https://filmarks.com/users/';


server.on('request', function(req, res){
    
  if (req.url === '/favicon.ico'){
    res.end();
  }else{
    const user = urlParser.parse(req.url, true).query.user;
    const movie = urlParser.parse(req.url, true).query.movie;
    const myPageUrl = filmarksUrl + encodeURI(user);


    client.fetch(myPageUrl)
      .then((result) => {
        const href = result.$('a.c-pagination__last').attr('href');
        const page = urlParser.parse(href, true).query.page;
        return page;
      })
      .then((page) => {
        let j = 0;
        let url = '';
        for (let i=1; i<=page; i++){
          let targetUrl = myPageUrl + `?page=${i}`;
          client.fetch(targetUrl)
            .then((result) => {
              result.$('h3.c-content-card__title').each(function (idx){
                const title = result.$(this).text();
                if(title.indexOf(movie) !== -1){
                  url = result.$(this).find('a').url();
                  url = url.replace('?mark_id=', '/reviews/');
                }
              });
            })
            .catch((err) => {
              console.log(err);
            })
            .finally(() => {
              j++;
              if (j === Number(page)){
                if (url === '') url = 'no mark';
                res.setHeader('Access-Control-Allow-Origin', 'https://ausnichts.hatenadiary.jp'); // クライアントのオリジン
                res.writeHead(200, {'Content-Type' : 'application/plain'});
                res.write(url);
                res.end();
              }
            });
        }
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        console.log('done');
      });
  }
});


server.listen(process.env.PORT || 8080);
console.log('Server running at http://localhost:8080/');

プログラムのポイント

オリジン間リソース共有 (CORS)

ブラウザから Filmarks のページをリクエストしても CORS エラーが出て取得できません。前記事で説明しています。

  • Node.js でスクレイピングしてクライアントに返す – IMUZA.com

そのため Nodejs サーバーを立て Access-Control-Allow-Origin: クライアントのオリジン を指定してブラウザからのリクエストを受け付けるようにしています。

非同期処理 Fetch API

Filmarks のページ取得に非同期処理の Fetch API を使っていますので全てのページ取得の完了を検知できません。目的のページが取得できた時はそれを返せばいいのですが、そうしますと取得できなかった場合を検知できなくなります。

そのため、正常終了でもエラーでも必ず最後に通る処理である finally で最終処理をしています。finally に到達した回数が総ページ数(ループ回数)と一致すれば全てのページを読み込んだことを検知できます。

Nodejs 無料ホスティング

Nodejs サーバーを立ち上げられるホスティングサービスを探さなくてはいけません。

Heroku は一度試したことがありますが、ググってみましたら Glitch というサービスがヒットしますので一度試してみようかと思います。

glitch.com

次回です。

レベルアップNode.js (技術の泉シリーズ(NextPublishing))

レベルアップNode.js (技術の泉シリーズ(NextPublishing))

  • 作者:佐々木 勝広
  • 発売日: 2020/06/19
  • メディア: Kindle版

Node.js でスクレイピングしてクライアントに返す
無料サービス Glitch で Node.js アプリを立ち上げる
Twitter
Facebook
ブックマーク
LINEで送る

最初のサイドバー

最新記事

2023/02/1

WordPress:期間指定で人気記事を表示(プラグインなし)

2023/01/26

WordPress:メニューのid,classを整理カスタマイズ

2023/01/19

WordPress:JSON-LD構造化データをプラグインなしで出力

2023/01/11

WordPress:OGPタグをプラグインなしで挿入する

2022/12/27

WordPress:canonicalタグをプラグインなしで制御する

最新記事を一覧で見る

よく読まれている記事

よく読まれている記事を一覧で見る

カテゴリー

  • はてなブログ214
  • WebTips108
  • javascript98
  • Joomla!88
  • Windows68
  • CSS63
  • Wordpress60
  • Joomla!更新53
  • Linux49
  • はてなテーマ45
  • Plamo33
  • Google32
  • はてなプラグイン25
  • php22
  • Node.js18
  • Ubuntu16
  • SASS16
  • laravel415
  • Chrome11
  • cms-style10
  • iPhone9
  • genesis6
  • ConoHa WING6
  • Git入門6
  • Python5
  • Android5
  • スマートフォン4
  • PC全般4
  • 静的サイトジェネレーター3
  • Firefox3
  • SSD3
  • Facebook3
  • Blankslate3
  • Docker3
  • Mactype2
  • GitHub2
  • youtube1
  • rails入門1
  • Twitter1
  • はてなブクマ1
  • 映画1
  • Xserver1

Footer

My Web Sites

  • @半径とことこ60分
  • そんなには褒めないよ。映画評
  • IMUZA.com
  • GitHub

Related Sites

  • WordPress公式
  • WordPress関数リファレンス
  • PHPマニュアル

Contact Us

  • お問い合わせフォーム
  • Twitter
  • Facebook
  • Feedly

Copyright © 2023 · IMUZA.com