主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Azure: VPSでサーバからNginxサンプルをサーブする(ポートの開け方)

                
tags:
 Azureの管理コンソールが変更され、ポートの開け方の説明が見つからなかったので、どうにかこうにかやってみたメモ。

 VPSへのOSインストール、Nginxのインストールは割愛。

 OSの用意が終わったら管理コンソールでそのOSを選ぶ。

 ネットワークインターフェイスを選択。
1607030112018.jpg

続いてネットワークセキュリティーグループを選択。
1607030112319.jpg

続いてまずインバウンドセキュリティーグループでポート80を開ける。これでリクエストを受け付けられるように。
1607030113136.jpg

インバウンドに続きアウトバウンドでもポート80を開ける。これでリクエストへのレスポンスを返せるように。
1607030113397.jpg

ポートを開けたらNginxを立ち上げて、IPにアクセスしてみる。ちゃんとポートが開いててNginxが動いてれば下の画像のようにレスポンスがある。
1607030114203.jpg


 このあとはDockerをインストールしてWebアプリをイミュータブルに置いておける環境を・・・と考えていたんだけど、AzureではWebアプリは専用の環境でいくつか無料で作れてしまう。なのでVPSいじりは一旦ここでストップする。


スポンサーサイト

WebアプリのテストにSeleniumを導入する

                
tags: Selenium
 継続的に改修依頼が来ているWebアプリにテストが組まれていなかった。そんでテストを導入した。ぼくの開発方法はたぶんTDDと呼ばれるものである。開発中にテストを必要に応じて行っているので、テストが主導だと大変面倒だと感じる。なのでクライアントサイドの動作確認にSeleniumを導入した。

 Seleniumとは、ざっくり言うとブラウザをスクリプトでコントロールしてしまおうというものである。なにか登録フォームを作ったとしたら、Seleniumでnameがほにゃららのとinputにほにゃららな値を入れて、submitボタンを押したことにして遷移画面をスクショで撮る、とかってことができる。
 以前はこういった役割にPhantomJSを使っていたが、PhantomJSというブラウザは一般的にない。SeleniumはFireFoxやクロームなどのドライバを入れれば、そのブラウザでテストができる。そういうわけでPhantomJSよりSeleniumを使うことにした。

 とりあえずSeleniumを使ってFireFoxのコントロールまでを今回はやる。

 まずインストールから。
 ぼくの導入タイミングでは、日本で作られたSeleniumの紹介サイトがだいぶふるいものになっていたので本家を参考にした。
http://www.seleniumhq.org
 コントロールに使う言語はスクリプト系やらなんやら選べるが、今回はC#。ということでVisualStudioを開いて、C#でコンソールアプリケーションのプロジェクトを新規作成する。
 続いてNugetでSeleniumパッケージを入れる。たぶんVisualStudioの真ん中下段にパッケージマネージャーコンソールというのがあるので、そこに下記を打ち込んでインストールされることを確認する。
Install-Package Selenium.WebDriver
Install-Package Selenium.Support


 以上でSeleniumを使う準備は整う。オブジェクトエクスプローラでWebDriverを見てみると、いろいろなブラウザが使えるようになっているのがわかるはず。あとは下記のコードをビルドでもして試してみる。Bingに検索キーワードを入れ、結果を見たりするようになっている。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;

namespace PlaySelenium
{
class Program
{
private static FirefoxDriver driver;
private static LogWriter log = new LogWriter("Selenium Test Sample");

static void Main(string[] args)
{
var url = "http://bing.com";

driver = new FirefoxDriver();

// Go to the home page
driver.Navigate().GoToUrl(url);

driver.FindElement(By.Id("sb_form_q")).SendKeys("selenium test");
driver.FindElement(By.Name("go")).Click();

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(1));
wait.Until(ExpectedConditions.TitleContains("selenium test"));
driver.GetScreenshot().SaveAsFile("screen1.png", System.Drawing.Imaging.ImageFormat.Png);

driver.FindElement(By.ClassName("sb_pagN")).Click();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(1));
wait.Until(ExpectedConditions.TitleContains("selenium test"));
driver.GetScreenshot().SaveAsFile("screen2.png", System.Drawing.Imaging.ImageFormat.Png);

driver.FindElement(By.ClassName("sb_pagN")).Click();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(1));
wait.Until(ExpectedConditions.TitleContains("selenium test"));
driver.GetScreenshot().SaveAsFile("screen3.png", System.Drawing.Imaging.ImageFormat.Png);

driver.FindElement(By.Id("sb_form_q")).SendKeys(" sample");
driver.FindElement(By.Name("go")).Click();


AssertEqual(driver.Title.Contains("selenium"), true);


