カテゴリーアーカイブ Python

著者:杉浦

【Python】対話型アプリケーション自動化ツールPexpectの紹介

 Linux端末などにアクセスしてコマンドライン上で操作を行うことはよくあります。何かの作業で定型化した操作を行うこともままあります。Pexpeectでコードを組むと自動化処理を作れます。PexpectはLinuxコマンドのexpectの様なことをするPythonモジュールです。
Pexpect version 4.7 — Pexpect 4.7 documentation
 接続コードはシンプルです。ただ使うだけなら次のコードで大丈夫ですが、gitやら何やらに上げると大惨事です。そういう時はid, passwordは設定ファイルなり実行時の引数なりで渡すようにしましょう。

child = pexpect.spawn('ssh user@example.com')
child.expect('password')
child.sendline('mypassword')

 Common problems — Pexpect 4.7 documentation
 とりあえずの作りなら対話は次の様になります。コマンドを送る、入力可能状態になるまで待つ、の繰り返しです。

child.expect('user@example.com.*') # 入力可能状態(左側にユーザ名とディレクトリが見えるアレ)であることを期待する
child.sendline('telnet localhost %d\r' % telnet_port# コマンドを送る

 あくまで対話なので対話先で改めて対話先のローカル線用対話プログラムを開始することもできます。というかかなり広範囲のことができます。Linuxを深く知らない自分の範囲では何でもできるぐらいの感じです。Pexpectはコマンドライン上のプログラムのテスト、サーバやマイコン設定のデプロイ、ncとか使ってペネトレーションテストなど様々な使い道があります。
 公式ドキュメントのExamples — Pexpect 4.7 documentationにはプログラムとしてほぼ完成の状態の例があるのでそれを改造すると理解が早まり、すぐ実践ができます。

  • この記事いいね! (1)
著者:杉浦

【Python】誤った引数に値を渡さないためのキーワード引数

 キーワード引数は造語という程ないにしろ正式な語ではありません。可変長引数の一種です。ですがググれば多く出るのでそう間違いでない通称の一つです。

 長大な引数の関数を用いる際、時々引数の順や数え間違いで事故が起こります。何かしらの構造体を使うのが一つの解決策です。構造体中に引数への正しい接続を埋め込み、使用する際には簡単にするAdapterパターンは構造体を用いる接続方法の典型的な解決策の一つです。

// 使いたい関数hogeMember。これを使うためにhogeMember('hoge', 'fuga', 'foo', 'bar',...)と大量の引数を正しい順序で用意することになる。何度も繰り返したり、変更が行われればミスが起きる。
function hogeMember($name, $code, $email, $number, $location, $birthday_year, $birthday_week, $birthday_day, $old)

// $member = new Member();として初期化した後に、$member->name='tarou';などと名前毎にプロパティをセット、$member->callHogeMember()とすることで誤りなくhogeMember()を呼び出せる。
class Member{
  public $name;
  public $code;
  public $email;
  public $number;
  public $location;
  public $birthday_year;
  public $birthday_week;
  public $birthday_day;
  public $old;
  
  public function callHogeMember(){
    hogeMember(
      $this->name,
      $this->code,
      $this->email,
      $this->number,
      $this->location,
      $this->birthday_year,
      $this->birthday_week,
      $this->birthday_day,
      $this->old,
    );
  }
}

 ですが、ただ誤りなく関数を呼ぶためだけのオブジェクトは無駄な気がしてしまいます。特にパラメータが疎な時はなおさらです。キーワード引数はそういった問題を解決します。
 Pythonのキーワード引数は例えば次の様に使います。

HEADERS = {
    "x-api-token": 'apiToken'
}
PARAMS = {
    "mailAddress": randomname(10) + "@example.com",
    "password": "password",
}

response = requests.post(url='https://hogehoge/api/member', headers=HEADERS, params=PARAMS)# 引数順不同
response = requests.post(params=PARAMS, headers=HEADERS, url='https://hogehoge/api/member')# ↑と同じ結果になる

 値に名前をつけて関数を呼ぶことによって、対応したキーの引数に値が渡せます。大体のライブラリは適切にキー名をつけてくれています。キーワード引数を用いることによって、わざわざ準備することなく適切に多様な引数を持つ関数を呼び出せます。

  • この記事いいね! (0)
著者:杉浦

【Python】PowerPointのファイルをpythonで作るpython-pptxの紹介

 Pythonは様々なライブラリを組み合わせて、多様な作業をプログラミングできます。pptxファイル(PowerPointのファイル)の作成も、またできます。python-pptxはこれを実現します。

python-pptx — python-pptx 0.6.17 documentation
 何ができるかはpptxファイルの構造を知ると少しわかりやすいです。pptxファイルはその実zipファイルと同じ形式です。pptxをzipに変えると例えば、次の様になります。

 解凍に成功しました。pptxファイルとは特定のファイル構造のファイル群を圧縮したzipファイルのことであり、zipファイル⊃pptxファイルとなっているわけです。この中から、どのページに、どのテンプレートが使われて、テンプレート中のある空欄に、何が、どう埋まっているか、が読み取れます。python-pptxではこの構造の指定に従ってページを構成していきます。
 テンプレート構造から細かく作っていく方法はGUIからpptxを作る場合、おそらくあまりしないでしょう。必然python-pptxは普段使いからかけ離れた理解の難しいものになります。そういった際にはpython-pptxを用いたhogehogeな関数を作った、というwebページを探すとよいでしょう。わかりやすいです。
 python-pptxは例えば、次の様に記述できます。

from pptx import Presentation
import datetime
from glob import glob
from pptx.util import Pt

def makeManual():
    prs = Presentation('template.pptx')
    prs = addContentPage(
        prs, '検索画面使用方法',
        '上部の検索ボックスに検索対象の語を入力し、検索ボタンを押すことで検索ができます。\nいずれの検索画面でも同様に検索ができます。',
        [], 'Tests_Browser_TestCase_Admin_Member_SearchTest_testSearchHogeHoge_000.png'
    )
    prs.save('管理者画面操作マニュアル.pptx')


# スライドにタイトル、サブタイトル、本文、画像ファイルを追加
def addContentPage(prs, title, subtitle, texts, fn):
    fnms = glob('%s/%s' % (__screenshots_dir, fn)) # 画像ファイル読み込み
    slide = prs.slides.add_slide(prs.slide_layouts[1]) # pptxファイルにスライド追加
    # slide = addTextToSlide(slide, title, subtitle, texts) # スライドにタイトル、サブタイトル、本文を追加
    addPictureToSlide(prs, slide, fnms[0]) # スライドに画像追加
    return prs


# スライドに画像を追加
def addPictureToSlide(prs, slide, fnm):
    pic = slide.shapes.add_picture(fnm, 0, 0)

    # 縦0.8倍。画像の比率変えず
    base = pic.height
    pic.height = int(prs.slide_height * 0.7)
    pic.width = int(pic.width * (pic.height / base))
    # 左右中央揃え
    pic.left = int((prs.slide_width - pic.width) / 2)
    # 下揃え
    pic.top = int((prs.slide_height - pic.height))

    return slide

 上記のコードはtemplate.pptxというテンプレートに従ってpptxファイルオブジェクトを生成。それに画像を追加して保存する、というコードになります。これだけでも画像を更新する度にpythonを走らせるだけでpptxを更新できます。特定の形式のpptxを高頻度で変更する場合、多少わかりにくくともpptx生成をプログラミング化すると作業が大きくはかどります。

  • この記事いいね! (1)
著者:杉浦

【Python】PythonのHTTP通信用ライブラリRequestsとBeautiful SoupとSelenium

 Pythonは次の標語にある様に、様々なことを簡単なコードで実現することが主目的の言語です。この目的は、多様なライブラリの中から目的に沿ったライブラリを呼び出す、という方法で実現されています。

Python is a programming language that lets you work quickly and integrate systems more effectively
Welcome to Python.org

 この記事では3種類のHTTP通信用ライブラリを目的別に紹介します。
 ひとつはRequestsです。
Requests: HTTP for Humans™ — Requests 2.21.0 documentation
 Requestsはとても簡易なHTTP通信用ライブラリです。例えば次の様にパラメータと宛先を用意してメソッド指定するだけで動きます。これはAPIが用意してある様な、GUIを用いないことを想定している相手との通信で有効です。

import requests

BACKLOG_PARAMS = {
    'apiKey': API_KEY,
    'projectId': PROJECT_ID,
    'summary': data['summary'],
    'issueTypeId': ISSUE_TYPE_ID,
    'categoryId[]': CATEGORY_ID,
    'priorityId': PRIORITY_ID,
    'startDate': data['startDate'],
    'endDate': data['endDate'],
    'estimatedHours': 7,
    'assigneeId': ASSIGNEE_ID,
}

response = requests.post(BACKLOG_URL, params=BACKLOG_PARAMS)
print(response)

pythonの人間のためのHTTPライブラリRequests – 株式会社シーポイントラボ | 浜松のシステム開発会社

 ふたつめはBeautiful Soupです。これはHTMLを始めとした構文解析を活用することができます。大体Requestsと組み合わせて静的なwebページを扱う時に使います。ブラウザを介さないため後述のSeleniumより遥かに高速です。
Beautiful Soup: We called him Tortoise because he taught us.

import requests
from bs4 import BeautifulSoup

response = requests.post(BACKLOG_URL, params=BACKLOG_PARAMS)
soup = BeautifulSoup(response.content)

soup.title
# <title>The Dormouse's story</title>

soup.title.name
# u'title'

soup.title.string
# u'The Dormouse's story'

soup.title.parent.name
# u'head'

 3つ目はSeleniumです。webページのテストでよく使うものでPythonにも用意されています。ブラウザを介する正式な手順を踏むことによってセキュアなページでも手間取ることなくアクセスできます。代わりにブラウザを介する分けっこう重いです。
Selenium with Python — Selenium Python Bindings 2 documentation

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.select import Select


def login():
    # ログイン
    driver.get('https://')
    driver.find_element_by_css_selector('input[name="_Account"]').send_keys('sugiura')
    password = ''
    driver.find_element_by_css_selector('input[name="Password"]').send_keys(password)
    driver.find_element_by_css_selector('input[name="Submit"]').send_keys(Keys.ENTER)


if __name__ == '__main__':
    options = Options()
    options.add_argument('--headless')
    # Chromeを起動
    driver = webdriver.Chrome(executable_path="C:\selenium\chromedriver.exe", chrome_options=options)
    login()
  • この記事いいね! (1)
著者:杉浦

最適化問題のための簡易学習

 最適化問題とは、任意の関数の出力値が最大、もしくは最小となる引数は何か、という問題です。任意の関数が単純な形、例えば次の図の様なきれいな谷の場合は解を陽に求める(試行することなく一発で求められる)ことが出来ます。

 しかし現実の問題はもっと複雑です。引数は多く、関数の出力は多峰性を持ちます。
 それでもとりあえず関数と引数さえ用意できれば(深く取り組むなら関数を考えること、関数を作ることに相当労力がかかります)、関数の出力を評価することはできます。
 今日まで考えられてきた機械学習手法はより正確な関数を用意し、より早くに正確に最大、最小となるパラメータを見つけるためのものです。この記事で考えるのは、より早くに正確に最大、最小となるパラメータを見つける、という部分を無視し、単純な乱数で最大、最小に近づく方法です。

# 最小問題について
def main():
    params = Params() # 引数オブジェクト。より適した値らが入る
    for i in range(0, 1000): # 雑に回す
        p_key, p_value = get_rand_param() # なにか値を引っ張ってくる。ここの動きを正確にすると機械学習になる
        new_val, new_params = get_eval(params, p_key, p_value) # 関数に引数を入力。この関数を正確にすると機械学習になる
        params = new_params if new_val < val else params # 評価値が前回の結果より良いならば引数更新

 具体的な関数の中身は書いていませんがこれを拡張すると機械学習らしいことができます。最終的に最も良いものを選んでいますが、このままだと引数がランダムなので学習感ないですね。

  • この記事いいね! (0)
著者:杉浦

【Python】PythonでSlackの通知を送る

 Slack開発元謹製のIncoming Webhookとライブラリslackwebを繋げることでとても楽にSlackへ通知を送ることが出来ます。
 どのくらい簡単かというと次のコードで実装できるくらいです。

import slackweb


slack = slackweb.Slack(url="Incoming Webhookで発行したURL")
slack.notify(text="python to slack")

 Slackに登録し、チャンネルを扱える状態で Incoming Webhook | Slack App ディレクトリへ移動。設定を追加で移動した画面からインテグレーションの追加を押すと、URLが発行されます。


 後は先のコードの様に通知を送るだけです。

  • この記事いいね! (1)
著者:杉浦

Pythonのグローバル変数の命名における慣習

 Pythonはファイル全体をスコープとした記述が出来、例えば次の三行だけのファイルを動かせます。

print('---')
print('Hello, World!')
print('---')

 インタプリタらしく一行一行コマンドを読み込み、実行していく感じです。この一行一行がくせもので必ずファイル全体をスコープとしたグローバル環境にコードを記述する必要があります。例えば関数を定義して呼び出す際、最後はグローバルから呼び出すことになります。

def hello_world():
    return 'Hello, World!'


hello_world()

 この仕様によるグローバル汚染を防ぐためにPythonにはいくつか慣習があります。例えば、実行ファイル以外のコードが不意に走ることを防ぐためのif文があります。

def hello_world():
    return 'Hello, World!'


if __name__ == '__main__':# このファイルがメインの実行ファイルならばtrue
    hello_world()

 同じ様にグローバル変数には命名の慣習があり、ローカル内で誤ってグローバル変数を参照することを避けます。内容はいたってシンプル、先頭の_です。

def hello_world():
    return 'Hello, World!'


_msg = hello_world()
if __name__ == '__main__':# このファイルがメインの実行ファイルならばtrue
    print(_msg)

 この様にすることで複数ファイルを連携させた際に参照したい変数、参照したくない変数を操りやすくします。この慣習は根付いており、Python実行ファイル上において_hogeな変数とfugaな変数は同等に扱われるにもかかわらず、IDE等のPython対応のエディタにおいて_hogeな変数はグローバル変数用の扱い、fugaな変数はローカル変数用の扱いと区別されます。

  • この記事いいね! (0)
著者:杉浦

Pythonのrequestsでmultipart/form-data形式通信を行う

 multipart/form-dataは文書、ファイル、またはバイト列の性質や形式を示す標準の一つです。multipart/form-dataは複数の部分から成るHTMLフォームのデータです。
MIME タイプ – HTTP | MDN #multipartform-data
 multipart/form-dataはごちゃまぜの種類のデータをまとめて送る時に便利です。これをどうやって使うかですがJavaScriptならば描画しないフォームを作り、それを送ることができます。次のコードはある画像ファイルとその画像ファイルの加工データを送信するのコードの一部です。JavaScriptはHTMLを扱う機能が数多く備わっており、フォーム形式の通信もJavaScript単独でパパっと書けます。

const formData = new FormData();// フォーム作成
formData.append('original_file', this.file);// フォームに値を入力
formData.append('cropped_file', croppieResponse);// フォームに値を入力

// multipart/form-data形式を指定して通信
axios.post(this.uploadDistUrl,
    formData,
    {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    }
).then((uploadImgResponse) => {
  // 通信成功時処理
}).catch(() => {
  this.vodalMsg = '通信に失敗しました。';
});

 pythonにはrequestsというHTTP通信用ライブラリがあります。これは人間に優しいを謳い文句にするくらい簡単に動かせることが特徴です。どのくらい楽かというと次の読みやすいインデント、改行の10行ないコードだけのファイルでpostを投げられるくらいです。

import requests

request_data = {
    'id': 'hoge',
    'password': 'fuga',
}

response = requests.post('http://127.0.0.1:8000/api/hoge', params=request_data)
print(response)

 便利なrequestsでmultipart/form-dataで送る方法を調べたところ次のコードで実現できました。
Quickstart — Requests 2.21.0 documentation#post-a-multipart-encoded-file

import requests

request_data = {
    'id': 'hoge',
    'password': 'fuga',
}
files = {'image': ('hoge_image',
                   'data:image/png;base64,000000000',
                   'image/png')}

response = requests.post('http://127.0.0.1:8000/api/hoge', params=request_data, files=files)
print(response)

 filesの様に色々形式毎の引数を用意して渡せば、まとめてよしなに送信してくれます。とてもとても便利ですね。

  • この記事いいね! (0)
著者:杉浦

pythonの人間のためのHTTPライブラリRequests

 Requests: HTTP for Humans™ — Requests 2.20.1 documentation
 requests · PyPI
 Requestsは人間に優しいHTTP通信用ライブラリです。ちょっとしたリクエストをAPIに送る時などに便利です。次のコード例はbacklogの課題追加APIです。backlogの課題はまとめて追加することが多くいちいちUIで記述をするのは面倒です。APIでまとめて送ることで楽が出来ます。

import requests

BACKLOG_URL = "https://hogehoge.backlog.jp/api/v2/issues"
API_KEY = "hogehogefugafuga"
PROJECT_ID = 104607  # プロジェクトID
ISSUE_TYPE_ID = 485681  # 課題種別ID
CATEGORY_ID = 279257  # カテゴリID
PRIORITY_ID = 3  # 優先度
ASSIGNEE_ID = 251977  # ユーザID

request_data = [
    {
        'summary': '会員登録機能',
        'startDate': '2018-12-07',
        'endDate': '2018-12-08',
    }, {
        'summary': '会員削除機能',
        'startDate': '2018-12-08',
        'endDate': '2018-12-09',
    }
]
for data in request_data:
    BACKLOG_PARAMS = {
        'apiKey': API_KEY,
        'projectId': PROJECT_ID,
        'summary': data['summary'],
        'issueTypeId': ISSUE_TYPE_ID,
        'categoryId[]': CATEGORY_ID,
        'priorityId': PRIORITY_ID,
        'startDate': data['startDate'],
        'endDate': data['endDate'],
        'estimatedHours': 7,
        'assigneeId': ASSIGNEE_ID,
    }

    response = requests.post(BACKLOG_URL, params=BACKLOG_PARAMS)
    print(response)

 requetsでリクエストを送るのは簡単です。送信メソッド毎(get,post,put,patch,delete)のメソッドがrequests内に用意されており、それの引数に文字列のURLと辞書型のボディを渡すだけです。これだけの設定でファイルを実行するとリクエストが送られます。
 細かい設定、細かい結果の取得も簡単にできます。

>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
  • この記事いいね! (0)
著者:杉浦

Pythonやjavascriptで現れる__の通称

 Double UNDERsocoreを略してdunderと読みます。発端は How do you pronounce “__” (double underscore)?らしいです。発端はどうあれ今はgoogleで`dunder __`と検索すると10万件以上ヒットするほど使われています。
 Pythonやjavascriptには__で囲われた変数が現れます。

__name__

__proto__

などです。この__は予約された変数で、プログラムを実行した時点ですでに中身が設定されている変数です。必然、中身を調べるわけですが、検索エンジンによっては__を読み取ってくれないことがあります。dunderはそのような時に助けなってくれる呼び方です。
 javascriptでは__proto__以外で__の絡んだ値をそうそう扱わないですが、pythonはまま使います。その中でもよく使うのは以下のあたりです。

class hogehoge
	def __init__(self, hoge, fuga):
		#コンストラクタ定義
if __name__ == '__main__':
	# メイン実行の関数呼び出し

 __init__はコメントの通りclassのコンストラクタ定義。if __name__ == ‘__main__’:は直接実行(__name__ = __main__)されているか、他ファイルから呼び出されてい実行(__name__ = ファイル名)されているかで場合分けです。過去のプログラムの一部を使いたい時はよくありますので、その時に備えて書いたりするわけです。

  • この記事いいね! (0)