最終更新日:
Python についての簡単な紹介。
環境設定 / Environment Setup
Visual Studio Codeの場合 / Visual Studio Code Case
データ構造(リスト、辞書、集合、タプル) / Data Structures (List, Dict, Set, Tuple)
| データ構造 | 概要 | 表記例 |
|---|---|---|
| リスト | 一般的な配列に使う | ['a', 'b'] |
| 辞書 | 連想配列として使う | {'a':1, 'b':2} |
| 集合 | 重複を許さないリスト。検索が高速。 | {'a', 'b'} |
| タプル | 挿入順を保証できるリスト。変更できないリスト。 | ('a', 'b') |
リストはスライスできる。
stepにマイナスを指定すると逆順に参照できる。
startにマイナスを指定すると後ろからの文字数を指定できる。
letters[start:stop:step]
Pythonの辞書はキーと値のペア(kv:key/value pair)。変更可能なハッシュテーブルとして実装されている。
C++とJavaでは辞書は「マップ」と呼ばれる。
PerlとRubyでは辞書は「ハッシュ」と呼ばれる。
person = { '名前': 'Taro Yamada', '性別': '男性', '職業': '研究者'}
辞書を反復処理する
for k, v in sorted(person.items()): print(k, 'の値は', v)
集合は重複を取り除く(キーと値は存在しない。setで集合に変換。unionで集合を結合。differenceは差集合。intersectionは積集合)
u = word1.union(set(word2))
d = word1.difference(set(word2))
i = word1.intersection(set(word2))
注:空の集合はset()と表現される
データを変更しない場合はタプルを使う(要素が1つだけのときは必ず,を後ろにつける。そうしないとタプルにならないので注意。)
t = ('Python', )
辞書の辞書を作ることも可能(pprintモジュールを使うと、整形して表示できる)
import pprint
dict['ja'] = {'表示':'日本語', '英語':'japanese'}
dict['en'] = {'表示':'英語', '英語':'english'}
pprint.pprint(dict)
zip、アンパック、enumerate(要素の値とインデックスの組み合わせ)
#結合
for d in zip(city, sale):
print(d)
#分解
for c, s in zip(city, sale):
print("city:", c, " sales:", s)
#要素とインデックスを組み合わせ
for d in enumerate(city):
print(d)
リストを集計する
max(リスト) 最大値を求める
min(リスト) 最小値を求める
sum(リスト) 合計値を求める
sorted(リスト) ソートする(reverse=Trueとすると逆順ソート)
関数定義 / Function Definitions
関数直下の"""で囲まれた箇所は説明文。bool関数はTrue/Falseを返す。戻り値は複数の値を返すことも可能。
def search4vowels(word):
"""入力された単語内の母音を表示する"""
vowels = set('aeiou')
found = vowels.intersection(set(word))
return bool(found)
Python3からアノーテーションにより引数・戻り値の型を表現できる(オプション)。
word:strは文字列を引数に取る、-> setは戻り値が集合(set)であることを示す。
def search4vowels(word: str) -> set:
"""指定された単語内の母音を表示する"""
return set('aeiou').intersection(set(word))
デフォルト引数を指定できる。
def search4vowels(word: str, letters: str='aeiou') -> set:
"""入力された単語内の母音を表示する"""
return set(letters).intersection(set(word))
呼び出し側でキーワード引数を指定できる。
このとき引数の順序は問題にならない。
serch4vowels(letters='xyz', word='abc')
Pythonはオブジェクト参照渡し
代入文があるとオブジェクトが上書きされる。
代入文がなく、不変なデータでなければ、オブジェクトが変更される。
def double(arg):
print('実行前':, arg)
arg = arg * 2 #オブジェクト上書き
print('実行後:', arg)
def change(arg):
print('実行前':, arg)
arg.append('追加データ')
print('実行後:', arg)
num = 10
double(num)
print(num) # データは更新されていないように見える
numbers = [1, 2, 3]
change(numbers)
print(numbers) # 追加データが見える
lamda関数(無名関数)
data = [1,2,3,4,5]
for d in map(lambda x: x*2, data):
print(d)
リスト内包表記でも同じ
data = [1,2,3,4,5]
for d in map(x*2 for x in data):
print(d)
モジュール / Modules
関数を持つファイルがモジュールになる。
import ファイル名(拡張子.pyを除く)で参照できる
モジュールは、作業ディレクトリ、site-packages、標準ライブラリ、のいずれかに置く。
Python3.4以降ではsetuptoolsモジュールを使うと簡単に配布パッケージが作成できる
setup.pyとREADME.txt(空でもよい)の2つがあれば良い
py_modulesにはパッケージに入れる.pyファイルのリストを指定する。
from setuptools import setup
setup(
name='testmodule',
version='1.0',
description='test module',
author='author',
author_email='xxx@xxx.com',
url='xxx.com',
py_modules=['testmodule']
)
配布パッケージの作成(Windows)。
sdistはソース配布ファイルに結合することを指定している。ソースコードを含む。
py -3 setup.py sdist
配布パッケージの作成(Linux)
python3 setup.py sdist
pipによるパッケージのインストール
py -3 -m pip install testmodule-1.0.zip (Windows)
sudo python3 -m pip install testmodule-1.0.tar.gz (Linux)
第3者と共有したい場合、配布パッケージをPyPIというWebベースの集中管理型ソフトウェアリポジトリにアップロードすることができる。
テストツールとPEP8準拠
py -3 -m pip install pytest
py -3 -m pip install pytest-pep8
py.test --pep8 testmodule.py
Webアプリケーション / Web Application
Flaskのインストール
py -3 -m pip install Flask
サンプルコード(webappフォルダにhello_flask.pyで保存する)
"@app.route('/')"は関数デコレータで関数のコードを変更せずに既存の関数の振る舞いを追加する。
下記の例では、url '/'をhelloにマッピングしている
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
app.run()
py -3 hello_flask.pyで実行(終了はCtrl+C)
Webページにはテンプレートを使う(jinja2)
base.html
<!doctype html>
<html>
<head>
<title>{{ the_title }}</title>
<link rel="stylesheet" href="static/xxx.css" />
<body>
{% block body %}
{% end body %}
</body>
</head>
</html>
entry.html
{% extends 'base.html' %}
{% block body %}
<h2>{{ the_title }}</h2>
<form method="POST" action='/serach4'>
<table>
<p>このフォームを使って検索リクエストを送ってください。</p>
<tr>
<td>フレーズ:</td>
<td><input name='phrase' type="text" width='60'></td>
</tr>
<tr>
<td>文字:</td>
<td><input name='letters' type="text" value='aeiou'></td>
</tr>
</table>
<p>準備ができたら、以下のボタンを押してください。</p>
<p><input value='実行' type="text"></p>
</form>
{% end body %}
result.html
{% extends 'base.html' %}
{% block body %}
<h2>{{ the_title }}</h2>
<p>以下のデータを送信しました。</p>
<table>
<p>このフォームを使って検索リクエストを送ってください。</p>
<tr>
<td>フレーズ:</td>
<td>{{ the_phrase }}</td>
</tr>
<tr>
<td>文字:</td>
<td>{{ the_letters }}</td>
</tr>
</table>
<p>{{ the_phrase }}から{{ the_letters }}を検索すると、次の結果を返します。</p>
<h3>{{ the_results }}</h3>
</form>
{% end body %}
サンプルコード(テンプレート使用)
@app.routeのデフォルトは"GET"メソッド。
@app.route('/entry', methods=['GET', 'POST']とするとGET,POSTの両方に対応できる。
app.run(debug=True)とすると変更時に自動リロードしてくれる
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/entry', methods=['POST'])
def entry_page() -> str:
return render_template('entry.html', the_title='Hello world from Flask!')
app.run()
フォルダ構成
webapp -- test.py
webapp -- static --- xxx.css
webapp -- templates --- base.html, entry.html, results.html
リクエストデータの処理(requestパッケージ)
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/search', methods=['POST'])
def entry_page() -> str:
phrase = request.form['phrase']
letters = request.form['letters']
return str(search(phrase, letters))
app.run()
リクエストデータのリダイレクト(redirectパッケージ)・・・不要
'302'はリダイレクトを示す。
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
@app.route('/')
def hello() -> '302':
return redirect('/entry')
app.run()
リクエストデータのリダイレクト
@app.routeに複数のURLをマッピングすればよい
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
@app.route('/entry')
def hello() -> str:
return hello()
app.run()
ローカル実行との区別
__name__と__main__を使う
if __name__ == '__main__':
app.run()
ファイル操作 / File Operations
ファイルのオープン、処理、クローズ:
tasks = open('todo.txt')
for task in tasks:
print(task, end='')
tasks.close()
ファイルのオープン、処理、クローズ(with):デフォルトはReadモード。
自動でクローズ処理をしてくれる。
with open('todo.txt') as tasks:
for task in tasks:
print(task, end='')
ファイルのオープン、処理、クローズ(with):Writeモード。
戻り値が無いことを示すのにNoneを使う
def log_request(req: 'falsk_request', res: str) -> None:
with open('vsearch.log', 'a') as log:
print(req.form, req.remote_addr, req.user_agent, res, file=log, sep='|')
ファイルのオープン、処理、クローズ(with):ログ表示。
escape関数でHTMLタグをエスケープする(from falsk import escapeが必要)
@app.route('/viewlog')
def view_the_log() -> str:
with open('vsearch.log') as log:
contents = log.read()
return escape(contents)
ファイルのオープン、処理、クローズ(with):ログ表示。
splitとappendを使ってlistに登録
@app.route('/viewlog')
def view_the_log() -> str:
contents = []
with open('vsearch.log') as log:
for line in log:
contents.append([])
for item in line.split('|'):
contents[-1].append(escape(item))
return str(contents)
ファイルのオープン、処理、クローズ(with):ログ表示。HTML形式。
@app.route('/viewlog')
def view_the_log() -> str:
contents = []
with open('vsearch.log') as log:
for line in log:
contents.append([])
for item in line.split('|'):
contents[-1].append(escape(item))
titles = ('フォームデータ', 'リモートアドレス', 'ユーザエージェント', '結果')
return render_template('viewlog.html', the_title='ログの閲覧', the_row_title=titles, the_data=contents,)
HTML形式。tableで表示。viewlog.htmlとして保存。
{% extends 'base.html' %}
{% block body %}
<h2>{{ the_title }}</h2>
<table>
<tr>
{% for row_title in the_row_titles %}
<th>{{row_title}}</th>
{% endfor %}
</tr>
{% for log_row in the_data %}
<tr>
{% for item in log_row %}
<td>
{{item}}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endblock %}
CSVファイル
import csv
f = open("Sasmple.csv", "r")
rd = csv.reader(f)
for row in rd:
for col in row:
print(col, end=",")
print()
f.close()
import csv
f = open("Sasmple.csv", "w")
w = csv.writer(f)
w.writerow(["ABC", "DEF"])
w.writerows([["ABC", "DEF"],["GHI", "JKL"]])
JSONファイル
import json
f = open("Sasmple.json", "r")
data = json.load(f)
print(data)
f.close()
json.dump({"ABC":10, "DEF":20}, f)
データベース操作 / Database Operations
MySQLのインストール
MySQL-Connector/Pythonのインストール
py -3 -m pip install mysql-connector-python
Webアプリケーションのデータベースとテーブルを作成する
mysql> create database vsearchlogDB;
mysql> grant all on vsearchlogDB.* to 'vsearch' identified by 'vsearchpasswd';
mysql> quit
> mysql -u vsearch -p vsearchlogDB
mysql> create table log(
-> id int auto_increment primary key,
-> ts timestamp default current_timestamp,
-> phrase varchar(128) not null,
-> letters varchar(32) not null,
-> ip varchar(16) not null,
-> browser_string varchar(256) not null,
-> results varchar(64) not null);
データベースにログ追加
def log_request(req: 'flask_request', res: str) -> None:
"""Webリクエストの詳細と結果をロギングする。"""
dbconfig = { 'host': '127.0.0.1',
'user': 'vsearch',
'password': 'vsearchpasswd',
'database': 'vsearchlogDB', }
conn = mysql.connector.connect(**dbconfig)
cursor = conn.cursor()
_SQL = """insert into log(phrase, letters, ip, browser_string, results) values (%s, %s, %s, %s, %s)"""
cursor.execute(_SQL, (req.form['phrase'],
req.form['letters'],
req.remote_addr,
req.user_agent.browser,
res, ))
conn.commit()
cursor.close()
conn.close()
クラス / Classes
__init__は初期化の特殊メソッド
クラスメソッドの第1引数は必ずselfをつける
class CountFromBy:
def __init__(self, v: int=0, i: int=1) -> None:
self.val = v
self.incr = i
def increase(self) -> None:
self.val += self.incr
def __repr__(self) -> str:
return str(self.val)
コンテキストマネジメントプロトコル
__enter__は前処理を行う。
__exit__は後処理を行う。
__init__は初期化を行う。
__init__ -> __enter__ -> __exit__ の順で呼ばれる
データベースクラス
import mysql.connector
class UseDatabase:
def __init__(self, config: dict) -> None:
self.configuration = config
def __enter__(self) -> 'cursor':
self.conn = mysql.connector.connect(**self.configuration)
self.cursor = self.conn.cursor()
return self.cursor
def __exit__(self, exc_type, exc_value, exc_trace) -> None:
self.conn.commit()
self.cursor.close()
self.conn.close()
クラスを使ったwith構文に置き換える
app.config['dbconfig'] = { 'host': '127.0.0.1',
'user': 'vsearch',
'password': 'vsearchpasswd',
'database': 'vsearchlogDB', }
def log_request(req: 'flask_request', res: str) -> None:
"""Webリクエストの詳細と結果をロギングする。"""
with UseDatabase(app.config['dbconfig']) as cursor:
_SQL = """insert into log(phrase, letters, ip, browser_string, results) values (%s, %s, %s, %s, %s)"""
cursor.execute(_SQL, (req.form['phrase'],
req.form['letters'],
req.remote_addr,
req.user_agent.browser,
res, ))
データベースから取得した情報を表示する
@app.route('/viewlog')
def view_the_log() -> str:
with UseDatabase(app.config['dbconfig']) as cursor:
_SQL = """select phrase, letters, ip, browser_string, results from log"""
cursor.execute(_SQL)
contents = cursor.fetchall()
titles = ('フレーズ', 'フォームデータ', 'リモートアドレス', 'ユーザエージェント', '結果')
return render_template('viewlog.html', the_title='ログの閲覧', the_row_titles=titles, the_data=contents,)
いくつのリクエストに応答したか
select * from log;
select count(*) from log;
もっとも一般的な検索文字のリストは何か
select count(letters) as 'count', letters from log
group by letters
order by count desc
limit 1;
リクエストがどのIPアドレスから来たか
select distinct ip from log;
最もよく使われているブラウザは何か
select browser_string, count(browser_string) as 'count' from log
group by browser_string
order by count desc
limit 1;
クラス変数
selfのつかない変数はクラスで共通。
クラスメソッド
@classmethodの下に定義する。
clsはクラス名を参照するのに用いる
@classmethod
def getCount(cls):
return cls.count
親クラスのメソッド呼び出し
super().親クラスのメソッド()という形式で呼び出す。
関数デコレータ / Function Decorators
セッション(session)
from flask import Flask, session
app = Flask(__name__)
app.secret_key = 'YouWillNeverGuess'
@app.route('/setuser/')
def setuser(user: str) -> str:
session['user'] = user
return 'User値を設定:' + session['user']
@app.route('/getuser')
def getuser() -> str:
return 'User値の現在の設定:' + session['user']
if __name__ == '__main__':
app.run(debug=True)
可変長の引数
*は「引数のリストを受け取る」という意味。ゼロ個以上の引数。
def myfunc(*args):
for a in args:
print(a, end=' ')
if args:
print()
呼び出し時のリスト展開
*を指定すると引数のリストに展開される
values = [1, 2, 3, 5, 7, 11]
myfunc(values)
myfunc(*values)
任意のキーワード引数を受け取る
**はキーワード引数
def myfunc2(**kwargs):
for k, v in kwargs.items():
print(k, v, sep='->', end=' ')
if kwargs:
print()
デコレータ functoolsのwraps関数
独自のデコレータを作成する場合
from flask import session
from functools import wraps
def check_logged_in(func):
@wraps(func)
def wrapper(*args, **kwargs):
if 'logged_in' in session:
return func(*args, **kwargs):
return 'ログインしていません。'
return wrapper
デコレータを利用
デコレータをインポートする
@構文でデコレータを使う
from checker import checker_logged_in
@app.route('/page1')
@checker_logged_in
def page1() -> str:
return 'これはページ1です。'
デコレータを作成するためのコードテンプレート
from functools import wraps
def decorator_name(func):
@wraps(func)
def wrapper(*args, **kwargs):
# 1. デコレートされる関数を呼び出す前に実行するコードを各。
# 2. 必要に応じてデコレートされる関数を呼び出し、必要なら結果を返す。
return func(*args, **kwargs)
# 3. デコレートされる関数を呼び出す代わりに実行するコードを書く。
return wrapper
例外処理 / Exception Handling
try-except
try:
with open('myfile.txt') as fh:
file_data = fh.read()
print(file_data)
except FileNotFoundError:
print('データファイルがありません。')
except PermissionError:
print('許可されていません。')
except Exception as err:
print('他のエラーが発生しました。', str(err))
#err = sys.exc_info()
#for e in err:
# print(e)
else:
#例外が起きなかったときに処理する文
...
finally:
#必ず最後に処理する文
...
カスタム例外を作成する
from DBcm import UseDatabase, ConnectionError, CredentialsError
class ConnectionError(Exception):
pass
raise ConnectionError('接続できません。')
try:
raise ConnectionError('エラー')
except ConnectionError as err:
print('データベース接続エラー:', str(err))
except CredentialsError as err:
print('ユーザーID/パスワード エラー:', str(err))
except Exception as err:
print('その他のエラー:', str(err))
return 'Error'
SQLErrorを投げる
class SQLError(Exception):
pass
class UseDatabase:
def __enter__(self) -> 'cursor':
try:
...
self.conn.close()
if exc_type is mysql.connector.errors.ProgrammingError:
raise SQLError(exc_value)
elif exc_type:
raise exc_type(exc_value)
def __exit__(self, exc_type, exc_value, exc_traceback):
self.conn.commit()
self.cursor.close()
self.conn.close()
if exc_type is mysql.connector.errors.ProgrammingError:
raise SQLError(exc_value)
スレッド / Threads
from threading import thread
try:
t = Thread(target=execute_slowly, args=(glacial, plodding, leaden))
t.start()
except Exception as err:
print('**** ロギングが失敗しました:', str(err))
イタレーション / Iteration
from datetime import datetime
import pprint
def convert2ampm(time24: str) -> str:
return datetime.strptime(time24, '%H:%M').strftime('%I:%M%p')
with open('buzzers.csv') as data:
ignore = data.readline()
flights = {}
for line in data:
k, v = line.strip().split(',')
flights[k] = v
pprint.pprint(flights)
print()
flights2 = {}
for k, v in flights.items():
flights2[convert2ampm(k)] = v.title()
pprint.pprint(flights2)
内包表記のパターン
内包表記の方がforループより高速
destinations = []
for dest in flights.values()
destinations.append(dest.title())
--->
more_dests = [dest.title() for dest in flights.values()]
リスト内包表記
data = [1,2,3,4,5]
ndata = [n*2 for n in data if n!= 3]
ジェネレータ
()で囲まれた内包表記のように見えるもの
データ生成の度に呼ばれるので待ち時間がない
for i in (x*3 for x in [1,2,3,4,5]):
print(i)
ジェネレータ(yeild)
returnで終了せずに、待機して復帰する
import requests
def gen_from_urls(urls: tuple) -> tuple:
for resp in (requests.get(url) for url in urls):
yeild len(resp.content), resp.status_code, resp.url
正規表現 / Regular Expressions
import re
ptr = "\.(csv|html|py)$"
str = ["Sample.csv", "Sample.exe", "test.py", "index.html"]
pattern = re.compile(ptr)
for valuestr in str:
res = pattern.search(valuestr)
if res is not None:
print("found")
else:
print("not found")
for valuestr in str:
res = pattern.sub(".txt", valuestr)
mst = "変換前:" + valuestr + " 変換後:" + res
print(msg)
Webスクレイピング / Web Scraping
| モジュール | 概要 |
|---|---|
| webbrowser | Python付属のモジュール。指定したページをブラウザで開く。 |
| Requests | インターネットからファイルやWebページをダウンロードする。 |
| Beautiful Soup | HTMLをパースする |
| Selenium | Webブラウザを起動し制御する。ブラウザ上のフォームを記入したり、マウスクリックをシミュレートできる。 |
webbrowserの例(Google Mapで地図を表示する)
(引数で住所を指定するか、メモ帳などに記載した内容をCtrl+Cでコピーした状態で引数なしで起動する)
py -3 -m pip install pyperclipでpyperclipをインストールする必要あり。
import webbrowser, sys, pyperclip
if len(sys.argv) > 1:
address = ' '.join(sys.argv[1:])
else:
address = pyperclip.paste()
webbrowser.open('https://www.google.co.jp/maps/place/' + address)
requestsの例
py -3 -m pip install requestsでモジュールをインストール
ファイル名はrequests.py以外にすること
import requests
res = requests.get('http://automatetheboringstuff.com/files/rj.txt')
print(type(res))
res.raise_for_status()
if (res.status_code == requests.codes.ok):
print(len(res.text))
print(res.text[:250])
play_file = open('RomeoAndJuliet.txt', 'wb')
for chunk in res.iter_content(100000):
play_file.write(chunk)
play_file.close()
print('exit')
BeautifulSoupの例
pip install beautifulsoup4でモジュールをインストール
import requests, bs4
res = requests.get('http://suoyimi.blog.jp/')
res.raise_for_status()
bs4res = bs4.BeautifulSoup(res.text, features="html.parser")
elems = bs4res.select('p')
print(type(elems))
print(len(elems))
length = len(elems)
for elem in elems:
print(elem.attrs)
print(elem.getText())
Google検索結果の上位5ページを開く例
import requests, sys, webbrowser, bs4
print('Googling...')
url = 'http://www.google.com/search?q=' + ''.join(sys.argv[1:])
print(url)
res = requests.get(url)
res.raise_for_status()
html_file = open('example.html', 'w', encoding='utf-8')
html_file.write(res.text)
html_file.close()
soup = bs4.BeautifulSoup(res.text, features="html.parser")
link_elems = soup.select('.kCrYT a')
print(link_elems)
print(len(link_elems))
num_open = min(5, len(link_elems))
print(num_open)
for i in range(num_open):
webbrowser.open('http://www.google.com' + link_elems[i].get('href'))
コミック画像のダウンロードの例
import requests, os, bs4
url = 'http://xkcd.com'
os.makedirs('xkcd', exist_ok=True)
while not url.endswith('#'):
# ページをダウンロードする
print('ページをダウンロード中 {}...'.format(url))
res = requests.get(url)
res.raise_for_status()
soup = bs4.BeautifulSoup(res.text)
# コミック画像のURLを見つける
comic_elem = soup.select('#comic img')
if comic_elem == []:
print('コミック画像が見つかりませんでした。')
else:
comic_url = 'http:' + comic_elem[0].get('src')
# 画像をダウンロードする
print('画像をダウンロード中 {}...'.format(comic_url))
res = requests.get(comic_url)
res.raise_for_status()
# 画像を./xkcdに保存する
image_file = open(os.path.join('xkcd', os.path.basename(comic_url)), 'wb')
for chunk in res.iter_content(100000):
image_file.write(chunk)
image_file.close()
# PrevボタンのURLを取得する
prev_link = soup.select('a[rel="prev"]')[0]
url = 'http://xkcd.com' + prev_link.get('href')
print('完了')
Seleniumでブラウザ制御の例
pip install seleniumでモジュールをインストール
chromedriver.exeをダウンロードしてパスの通った場所に置く
https://chromedriver.chromium.org/downloads
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome()
print(type(browser))
browser.get('http://inventwithpython.com')
link_elem = browser.find_element_by_link_text('Read Online for Free')
print(type(link_elem))
link_elem.click()
html_elem = browser.find_element_by_tag_name('html')
html_elem.send_keys(Keys.END)
browser.refresh()
browser.back()
pyinstallerでseleniumをchromedriverと一緒にパッケージ化する場合は、以下のようにコマンドを実行する
add-binaryは"コピー元;コピー先"となっている。
pyinstaller ./main.py --onefile --noconsole --add-binary "./driver/chromedriver.exe;./driver"
pythonスクリプトのパス指定も以下のように行う。
sys._MEIPASSにはexeファイルからの実行時に一時フォルダのパスが入る。
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.dirname(__file__)
return os.path.join(base_path, relative_path)
driver = webdriver.Chrome(resource_path('./driver/chromedriver.exe'),options=options)
フォームを記入して送信する
from selenium import webdriver
login_username = 'username'
login_passwd = 'password'
browser = webdriver.Chrome()
browser.get('http://localhost/redmine/login')
email_elem = browser.find_element_by_id(login_username)
email_elem.send_keys('not_my_real_email')
password_elem = browser.find_element_by_id(login_passwd)
password_elem.send_keys('12345')
password_elem.submit()
proxy設定 / Proxy Configuration
> set HTTP_PROXY=http://{プロキシーサーバ}
> set HTTPS_PROXY=http://{プロキシーサーバ}
> pip install pyinstaller --proxy=http://{プロキシーサーバ}
実行ファイルの作成 / Create Executable File
main.pyがスクリプト名。 openpyxlなどを使用する場合、main.pyにしないとエラーになる可能性がある。 Testが出力実行ファイル名。
pip install pyinstaller pyinstaller main.py --onefile --noconsole -n Test
仮想環境 / Virtual Environments
プロジェクト毎に環境を設定する。 pyinstallerで実行ファイルサイズを小さくする目的で用いる。
pip install pipenv cd exe(フォルダ名) pipenv --python 3.9 pipenv shell pipenv install 必要ライブラリ
パッケージインストーラ(pip) / Package Installer (pip)
パッケージインストーラ。 ”pip install” と “python -m pip install”で動作が異なる場合があることに注意。 python -m pipとした場合は実行ファイルpythonに対してパッケージをインストールする。 python -m pipを使った方が無難。
参考:https://daeudaeu.com/python-pip-difference/
参考資料 / Reference Materials
- Head First Python 第2版
- やさしいPython
- 退屈なことはPythonにやらせよう(http://automatetheboringstuff.com/)