//File.WriteAllText("result.txt", result);

log.Close();
driver.Quit();
driver.Dispose();
}


private static void AssertEqual(string a, string b)
{
if (a == b)
{
return;
}
else
{
var output = $"Test failed!\n" +
$"Page Title: {driver.Title}\n" +
$"URL: {driver.Url}\n" +
$"'AssertEqual' failed: {a} != {b}";
Console.WriteLine(output);
log.Add(output);
log.Close();
driver.Dispose();
Environment.Exit(1);
}
}

private static void AssertEqual(bool a, bool b)
{
if (a == b)
{
return;
}
else
{
var output = $"Test failed!\n" +
$"Page Title: {driver.Title}\n" +
$"URL: {driver.Url}\n" +
$"'AssertEqual' failed: {a} != {b}";
Console.WriteLine(output);
log.Add(output);
log.Close();
driver.Dispose();
Environment.Exit(1);
}
}
}
}

 

Dockerを使ってLinuxサーバにのっけるWebアプリをWindowsで開発する

                
tags: python Docker
 MSのIDEであるVisualStudioではPythonやNode.js開発を可能にするツール類もリリースされており、VisualStudioをコーディングに使うことを考える。VisualStudioでコーディングをしてそのWebアプリを仮想マシンのLinuxで走らせてデバッグを行いたい。それがそれほどの手間にならずに行えたらコーディングにVisualStudioを使うのを一つの選択肢に入れようかという気になってくる。そこでDockerを使う。ASP.NETもLinux対応が始まっている。ASP.NETといえば開発はVisualStudioを使うのが標準だろうから、Linuxサーバで動かすASP.NETアプリをWindows上のVisualStudioで開発という話はやっぱり出てくるだろう。
 Linuxサーバで動かすWebアプリをWindows上で書いてしまう。こんなことをする一定の価値はあるはず。

 Windows上で書いたWebアプリをコンテナとして用意したLinuxサーバで簡単にデバッグできるかやってみる。DockerでWebアプリを動かすというのは前にもやっているが、イマイチ手順が整理できてなかったので改めて。

 まずはWebアプリの用意から。簡単なサンプルをPythonで用意。"/"にアクセスすると"Hello."を返すだけのもので、Gunicorn + nginxで動かす。これhello.pyとしてプロジェクトのディレクトリ内に配置。
import os

import tornado.web
import tornado.wsgi


class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello.")


settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
}

application = tornado.web.Application([
("/", HelloHandler),
], **settings)

wsgi_app = tornado.wsgi.WSGIAdapter(application)

あとnginx設定ファイルとしてhello.confというファイルも作って同様に配置しておく。
server {
listen 80 default;
server_name example.org;
access_log /var/log/nginx/example.log;

location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}


 適当過ぎるWebアプリが用意できたので、WindowsにBoot2Dockerを入れてコマンドラインを立ち上げる。ここからはDockerの操作。
 Dockerを使うにあたってイメージとコンテナという二つの概念がある。イメージがクラスでコンテナがインスタンスと考えられるかもしれない。OSイメージからコンテナをつくる、実際に環境として動くのが作られたコンテナの方。
 Boot2Dockerで立ち上げたコマンドラインにDockerコマンドを入れていく。

docker pull ubuntu:latest
ubuntuイメージを用意。今回はサーバとしてubuntuを使うことにしておく。

docker run -it --name [new container name] ubuntu bash
ubuntuイメージを利用してコンテナを作成、同時に作成したコンテナでbashをとりあえず実行。

(作成したコンテナ内)
apt-get update;apt-get install -y nginx;rm /etc/nginx/sites-enabled/default;apt-get install -y python3-pip;pip3 install gunicorn;pip3 install tornado;
Webアプリサーバにするのに必要なソフトやライブラリをコンテナ内で用意。

ctrl + dでコンテナから抜ける

docker commit [container name] [new image name]
前までで使いまわしたい構成がコンテナとして用意できた。さらにその前でイメージからコンテナを作成したことからわかるように、コンテナのままでは同じ構成、状態を使いまわせず、コンテナを一旦イメージとしてコミットしておく必要がある。コミットが終了したらそのコンテナは用済み。

cd /c/Users/john/hello
hello.pyを保存してあるディレクトリへ移動(WindowsのパスをUNIX風に書き換えるc:\→/c/)。そこにコンテナ内で実行したいコマンドを列記したDockerfileを用意しておく。コマンドとしてはWebアプリを立ち上げるもの。Dockerfileの中身はあとに載せておく。

