- 投稿日:2020-05-26T20:10:40+09:00
Puppeteerのpuppeteerクラス
puppeteerとは
他の記事とかでも書いてあると思いますが、一応説明をしておくと、puppeteerはDevToolsプロトコルを使ってChromiumもしくはChromeを管理する高レベルAPIを提供するNodeライブラリです。
今回はこのpuppeteerが面白そうだったので、このライブラリを調べたり使ったりしたことを残していきたいと思います。今回はpuppeteerクラスをやっていきたいと思います。
puppeteerクラス
このクラスはChromiumインスタンスを立ち上げるためのメソッドを提供してくれます。この辺りは設定云々のところなので実証していくところはないです。
メソッドは
connect
、createBrowserFetcher
、defaultArgs
、executablePath
、launch
の5つ。それぞれ説明していきます。connectメソッド
実際のURLを指定するかWebsocketのURLを指定してブラウザインスタンスにつなげるメソッド。
このメソッドは存在しているChromiumインスタンスにのみに接続します。puppeteer.connect(options) options↓ browserWSEndpoint ?string 接続するブラウザwebsocketエンドポイント。 browserURL ?string 形式がhttp://${host}:${port}である接続するブラウザURL。 ignoreHTTPSErrors boolean ナビゲーション中にHTTPSエラーを無視するかどうかを決められます。デフォルトはfalse。 defaultViewport ?Object さまざまなページのviewportを準備します。デフォルトのviewportは800x600。nullはデフォルトのviewportを無効にします。 width number ピクセルでのページのwidth。 height number ピクセルでのページのheight。 deviceScaleFactor number デバイスの(dprとして考えることができる)スケール係数を指定できます。デフォルトは1。 isMobile boolean メタviewportタグを考慮するかどうかを決めることができます。デフォルトはfalse。 hasTouch boolean viewportがタッチイベントをサポートしている場合に指定することができます。デフォルトはfalse。 isLandscape boolean viewportがランドスケープモードである場合に指定することができます。デフォルトはfalse。 slowMo number 指定されたミリ秒単位でPuppeteerオペレーションを遅くします。 transport ConnectionTransport Puppeteerのカスタムトランスポートオブジェクトを指定することができます。このプロパティは実験的なものです。(2020年6月時点) product string 可能な値はchrome、firefox。デフォルトはchrome。createBrowserFetcherメソッド
ChromiumもしくはFirefoxのダウンロードホストやダウンロードフォルダを設定できるメソッド。
puppeteer.createBrowserFetcher([options]) options↓ host string 使用するダウンロードホスト。デフォルトはhttps://storage.googleapis.com。もしproduct(さっきのconnectメソッドで指定するなど)がfirefoxである場合はデフォルトはhttps://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central。 path string ダウンロードフォルダのパス。デフォルトは<root>/.local-chromiumで、<root>はpuppeteerのパッケージルート(大体の場合はnode_modules内のpuppeteerフォルダになってる)。もしproductがfirefoxの場合、デフォルトは<root>/.local-firefox。 platform <"linux"|"mac"|"win32"|"win64"> 現在のプラットフォーム。可能な値はmac、win32、win64、linux。デフォルトは現在のプラットフォーム。 product <"chrome"|"firefox"> 起動するためのproduct。可能な値はchrome、firefox。デフォルトはchrome。defaultArgsメソッド
ブラウザを起動させるときの初期引数を設定するメソッド。
puppeteer.defaultArgs([options]) options↓ headless boolean headlessモードでブラウザを起動するかどうかを設定することができます。デフォルトはdevtoolオプションがtrueである限りはtrue。 args Array<string> ブラウザインスタンスに渡すために追加の引数を設定することができます。Chromiumフラグは参考文献で参照してください。 userDataDir string ユーザーデータディレクトリのパス。 devtools boolean 様々なタブのDevToolパネルを自動でオープンするかどうかを決めることができます。もしこのオプションがtrueなら、headlessオプションはfalseになります。executablePathメソッド
Puppeteerがバンドルされたブラウザを見つけるために期待するパスを取得するメソッド。
launchメソッド
基本的に
connect
メソッドとほとんど変わらないですが、connect
メソッドよりすこしできることが多くなってます。このメソッドはChromiumインスタンスを起動した後に接続をします。puppeteer.launch([options]) options↓ product string 起動するブラウザ。現時点だと、この値はchromeもしくはfirefoxのどちらか。 ignoreHTTPSErrors boolean ナビゲーション中にHTTPSエラーを無視するかどうかを決めることができます。デフォルトはfalse。 headless boolean headlessモードでブラウザを起動するかどうかを設定することができます。デフォルトはdevtoolオプションはtrueである限りはtrue。 executablePath string バンドルされたChromiumの代わりの実行可能なブラウザのパス。もしexecutablePathが相対パスなら、現在の作業ディレクトリを基準にして解決されます。注意:PuppeteerはバンドルされているChromiumでの動作のみが保証されていて、この設定は自己責任での使用です。 slowMo number 指定されたミリ秒単位でPuppeteerオペレーションを遅くします。 defaultViewport ?Object さまざまなページのviewportを準備します。デフォルトのviewportは800x600。nullはデフォルトのviewportを無効にします。 width number ピクセルでのページのwidth。 height number ピクセルでのページのheight。 deviceScaleFactor number デバイスの(dprとして考えることができる)スケール係数を指定できます。デフォルトは1。 isMobile boolean メタviewportタグを考慮するかどうかを決めることができます。デフォルトはfalse。 hasTouch boolean viewportがタッチイベントをサポートしている場合に指定することができます。デフォルトはfalse。 isLandscape boolean viewportがランドスケープモードである場合に指定することができます。デフォルトはfalse。 args Array<string> ブラウザインスタンスに渡すために追加の引数を設定することができます。Chromiumフラグは参考文献で参照してください。 ignoreDefaultArgs boolean|Array<string> もしtrueなら、puppeteer.defaultArgs()を使わないでください。もし配列で定義する場合、指定されたデフォルトの引数を除外します。デフォルトではfalseです。 handleSIGINT boolean Ctrl-Cのブラウザプロセスを閉じます。デフォルトではtrueです。 handleSIGTERM boolean SIGTERMのブラウザプロセスを閉じます。デフォルトではtrueです。 handleSIGHUP boolean SIGHUPのブラウザプロセスを閉じます。デフォルトではtrueです。 timeout number ブラウザインスタンスの起動を待機する最大時間(ミリ秒)。デフォルトは30000(30秒)。タイムアウトを無効にするには、値を0にすること。 dumpio boolean process.stdoutとprocess.stderr内のブラウザプロセスのstdoutとstderrをパイプするかどうかを設定します。デフォルトではfalseです。 userDataDir string ユーザーデータディレクトリのパス。 env Object ブラウザに見ることができる環境変数を指定します。デフォルトではprocess.env。 devtools boolean 様々なタブのDevToolパネルを自動でオープンするかどうかを決めることができます。もしこのオプションがtrueなら、headlessオプションはfalseになります。 pipe boolean WebSocketの代わりのパイプを介してブラウザと接続します。デフォルトではfalseです。 extraPrefsFirefox Object Firefoxに渡すことができる追加のパフォーマンスを設定できます。さいご
次の記事ではBrowserFetcherクラスをやっていきます。おそらく実証なんかもこの辺からだと思います。
参考文献
devtools protocol -- https://chromedevtools.github.io/devtools-protocol/
メタデータエンドポイント -- https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
Getting Started with Headless Chrome(日本語はバージョンが古い) -- https://developers.google.com/web/updates/2017/04/headless-chrome
Chromiumフラグ -- https://peter.sh/experiments/chromium-command-line-switches/
ユーザーデータディレクトリ -- https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md
- 投稿日:2020-05-26T15:52:24+09:00
【解説しながら】ターミナル上で動作するメモアプリをnodeで作ってみる。Part1
今回の記事は【作成】・【解説】の二部構成になっています。
初学者が理解るように丁寧に解説して行きつつ、完成を目指していきます。
解説は良いから作り方だけ見せてくれやって言う方は、【作成】だけを見ていくことをおすすめします。
細かい説明を知りたい方は【解説】を読んで頂くと良いかと思います。
序盤は解説が多くなりますがご了承ください。
今回は、expressを使わずに実装していきます。? 対象
- nodeを始めたばかりの人・なんとなく触ってみたい人
- ES6.ECMAScriptを基礎的なところまで理解している人
? まずはディレクトリを作成しましょう♪ 【作成】
任意のフォルダに今回はmemoというディレクトリを作ります。
ターミナル% mkdir memo % cd memo % touch app.js上記のコマンドは、メモディレクトリを作成→メモディレクトリを指定→app.jsを作成という流れになってます。
app.jsが動作するか、適当にコードを書いてみたいと思います。
app.jsconsole.log("起動してます")nodeで開くときは
% node app.jsこのように node というコマンドを使って開きます。
しかし、コレだとコードを更新するたびにコマンドを入力しないといけないので、非常に面倒です。
後ほど紹介しますが、nodemonというnpmを使用していきたいと思います。? require関数を使ってみる 【解説】
requireは直訳すると、「必要とする」という意味になります。
この関数は外部ファイルを呼び出すための関数で、nodeファイルの中で自由に使えるようになります。
呼び出すファイルのことを、「モジュール」や「パッケージ」などと呼ぶこともあります。require関数が呼び出せる対象は
1. コアモジュール、ビルトインモジュール(nodeをインストールした時点で自動的に使えるようになっているツール群のこと)
2. 独自に作成したオリジナルファイル(ディレクトリに自分で作ったファイルとか)
3. npmパッケージ(npmで取得してインストールして呼び出す)
この3つが主に呼び出せるものとなります。require関数には、ファイルパス、モジュール名、パッケージ名などを文字列として渡します。
コアモジュール公式
公式ドキュメントは
https://nodejs.org/api/documentation.html
こちらになります。全部英語なので、得意な人は読んでみても良いかもしれません。私は一ミリも読めません。勉強します!? コアモジュールfsを使う 【解説】
今回はfsというコアモジュールを使っていきます。file sytemの頭文字をとってfsだと思います。
また、今回はappendFileというメソッドも使ってみましょう。
appendFileは、指定したファイルが無ければ、ファイルを作成し、次に情報を追加します。app.jsconst fs = require('fs'); //fsを使えるようにrequireする fs.appendFile("greeting.txt","Hello,world",function(err){ //greeting.txtがなければ作成、そのファイルの中にHello,worldという情報を入れる。 if(err){ console.log(err); } });エラーが起こった場合のif文を書いていますがそこはあまり気にしなくていいです。
実行してみましょう。ターミナル% node app.js画面は前回同様に、起動していますよ という文字が出ています。
ではどこに変化が出ているのでしょうか?
エディタを見てみます。
このように、greething.txtファイルができており、中にはHello,worldの文字列が格納されています。
再度、ターミナル% node app.jsと行うと、
このように、新しいファイルはつくられず、文字列だけが追加されているのがわかります。
簡単な記述で、ファイルの作成や情報の追加が出来ることがわかったと思います。?コアモジュールosを使ってみる【解説】
os(オペレーティングシステム)のコアモジュールを使って機能を追加してみます。
パソコンのシステムの基本的な操作や情報取得を行うオブジェクトです。
今回は、
os.userinfo()
というメソッドを使います。
文字通りuserの情報を入手するのが目的です。app.jsconst fs = require('fs'); const os = require('os'); //fs同様 osをrequireする。 let user = os.userInfo(); //user変数に、os.userInfo()というuserの情報を入れる。 console.log(user);ではプログラムを実行してみましょう。
このように、自身のPCの情報などが取得できたかと思います。では実際にosプロパティを使ってみましょう。
先程fsで記入したコードを活用します。app.jsfs.appendFile("greeting.txt","こんにちは!"+ user.username +"さん!ようこそ",function(err){ if(err){ console.log(err); } });node app.jsで実行してみましょう。
すると、
このように、さきほどusernameに入っていた情報が出力されます。オリジナルファイルを扱ってみる【解説】
自身で作成したファイルをrequireさせるにはどうしたら良いでしょうか?
適当にファイルを作ってみます。今回はcontents.jsを作成しました。
その中に、console.log("contentsが稼働しております。")など適当なメッセージログを書いて保存してください。では、requireしてみましょう。
app.js// 省略 constの下に書いてください require("./contents.js"); //引数として渡すのは、モジュール名ではなく、相対パスになります。./は忘れずに書きましょう。保存してnode app.jsで立ち上げると、ターミナル上に、contents.jsで記入したコードが出力されているはずです。
ただ、このやり方は別ファイルの処理を行うだけです。
では、contens.js内で宣言したものをapp.jsで使うにはどうしたら良いでしょうか?
それには、moduleというものを使います。
moduleオブジェクトはrequireと同じようにnodeにおいてグローバルなもので、どこでも使える物となっています。moduleを使う上で、中身を知る必要性があるので、contents.jsにて
contents.jsconsole.log(module);そして、ターミナルでapp.jsを立ち上げてください。
注目してほしいのが、exports:{}という部分になります。
このexportsに付属するものとして定義することで他のファイルから呼び出せるようになります。では、先程書いたconsole.log(module)は削除して、情報をcontens.jsの中に身長の情報定義していきたいと思います。
contents.jsmodule.exports.height = 178;app.jsconst contents = require("./contents.js");//先程requireしたcontents.jsを変数化してあげる。 fs.appendFile("greeting.txt","こんにちは!"+ user.username +"さん!あなたの身長は"+ contents.height +"cmです。"以下コード割愛 //このように、既存のコードに追加してnode app.jsを行ってください。すると、greeting.txtに、こんにちは!〇〇さん!あなたの身長は178cmです。というように出力されていると思います。
関数の場合も同じです。
contents.jsmodule.exports.addNote =(){ console.log("addNote"); return "new note";app.jslet result = contents.addNote(); console.log(result);実行すると、コンソール上にaddNote new note と出力されていることが確認できます。
以上が、require関数による外部ファイルの処理、module.exportsによるファイルの外部化と呼び出しについての解説になります。
? npm init(初期化) install について【作成】
npm initを入力することでnodeに欠かせないnpmパッケージが利用できるようになります。
ターミナルにて% npm initこれは、アプリケーションの初期設定となります。gitに上げるときはgit repositoryに記入したりしてください。
今回は、ここの説明は省略します。とりあえず、入力したら何も考えずに連打してOKです。
すると、ディレクトリにpackage.jsonができています。
中をのぞくと先程ターミナル上で聞かれた内容が書いてあると思います。これでnpmパッケージをインストールする準備ができました。
npmパッケージは2種類のインストール方法が存在します。
1つ目はターミナルから入力していきます。ターミナル% npm install パッケージ名 --saveこうするとpackage.jsonの
"description": "",この中にnpmパッケージが入力されます。
2つ目は、上記のパッケージが格納される場所に直接書くことでインストールできます。
expressを入れてみましょう。(実際は入れなくていいです。)package.json"description": { "express":"*" // "*"は最新版という意味です。 }このようにして、npmパッケージを導入してきます。
nodemon導入【作成】
コレまでの解説を見てきて、
% node app.jsこれを毎回打つのが凄いめんどくさいなと思いませんでしたか?
コードに変更を加えたら自動で更新してくれればいいのに、というニーズを叶えてくれるのが
nodemonというnpmになります。nodeで開発を行う上で必須のnpmとなりますので、今回はPC自体にインストールしたいと思います。
sudo npm install nodemon -g -gはグローバルという意味でパソコン自体にインストールするということです。すると、passwordを聞かれますので、ご自身のPCのパスワードを入力してください。
インストールができたら早速nodemonでファイルを起動してみましょう。
% nodemon app.jsでは、app.jsのconsole.logの文字を適当に変更してみてください。
ターミナル上で自動的に再読み込みされているのがわかると思います!長くなりそうなので、今回は以上となります!
今回は、ほとんど説明ばかりになってしまいました、申し訳ありません。次回のための準備【作成】
app.jsconsole.log("app.js起動中"); const = require("fs"); const contents = require("./contents.js");contents.jsconsole.log("contents.js起動中");こんな感じに、jsファイルの余分なコードを削除した状態から始めます。
? 次回予告
今回の内容を踏まえた上で
次回から本格的にメモアプリを作って行きたいと思います。
- 投稿日:2020-05-26T15:37:47+09:00
Node.jsで簡易サーバをつくる
install
$ sudo apt install nodejs npm# 実行 $ node demo.jswebserver using http module
Node.jsはモジュールをrequire()で呼び出す
createServer() メソッドを使ってWebサーバーを構築する
最後にlisten()でポート番号を指定すれば「localhost:8080」にブラウザからアクセスする
createServer()の中身は、最低限の記述としてヘッダー情報とコンテンツを次のように記述する
writeHead()は、responseオブジェクトのメソッドで、ヘッダー情報をレスポンスに書き出す。第1引数にはステータスコードを指定し、第2引数にヘッダー情報を連想配列でまとめたものを指定する。
var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200,{'Content-Type': 'text/html; charset=utf-8'}); response.end('<h1><span id="hello">Hello World</span></h1>'); }) server.listen(8080);htmlを表示するサーバ構築
- Node.jsでファイルを扱うためのfsモジュールを使って「index.html」を読み込む
- これを変数htmlに格納し、end()の引数に設定することでブラウザに表示できる
var http = require('http'); var html = require('fs').readFileSync('views/index.html'); var server = http.createServer(function(request,response){ response.writeHead(200,{'Content-Type':'text/html'}); response.end(html); }) server.listen(8080);Expressによるサーバ構築
var express = require('express'); var app = express();createServer()の引数に先ほど作成したExpressのサーバーオブジェクトを設定する。
var server = require('http').createServer(app); app.get("/", function (request, response) { response.sendFile(__dirname + '/views/index.html'); }); server.listen(8000);GETを受信する
ブラウザからWebサイトにアクセスする時はGET通信でサーバーへリクエストを自動的に送信する。
フォームなどのデータを送信する場合はPOST通信で送る。
サーバーに来るリクエストがGET通信であるかどうかを判断するには次のように記述する。
http.createServer(function(request,response){ response.writeHead(200,{'Content-Type':'text/html; charset=utf-8'}); if(request.method == 'GET'){ //処理 } })「request.method」には、サーバーへ送られたリクエストの種類が格納される。
POSTを受信する
ブラウザからWebサイトにアクセスする時はGET通信でサーバーへリクエストを自動的に送信する。
フォームなどのデータを送信する場合はPOST通信で送る。
http.createServer(function(request, response) { response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'}); if(request.method == 'POST'){ var postData = ''; request.on('data', function(chunk){ postData += chunk; }).on('end',function(){ response.end('あなたが送信したのは'+postData); }) } })POSTの場合は何らかのデータが送信されているのが普通なので、このデータを受けとる処理が必要である。
request.on() の中で関数を記述し、その引数である「chunk」に送信されたデータが格納される。
続けて、on('end')イベント処理内で取得したデータを画面に表示させる。
on というメソッドは、指定のイベント処理を組み込むためのもので、第一引数にイベント名を、第2引数に組み込む処理(関数)をそれぞれ指定する。
var http = require('http'); var server = http.createServer(); server.on('request', doRequest); server.listen(process.env.PORT, process.env.IP); function doRequest(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('Hello World\n'); res.end(); }requestというイベントにdoRequestという関数を割り当てる。
requestというのは、Serverオブジェクトがクライアントからのリクエストを受け取ったときに発生するイベントで「ブラウザからサーバーにアクセスした時のサーバー側の処理」を組み込む。
- 投稿日:2020-05-26T00:38:59+09:00
たぶん10分で試せる。Azure Static Web AppにWebサイトをデプロイして独自ドメイン設定とFunctionsでAPI公開まで
AzureにStatic Web AppsというJAMstack向けなサービスが登場した模様で、プレビュー段階だけど試せたのでメモ残しておきます。
無料らしい(大事)
NetlifyやVercel同様に静的ホスティングだけじゃなく、Functionsも利用できるのが良いですね。
ドキュメントにGitHub Actionsと連携して〜みたいなことが書いててなんでだろう的なこと思ったけどそういえば買収されてましたね(忘れがち)
作るもの: 静的サイト & API
AzureのStatic Web ApssにVue.jsで作った簡単なアプリをデプロイします。(いつまで置いてるか分からないのでキャプチャも貼っておきます)
実際にデプロイした静的サイト
URL: https://www.suikousaibai.ga/
実際にデプロイしたAPIエンドポイント
URL: https://www.suikousaibai.ga/api/hoge
手順1. GitHubでリポジトリ&index.htmlを作成
GitHubで新規にリポジトリ作成します。名前はなんでも良いですが、今回は
staticwebapp-vue-sample
という名前にしました。
create a new file
を選択します。
index.html
を作成します。内容はなんでも大丈夫ですがコードは以下の記事のものを利用しました。リポジトリの完成です。
https://github.com/n0bisuke/staticwebapp-vue-sample/tree/master
手順2. Azureのポータルでアプリを作成
新規作成でStatic Web Appを検索して選択。
作成を押します。
サブスクリプションや、リソースグループ、アプリ名などを入力ます。
ここでGitHubアカウントとの連携が必須みたいです。エラーが出ました。
GitHubアカウントでサインインし、GitHubと連携させます。
先ほど作成したリポジトリを選択し、作成を進めます。
確認画面が出るので作成します。
しばらく経つとデプロイが完了します。
リソースに移動すると公開されたURLが表示されるのでアクセスすればOKです。
手順3: Freenomで無料独自ドメイン
Freenomに関しては前に書いた記事も参考に。
ドメイン取得
Freenomでドメインを取得します。
今回は
suikousaibai.ga
というドメインを取得しました。CNAMEの情報を確認
AzureのStatic Web Appの管理画面で、カスタムドメイン>追加を選択します。
- 名前: www
- 種類: CNAME
- 値: 自身のアプリのURL
が表示されます。この情報をもとにfreenomのDNSを設定します。
FreenomのDNS設定
Freenom側で、
Manage Freenom DNS
の画面にいきます。先程のAzure側で見た情報を設定し、
Save Changes
で保存します。数分待つ
しばらく待ちます。数分... (長いと48時間かかる場合もあるらしい)
Azureの管理画面で検証
Azureの管理画面に戻り、ドメインを入力し、検証を押します。
www.suikousaibai.ga
という形でwwwを入れたドメインの設定でした。他にもやり方あるみたいですがドキュメントを見てみましょう。ちなみに プレビュー期間中は、頂点ドメインの登録はサポートされません。 とドキュメントに書いてあって、
suikousaibai.ga
だと現時点では登録できないっぽいですね。検証に成功しました。と出たら追加ボタンを押しましょう。
これで静的サイトのデプロイ+カスタムドメイン設定が完了しました。
静的ホスティングのみの場合はここまでで十分だと思います。
手順4: APIフォルダを作成することでAPIが作れる
(ここの手順はVercelと同じ雰囲気でした。)
先ほど作成したGitHubリポジトリはローカルにcloneしておきましょう。
今回は
https://ドメイン/api/hoge
にアクセスするとjsonが返ってくるHOGE APIを作成します。APIというフォルダを作成し、その中にAPIのエンドポイントとなる名前でフォルダを作成します。今回はhogeフォルダです。
さらにそのフォルダの中に
index.js
とfunction.json
を作成します。index.jsmodule.exports = async function (context, req) { context.res = { body: { text: "Hello from the API" } }; };
function.json
は"route": "hoge"
の箇所を自身で設定した名前にしましょう。function.json{ "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get" ], "route": "hoge" }, { "type": "http", "direction": "out", "name": "res" } ] }これでpushすればOKです。
Vercelもapiフォルダを作成してその中にAPI作成をしていくので似ている感じがしました。
↓成功すると管理画面の関数(functions)の箇所にAPIが追加されます。
エンドポイントにアクセスするとindex.jsで記載した内容が表示されると思います。
更新時
更新する場合はGitHubのリポジトリを編集してPushしていくやり方です。
所感
個人的にはPaaS未満の使い方が最近好きなので割と嬉しい。
Functions使うとお金は別途かかるのかドキュメントも必要最低限はそろってそうな印象でした。
もっと色々やれそうな雰囲気あるのでこの辺好きな人は調べていきたいですね。