ソフトモヒカンの勉強と開発の記録

サービス開発を目指して、プログラミングの勉強とコーディングをしています。本ブログは、そのログになります!

【PHP】2種類の連番画像ファイルをそれぞれ別サイズにリサイズする

連番になっていて、かつ、ファイル名が2種類に分けられている画像ファイル群をそれぞれ別のサイズにリサイズしたい!

開発環境

macOS High Sierra(バージョン10.13.5)
PHP7.1.16
Sublime Text

前提条件

以下で作成した関数をさっそく使いたいと思います。
【PHP】画像ファイルのリサイズをする関数の作成 - ソフトモヒカンの勉強と開発の記録


以下の設定で、画像を2種類のサイズにリサイズしたいと思います

  • 元画像のサイズは任意とする
  • 元の画像ファイルは全て「images」ディレクトリ内に置かれている
  • 画像ファイル名は、「xxxx_yy.拡張子」、「xxxx_pyy.拡張子」の2種類のルールで置かれている
  • xxxxは画像を示す名前(例:picFamily、picStarsなど)とする
  • yyは連番数字。pyyはp+連番数字とする(例:picFamily_1.jpg、picFamily_p2.png
  • pのありなしで、画像ファイルのリサイズを2通りに分けるものとする
  • リサイズした画像ファイルは、「images_resized」ディレクトリを作成して、そこに置く

プログラミング

以前に作成した関数になります。画像をリサイズして、リサイズしたファイルを指定したディレクトリに保存します。
今回は、このファイルを「imageReseze_func.php」という名前で使用します。

<?php
function image_resize($width_resized, $origin_path, $imagefile, $resize_path){
      /** width_resized:リサイズ後の画像ファイルの横幅
         orgin_path:リサイズする元画像ファイルのパス
            imagefile:画像ファイル名
            resize_path:リサイズ済みの画像ファイルの保存先パス **/

    //元の画像情報(横幅、縦、拡張子)を取得
    list($width_origin, $height_origin, $type) = getimagesize($origin_path.$imagefile);

    //画像を加工前にフォーマットごとに書き出し
    switch ($type) {
    case IMAGETYPE_JPEG:
        $image_origin = imagecreatefromjpeg($origin_path.$imagefile);
        break;
    case IMAGETYPE_PNG:
        $image_origin = imagecreatefrompng($origin_path.$imagefile);
        break;
    default:
        throw new RuntimeException('対応していないファイル形式です。: ', $type);//jpg、png以外は処理中止
    }

    /** アスペクト比を固定して、リサイズ後の縦の長さを算出
      リサイズ後の横幅は、function image_resizeを実行時に引数として指定済み **/
    $height_resized = ($height_origin / $width_origin) * $width_resized;

    // 新しく描画するキャンバスを作成
    $canvas = imagecreatetruecolor($width_resized, $height_resized);

    //$canvasオブジェクトに画像をリサイズしてコピー
    imagecopyresampled($canvas, $image_origin,0,0,0,0, $width_resized, $height_resized, $width_origin, $height_origin);

    //$canbasオブジェクトを$resize_pathに出力
    switch ($type) {
        case IMAGETYPE_JPEG:
            imagejpeg($canvas, $resize_path.$imagefile);
            break;
        case IMAGETYPE_PNG:
            imagepng($canvas, $resize_path.$imagefile);
            break;
    }

    // 読み出したファイルは消去
    imagedestroy($image_origin);
    imagedestroy($canvas);
}
?>


以下が、メインのファイルになります。
ファイル名で2種類に分けてリサイズします。

<?php
	//画像リサイズ関数のPHPファイルの読み込み
	require "imageResize_func.php";

	//リサイズした画像の置き場所の確認と作成
	$dir_resized = './images_resized/';
	if(!file_exists($dir_resized)){
		    if(mkdir($dir_resized, 0777, true)){
				echo $dir_resized."フォルダ作成成功";
		    }else{
		    	echo $dir_resized."フォルダ作成失敗";
		    }
	}else{
		echo $dir_resized."フォルダはすでに存在";
	}

	//ディレクトリ内のファイル名一覧の取得
	$dir = './images/' ;//ファイルのバス
	$filename = [];//ファイル名一覧の格納配列
	if( is_dir( $dir ) && $handle = opendir( $dir ) ) {//ディレクトリが存在する&開くことが可能である
		while( ($file = readdir($handle)) !== false ) {
			if( filetype( $path = $dir . $file ) == "file" ) {
				$filename[] = $file;
			}
		}
	}

	/** 正規表現を用いて、p付きか、pなしかを判別
              pなしは300px、p付きは600pxへリサイズ **/
	$cnt_file = count($filename);
	$pattern_size = '/_p.*\..*/';
	for( $i = 0; $i < $cnt_file; $i++ ){
		if( preg_match($pattern_size, $filename[$i]) ){
			image_resize(300, $dir, $filename[$i], $dir_resized);//引数:リサイズサイズ(px)、元ファイルのパス、元ファイル名、リサイズファイルの保存先パス
		}else{
			image_resize(600, $dir, $filename[$i], $dir_resized);//引数:リサイズサイズ(px)、元ファイルのパス、元ファイル名、リサイズファイルの保存先パス
		}
	}
?>

【PHP】画像ファイルのリサイズをする関数の作成

今回は、PHPで画像ファイルのリサイズを行う関数を作成してみます。

開発環境

macOS High Sierra(バージョン10.13.5)
PHP7.1.16
Sublime Text

前提条件とやりたいこと

  • PHPコードの存在するディレクトリ内に「images」という名前のディレクトリがあり、中に画像ファイルが置いてある。
  • 「images」ディレクトリ内の画像ファイルのサイズを変更する。
  • 「images_resized」ディレクトリを用意して、そこに保存する。

プログラム

<?php
function image_resize($width_resized, $origin_path, $imagefile, $resize_path){
      /** width_resized:リサイズ後の画像ファイルの横幅
         orgin_path:リサイズする元画像ファイルのパス
            imagefile:画像ファイル名
            resize_path:リサイズ済みの画像ファイルの保存先パス **/

    //元の画像情報(横幅、縦、拡張子)を取得
    list($width_origin, $height_origin, $type) = getimagesize($origin_path.$imagefile);

    //画像を加工前にフォーマットごとに書き出し
    switch ($type) {
    case IMAGETYPE_JPEG:
        $image_origin = imagecreatefromjpeg($origin_path.$imagefile);
        break;
    case IMAGETYPE_PNG:
        $image_origin = imagecreatefrompng($origin_path.$imagefile);
        break;
    default:
        throw new RuntimeException('対応していないファイル形式です。: ', $type);//jpg、png以外は処理中止
    }

    /** アスペクト比を固定して、リサイズ後の縦の長さを算出
      リサイズ後の横幅は、function image_resizeを実行時に引数として指定済み **/
    $height_resized = ($height_origin / $width_origin) * $width_resized;

    // 新しく描画するキャンバスを作成
    $canvas = imagecreatetruecolor($width_resized, $height_resized);

    //$canvasオブジェクトに画像をリサイズしてコピー
    imagecopyresampled($canvas, $image_origin,0,0,0,0, $width_resized, $height_resized, $width_origin, $height_origin);

    //$canbasオブジェクトを$resize_pathに出力
    switch ($type) {
        case IMAGETYPE_JPEG:
            imagejpeg($canvas, $resize_path.$imagefile);
            break;
        case IMAGETYPE_PNG:
            imagepng($canvas, $resize_path.$imagefile);
            break;
    }

    // 読み出したファイルは消去
    imagedestroy($image_origin);
    imagedestroy($canvas);
}
?>

結果

これで、画像ファイルをリサイズする関数が完成しました。


次回は、この関数を使って、ファイル名で2種類に分類された画像ファイル群を、それぞれ別のサイズにリサイズするという処理を行いたいと思います。


それでは!

【GAS】Trelloの特定のリストのカードのコメント情報を取得する

Google Apps Scriptで、Trelloの特定リストにあるカードのコメント情報を取得して、ログとして出力します!

開発環境

macOS High Sierra(バージョン10.13.5)
Google Drive
Sublime Text

前提条件とやりたいこと

GAS、Trelloキー、Trelloトークンの取得やTrelloとは何ぞやということについては、今回は割愛します。
また別記事で書けたら書きたいと思います。


今回は、上述を既知として、Trelloの特定のリストにあるカードのコメント全ての中から、Google DriveのドキュメントファイルのURLだけを検索・抽出することを試みます。
→結果から述べると、最後の検索・抽出だけ出来ませんでした・・・。

プログラム

function draftList() {
  var trelloKey   = "";//trello key
  var trelloToken = "";//trello token
  var listId = "";//リストID
  var cardUrl;//特定リストのカード群へアクセス
  //var boardId = "";//ボードID
  //var userName = "";//ユーザー名
  cardUrl = "https://trello.com/1/lists/" + listId + "/cards?key=" + trelloKey + "&token=" + trelloToken;
  
  var cardList;//特定リストのカード一覧
  var cardJson;//カード一覧のjson形式
  var cardMaxRows;//格納されているカード数
  cardList = UrlFetchApp.fetch(cardUrl, {'method':'get'});
  cardJson = JSON.parse(cardList.getContentText());
  cardMaxRows = cardJson.length; 
  
  var cardId = [];//各カードのID
  var cardName = [];//各カードの名前
  var commentUrl = [];//各カードのアクティビティ情報へアクセス
  var commentList = [];//各カードのアクティビティ情報
  var commentJson = [];//各カードのアクティビティ情報のjson形式
  var commentMaxRows = [];//各カードのアクティビティ情報の配列数
  var comment_tmp = [];//temporary array
  var documentUrl = [];//ドキュメントファイルのあるDriveのURL
  var pattern = /https\:\/\/docs\.google\.com\/document\/.*\/edit/;//DriveのURLの検索パターン
  for(var i=0; i<cardMaxRows; i++){
    cardId[i] = cardJson[i].id;
    cardName[i] = cardJson[i].name;
    //カードごとにアクセス
    commentUrl[i] = "https://trello.com/1/cards/" + cardId[i] + "/actions?key=" + trelloKey + "&token=" + trelloToken;
    commentList[i] = UrlFetchApp.fetch(commentUrl[i], {'method':'get'});
    commentJson[i] = JSON.parse(commentList[i].getContentText());
    commentMaxRows[i] = commentJson.length; //格納されているコメントの行数を取得
    Logger.log(commentJson[i]);
    //documentUrl[i] = commentJson[i].match(pattern);
    //Logger.log(documentUrl[i]);
  } 
}

結果

ソースコード内のcommentJsonには、カード情報がjson形式できちんと格納されてました。


ただ、その下のコメントアウトにある関数matchを叩くとエラーが返ってきてしまいます(そこが動けば、ミッションコンプリートだったんですけどねぇ・・・)。
ですので、documentUrlへの検索・抽出結果の格納には失敗しました。


もっと、GASについても勉強していきたいと思います!

【Python】Webスクレイピング+抽出データをメール送信

Webスクレイピングを実行して、抜き出したテキストデータをメールで自分に送りたい!

開発環境

macOS High Sierra(バージョン10.13.5)
Python3.6.4
Sublime Text

前提条件とやりたいこと

学術論文の保存・公開ウェブサイトarxivをWebスクレイピングして、その日に公開された論文のタイトル、著者、要旨の一覧を取得します。

さらに、取得した内容を、メールの本文に記述して、送信するというところまでを行うコードを作成する。

arxivとは
arXiv - Wikipedia
arxiv
https://arxiv.org/

プログラム

#scrapeArxiv.py3
import urllib.request#webページへのアクセス
import urllib.error
from bs4 import BeautifulSoup#スクレイピングデータの操作
from datetime import datetime#現在日時の取得
from pytz import timezone#タイムゾーンの取得
import re
import ssl
#Gmail作成用
import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate

#ssl認証で引っかかるのを防ぐ
ssl._create_default_https_context = ssl._create_unverified_context

#HTMLソースをbeautifulsoupで取得
def htmlAccess(url):
	#urlにアクセスして、html取得
	html = urllib.request.urlopen(url);
	#htmlをbeautifulsoupで操作
	soup = BeautifulSoup(html, "html.parser");
	return soup;

#Gmailのメッセージを作成
def create_message(from_addr, to_addr, bcc_addrs, subject, body):
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = from_addr
    msg['To'] = to_addr
    msg['Bcc'] = bcc_addrs
    msg['Date'] = formatdate()
    return msg

#Gmailアカウントから送信
def send(from_addr, to_addrs, my_password, msg):
    smtpobj = smtplib.SMTP('smtp.gmail.com', 587)
    smtpobj.ehlo()
    smtpobj.starttls()
    smtpobj.ehlo()
    smtpobj.login(from_addr, my_password)
    smtpobj.sendmail(from_addr, to_addrs, msg.as_string())
    smtpobj.close()


today = datetime.now(timezone('Asia/Tokyo'));#現在年月日時分秒曜日取得
year = today.year;
year = str(year);
month = today.month;
day = today.day;
day = str(day);
weekday = today.weekday();#曜日を数字で取得

#曜日を数字から英語に変換
weekdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
weekday = weekdays[weekday];
#月を数字から英語に変換
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
month = months[month-1];

#アーカイブページにアクセス
url_recent = "https://arxiv.org/list/cs.AI/recent";
soup = htmlAccess(url_recent);


#h3タグを日付でフィルタリング
filter_today = weekday + ", " + day + " " + month + " " + year;
#filter_today = "Fri, 1 Jun 2018"
h3_tag = soup.h3;
if filter_today in h3_tag:
	url_articles = h3_tag.find_next("dl").find_all(href=re.compile("/abs/"));#指定日の論文URLタグを取得
	url_articles = str(url_articles);#strに変換

	pattern = r'<a href=\"(\/abs\/[0-9]{1,}\.[0-9]{1,})\"\s';
	pattern_comp = re.compile(pattern);
	resultList = pattern_comp.findall(url_articles);

	urlList = [];#各論文へのアクセスURLを格納するリスト
	for value in resultList:
		url_article = "https://arxiv.org" + value;
		urlList.append(url_article);

	articleDict = {};#著者などの各論文の情報を格納
	articles = "";
	title_l = "[<h1 class=\"title mathjax\"><span class=\"descriptor\">Title:</span>";
	title_r = "</h1>]";
	pattern_author = r'<a href=".*">(.*)</a>';
	abstract_l = "[<blockquote class=\"abstract mathjax\">\n<span class=\"descriptor\">Abstract:</span>";
	abstract_r = "</blockquote>]";

	for index, value in enumerate(urlList):
		soup_article = htmlAccess(value);
		articleDict['Title'] = soup_article.select('.title.mathjax');#タイトル取得
		articleDict['Authors'] = soup_article.select('.authors');#著者取得
		articleDict['Abstract'] = soup_article.select('.abstract.mathjax');#アブスト取得
		articleDict['Title'] = str(articleDict['Title']);
		articleDict['Authors'] = str(articleDict['Authors']);
		articleDict['Abstract'] = str(articleDict['Abstract']);
		articleDict['Title'] = articleDict['Title'].lstrip(title_l).rstrip(title_r);
		articleDict['Authors'] = re.findall(pattern_author,articleDict['Authors']);
		articleDict['Authors'] = str(articleDict['Authors']).lstrip("[").rstrip("]");
		articleDict['Abstract'] = articleDict['Abstract'].lstrip(abstract_l).rstrip(abstract_r);
		tmp = "【"+str(index+1)+"】"+"Title:"+articleDict['Title']+"\n\n"+"Author:"+articleDict['Authors']+"\n\n"+"Abstract:"+articleDict['Abstract']+"\n\n\n";
		articles = articles + tmp;

	#メールで送信部分
	fromAddress = '送り主側のメールアドレス';
	myPassword = '送り主側で作成したアプリパスワード';#二段階認証をオンにした後、生成されたアプリパスワードを使用
	toAddress = '送り先側のメールアドレス';
	bccAddress = "";
	Subject = '本日のアーカイブ' + '(' + year + '/' + month + '/' + day + '/' + weekday + ')';
	Body = articles;

	if __name__ == '__main__':
		message = create_message(fromAddress, toAddress, bccAddress, Subject, Body);
		send(fromAddress, toAddress, myPassword, message);

実行結果

メールタイトルに、スクレイピングをした年月日曜日、本文にスクレイピング結果が出力されます。

  • メールタイトル:
本日のアーカイブ(2018/Jun/12/Tue)
  • 本文
【1】Title:
An Efficient, Generalized Bellman Update For Cooperative Inverse  Reinforcement Learning

Author:'Dhruv Malik', 'Malayandi Palaniappan', 'Jaime F. Fisac', 'Dylan Hadfield-Menell', 'Stuart Russell', 'Anca D. Dragan'

Abstract:Our goal is for AI systems to correctly identify and act according to their
human user's objectives. Cooperative Inverse Reinforcement Learning (CIRL)
formalizes this value alignment problem as a two-player game between a human
and robot, in which only the human knows the parameters of the reward function:
the robot needs to learn them as the interaction unfolds. Previous work showed
that CIRL can be solved as a POMDP, but with an action space size exponential
in the size of the reward parameter space. In this work, we exploit a specific
property of CIRL---the human is a full information agent---to derive an
optimality-preserving modification to the standard Bellman update; this reduces
the complexity of the problem by an exponential factor and allows us to relax
CIRL's assumption of human rationality. We apply this update to a variety of
POMDP solvers and find that it enables us to scale CIRL to non-trivial
problems, with larger reward parameter spaces, and larger action spaces for
both robot and human. In solutions to these larger problems, the human exhibits
pedagogic (teaching) behavior, while the robot interprets it as such and
attains higher value for the human.



【2】Title:
Greybox fuzzing as a contextual bandits problem

Author:'Ketan Patil', 'Aditya Kanade'

Abstract:Greybox fuzzing is one of the most useful and effective techniques for the
bug detection in large scale application programs. It uses minimal amount of
instrumentation. American Fuzzy Lop (AFL) is a popular coverage based
evolutionary greybox fuzzing tool. AFL performs extremely well in fuzz testing
large applications and finding critical vulnerabilities, but AFL involves a lot
of heuristics while deciding the favored test case(s), skipping test cases
during fuzzing, assigning fuzzing iterations to test case(s). In this work, we
aim at replacing the heuristics the AFL uses while assigning the fuzzing
iterations to a test case during the random fuzzing. We formalize this problem
as a `contextual bandit problem' and we propose an algorithm to solve this
problem. We have implemented our approach on top of the AFL. We modify the
AFL's heuristics with our learned model through the policy gradient method. Our
learning algorithm selects the multiplier of the number of fuzzing iterations
to be assigned to a test case during random fuzzing, given a fixed length
substring of the test case to be fuzzed. We fuzz the substring with this new
energy value and continuously updates the policy based upon the interesting
test cases it produces on fuzzing.



【3】Title:
Context-Aware Policy Reuse

Author:'Siyuan Li', 'Fangda Gu', 'Guangxiang Zhu', 'Chongjie Zhang'

Abstract:Transfer learning can greatly speed up reinforcement learning for a new task
by leveraging policies of relevant tasks.
<br/>Existing works of policy reuse either focus on only selecting a single best
source policy for transfer without considering contexts, or cannot guarantee to
learn an optimal policy for a target task.
<br/>To improve transfer efficiency and guarantee optimality, we develop a novel
policy reuse method, called {\em Context-Aware Policy reuSe} (CAPS), that
enables multi-policy transfer. Our method learns when and which source policy
is best for reuse, as well as when to terminate its reuse. CAPS provides
theoretical guarantees in convergence and optimality for both source policy
selection and target task learning. Empirical results on a grid-based
navigation domain and the Pygame Learning Environment demonstrate that CAPS
significantly outperforms other state-of-the-art policy reuse methods.

(多いので以下省略)

課題点としては2点。


Texコマンド、HTMLコマンドがそのまま出力されてしまいます。
もともと、ウェブサイト側でも出力されてしまっている場合もありますが、正しく表示されていても、私のコードではソースコードとして表示されてしまうようです。


もう1点は、更新数が多い場合、ウェブサイトの方は改ページされますが、私のコードは今回それを考慮していません。
(どうやるんだろうなぁ笑)

今後は、上の2点について改修していきたいと思っています。


そして、最終的には、自動化します!

【Python】処理のログファイルに今日の年月日を項目として加える

テキストファイルに今日の年月日を文字列で追記すること

開発環境

macOS High Sierra(バージョン10.13.5)
Python3.6.4
Sublime Text

前提条件

以下で作成した年月日取得関数を使う。
そして、1日1回だけ実行させるようなスクリプトファイルの実行判定に用いるための
ログファイルに今日の日付によるログ項目を追加する。
【Python】現在の年月日を"YYYYMMDD"形式で取得しようとした話 - ソフトモヒカンの勉強と開発の記録

import sys
sys.path.append("日付作成関数のパス");
import myFunc as mf#日付作成関数のインポート
import os
from datetime import datetime
from pytz import timezone

f = open('logScraping.txt', 'a');#日付をログ項目として追記するテキストファイル

#ログ項目名を作成
presentYMD = mf.presentDay();#関数による日付の文字列取得
logName = presentYMD[0] + "=";#「YYYYMMDD=」という形で記述
f.write(logName + "0\n");#処理ログのデフォルト値は0とする

f.close();
  • logName = ~~~の右辺

 関数presentDay()からは、インデックス0番目に年月日、1番目に曜日(例:Mon)が格納されたタプルが返される。
 よって、もちろんpresentYMDはタプルとなっています。

  • 結果は以下のようになります

 logScraping.txtに、以下が追記されています。

20180611=0


 簡単なコードですが、このコードは、今つくっている自動スクレイピングコードの一部になります!
 それでは、読んでくださってありがとうございました!

【Python】現在の年月日を"YYYYMMDD"形式で取得しようとした話

プログラム実行時の年月日を"YYYYMMDD"形式の文字列で取得

開発環境

macOS High Sierra(バージョン10.13.5)
Python3.6.4
Sublime Text

前提条件

ファイルに日付で名前をつけたり、ログファイルに日付ごとに項目を入れる時のために便利な関数として作ってみました。

ソースコード

以下がソースコードになります。
結末から言うと、srtftimeという関数を使用すると、このコードがとても簡単になります。

#コード1:修正前
import os
from datetime import datetime
from pytz import timezone

#現在の年月日を取得
def presentDay():
    today = datetime.now(timezone('Asia/Tokyo'));
    year = today.year;
    year = str(year);
    month = today.month;
    if not month > 9:
        month = str(month);
        month = "0" + month;
    else:
        month = str(month);
    day = today.day;
    if not day > 9:
        day = str(day);
        day = "0" + day;
    else:
        day = str(day);
    return year + month + day;#文字列で、YYYYMMDDを返す
  • まずは、必要なライブラリをインポート。
  • today = datetime.now(timezone('Asia/Tokyo'));

 東京の現在の年月日、時分秒、曜日までが

2018-06-09  21:05:02.219407+09:00

 というdatetimeオブジェクトの形でtodayの中に格納。
 また、

"weekday = today.weekday();"

 で、weekdayに曜日が数字の形で格納されます(0〜6:月〜日曜日)。

  • year = str(year);

 年をdatetimeオブジェクトから、str型にします。

  • その下のif文について

 月、日については、1桁の場合、0をつけて2桁にしてから文字列になおします。

  • return year+month+day;

 文字列連結をして、returnで返す。
 

できたー!と思ったところ、strftimeでもっと簡単に書けた。。。

#コード2:修正後
from datetime import datetime
from pytz import timezone

#現在の年月日を取得
def presentDay():
	today = datetime.now(timezone('Asia/Tokyo'));
	presentday = today.strftime("%Y%m%d");
	weekday = today.strftime("%a");
	return presentday, weekday;
  • returnで、"YYYYMMDD"文字列と"Mon"などの曜日の文字列も返す。

 返されるときは、タプル型として返される。

 世の中、便利なものがあちこち転がってるものなんですね。感謝感謝!