******
docker build -t [new image name] ./
Dockerfileをもとに新しいイメージをビルド。ここでWindowsで作っておいたプロジェクトのファイルをもろもろ、さっき必要なソフトをインストールしたコンテナから作成したイメージ内にコピーしたりソフトの設定したり。

docker run -d -p 80:80 --name [container name] [image name]
イメージからコンテナを用意して走らせる。

docker exec [container name] nginx
nginxをコンテナ内で走らせる。

Windowsのブラウザでhttp://192.168.59.103へアクセス。"Hello."が返ってくることを確認する。
15070302291312.jpg


******

Webアプリの立ち上げを含めたコンテナの用意ができているので、これを手軽に反復できるようにする。******~******内で使用しているdockerコマンドをshファイルにまとめる。ここではhello.shという名前にしておく。コンテナは作成時に指定の名前のものがすでに存在する場合は作成が実行されない。それを回避するためにすでに存在するコンテナを削除するためのコマンドも追加しておく。
cd /c/Users/foo/py_web
docker stop [container name]
docker rm [container name]
docker build -t [new image name] ./
docker run -d -p 80:80 --name [new container name] [image name]
docker exec b2 nginx


 hello.pyをちょっと書き換えてみる。返す文字列を"Hello."から"Hello, again."へ。

 Webアプリの書き換えを行ったので"sh hello.sh"を実行してLinuxサーバを再度立ち上げなおし、ブラウザでまたhttp://192.168.59.103へアクセスして返ってくる文字列をチェックする。おおよそ10秒ほどでコンテナが立ち上がり、アドレスへのアクセスが可能になった。
1507030230089.jpg


 このhello.shをDocker上で実行、終了後のお掃除をするためのコマンドを書いたバッチファイルを用意するのもいいかもしれない。
@echo off
boot2docker ssh sh [project directory]/hello.sh
echo Server is running. http://192.168.59.103/
echo Press any key to stop server.
pause > NUL
echo Removing container...
boot2docker ssh docker stop [container name]
boot2docker ssh docker rm [container name]
pause


 Dockerを使うことでWindowsから手軽にLinuxサーバのWebアプリを立ち上げることができた。今回の使い方においてはGUIありの仮想マシーンを使うよりだいぶテンポよくWindows上でLinuxサーバのWebアプリを立ち上げられそうであり、デバッグに使えそうである。


今回のDockerfileの中身
******
FROM [image name]

ADD . /usr/
WORKDIR /usr/
EXPOSE 80
RUN cp hello.conf /etc/nginx/conf.d/
RUN /etc/init.d/nginx reload
CMD gunicorn hello:wsgi_app
******
ADDは指定ファイルを指定ディレクトリへコピー
WORKDIRはワーキングディレクトリの指定(cdコマンドでは行わない)
EXPOSEで待ち受けポートの指定
あとはコマンド実行である

BootstrapでWebサイトの対応デバイスを広げる

                
tags: bootstrap
 スマフォやタブレットの普及によって、Webサイトを見るためのデバイスが増え、Webサイトの製作側もそれらに対応する必要がある。Googleは検索の表示順位にモバイルデバイス対応をしているかを加味すると発表したようだ。
 それでもわざわざ高解像度をもったデバイスと低解像度のデバイスを分けてサイトを用意するのは手間である。そこで使う手の一つがBootstrapによるレスポンシブWebデザイン。一つのHTMLで低解像度にも高解像度にも対応できるようにしてしまおうと。


 たとえばこのブログでは、ページ上部にタイトルと概要を書いたヘッダー、その下が左右にわかれていて、左側がブログ記事本文、右側がサイドバーとして簡単な案内を書いてある。高解像デバイスには今表示されているこの状態でいいとして、低解像デバイスで見るには、記事本文とサイドバーが横並びになっていると表示領域が足りないだろう。そこで低解像デバイスではサイドバーを横でなく、記事本文の下にまわせばよさそう。そういうときに使えるのがBootstrapのグリッドシステム。
 参考:http://www.atmarkit.co.jp/ait/articles/1403/19/news034_2.html
 グリッドシステムは横幅最大値を12として、要素にクラスとして”col-{prefix}-{n}”と書くことでデバイスの水平解像度ごとにどの程度横幅を取るかを設定できる。”col-lg-6”と書けばlgはlargeを表すので高解像デバイスで、nの最大が12のところ6なので、隣にもう一つ同じ要素を置ける。さらに一つ置こうとすればカラムが12からあふれることになるので表示位置が改行される。
 以下のように書けば、低解像度デバイスではサイドバーが下にまわってくれる(つまりサイドバーではなくなるが)。下にデモファイルもつけたのでブラウザで開いて、ブラウザの横幅を変化させてみたり。
<div class="container">
<section class="row">
<div id ="main" class="col-md-8 col-sm-12">main</div>
<div id="sidebar" class="col-md-4 col-sm-12">sidebar</div>
</section>
</div>

デモ

 上記のグリッドシステムを使って、PC向けに横に並べて表示していた要素を、うまく幅調節したり下部にまわしたりして画面内に収められれば、それで低解像度向けの対策がおおよそ済んでしまいそうなWebサイトはぼちぼち見かける(実際はタップするためにリンク要素間に間を取るようにするなども必要だが)。まあとりあえず解像度による要素配置を検討するときにグリッドシステムは有用ということ。



 Bootstrapでもう一つ使えるようにしておきたいのが「navbar」。
 会社のWebページを見るとおおよそが、ページ上部に会社名と案内メニューを並べている。
Company | About | うんたら | かんたら
というように。会社以外でもこういう上部に案内メニューを付けるというテンプレートを採用するWebサイトは多い。こういうメニューを作れるのがnavbar。
 低解像度デバイスで上記のような案内メニューをつける場合、多くはメニューの要素ごとに改行することで画面に収めている。
Company |
About |
うんたら |
かんたら
 このやり方を採用するのもありだが、案内メニューの要素が多いとコンテンツにたどりつくまでのスクロール量が増えて手間。訪問者に嫌われるかも。だから低解像度デバイスではトグルメニューとして表示できるように準備はしておくが、デフォルトでは表示しないという方法もありえる。
参考:http://codezine.jp/article/detail/8182?p=2
デモ
<nav class="navbar navbar-default" role="navigation">
<div class="container">

<!-- 1.モバイル表示用の省略メニュー -->
<div class="navbar-header">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target="#navbar-menu">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Title</a>
</div>

<!-- 2.ナビゲーションメニュー -->
<div class="collapse navbar-collapse" id="navbar-menu">
<ul class="nav navbar-nav">
<li><a href="#">About</a></li>
<li><a href="#">Content1</a></li>
<li><a href="#">Content2</a></li>
</ul>
</div>
</div>
</nav>



 とりあえず上記に挙げたグリッドシステム、navbarを理解しておけば、コンテンツをどう低解像度端末と高解像度端末に収めるか考える助けになるだろう。それが済んだらあとは実際のコンテンツの見易さやタップのしやすさなどを考えていけば低解像度端末と高解像度端末の両対応に近づいていける。

書籍情報を取得するためのAPIをいくつか

                
tags: WebAPI
 ISBNやタイトル、著者から書籍情報を取得するためのAPIはいくつかある。Amazon Advertising APIがたぶんもっとも有名なもので、これを使って情報取得するというブログ記事は簡単に見つかる。ここでもPythonでやったことがあるし。書籍をそろえるAmazonだけあって、素晴らしいぐらいに情報が揃うし、出版済みの本の正しいISBNをぶん投げてなんの情報も取ってこれなかったってことはない。なんの制約もないなら、書籍情報の取得はこのAPIにすべて頼りたいぐらい。
 だけどこのAPIの利用制約として商用利用のみ。使用開始までにはちょっと手間な登録作業もある。リクエスト発行回数も時間当たりの上限が設定されている。というわけで、手軽に使える書籍情報取得APIを他にさがしてみる。

Google Books API
https://developers.google.com/books/docs/v1/using?hl=ja#PerformingSearch
Googleが本に関するサービスをしているから、マイ書棚作成のような手の込んだこともできる。もちろん書籍情報の取得もできて、ISBNで書籍情報をひっぱってくるぐらいなら登録不要でURLリクエスト一発。返ってくるデータがJSONなのもクール。だけどデータベースが貧弱。書籍といってもわりと新しいタイトルは未登録のため情報取得できなかったり、マンガが駄目だったり、そもそもハードカバーの本だろうが何だろうがISBN投げても情報取ってこれなかったり。手軽なのはいいけどちょっとね……という感想。
リクエスト例:https://www.googleapis.com/books/v1/volumes?q=isbn:[ISBN]

国立国会図書館サーチAPI
http://iss.ndl.go.jp/information/api/
日本中の発行物はまじめなものからマンガ、ポルノとあらゆるものが収められているといわれる国立国会図書館のAPI。商用利用は申請必須、リクエスト発行をヘビーに繰り返す場合も登録必須。でもそうでなければ今すぐ、登録せずに使えるかもというAPI。自分の使用条件が登録必須かどうかはリンク先で。これはマンガもOKだったし、説明ページにある例を試してみるとCDの情報までも返ってきてる。
リクエスト例:http://iss.ndl.go.jp/api/sru?operation=searchRetrieve&query=isbn=[ISBN]
プロフィール

Matoba

Author:Matoba

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。