dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

python で画像をリサイズ

2024-02-24 13:36:44 | python
python で画像をリサイズする方法のメモ。
import sys
from PIL import Image

def main():
    in_file = sys.argv[1]
    out_file = sys.argv[2]
    rate = float(sys.argv[3])

    img = Image.open(in_file)
    out_width = int(img.width * rate)
    out_height = int(img.height * rate)

    out_img = img.resize((out_width, out_height))
    out_img.save(out_file)

    return 0

exit(main())


python で excel ファイルを生成

2024-01-25 00:18:35 | python
python で excel ファイルを作成する方法のメモ。
import xlsxwriter

class ExcelConverter:
    def __init__(self, fname):
        self.workbook = xlsxwriter.Workbook(fname)
        self.worksheet = self.workbook.add_worksheet()
	
        # 赤・ボールド
        self.strong = self.workbook.add_format({'color': 'red', 'bold': True})

        # 上・左詰め・折り返し
        self.cell_format = self.workbook.add_format()
        self.cell_format.set_text_wrap()
        self.cell_format.set_align('left')
        self.cell_format.set_align('top')

        self.data_idx = 0
        self.row = 0

    # ヘッダ行を出力する
    def output_header(self):
        self.row += 1

        cell = f'A{self.row}'
        self.worksheet.write(cell, '行番号')

        cell = f'B{self.row}'
        self.worksheet.write(cell, 'データ')

    # データを出力する
    def output_data(self, obj):
        self.data_idx += 1
        self.row += 1

        # 行番号
        cell = f'A{self.row}'
        self.worksheet.set_column(f'{cell}:{cell}', 7, self.cell_format)
        self.worksheet.write(cell, self.data_idx)

        # データ
        cell = f'B{self.row}'
        self.worksheet.set_column(f'{cell}:{cell}', 15, self.cell_format)
        self.worksheet.write(cell, obj['product-id'])

    def close(self):
        self.workbook.close()

def main():
    out_fname = sys.argv[1]

    conv = ExcelConverter(out_fname)
    conv.output_header()

    for line in sys.stdin:
        try:
            obj = json.loads(line)
            conv.output_data(obj)
        except Exception as e:
            try:
                sys.stderr.write(json.dumps(obj, ensure_ascii=False) + '\n')
                sys.stderr.write(e)
                sys.stderr.write('\n')
            except:
                pass

    conv.close()


二次関数のグラフをインタラクティブに描画

2023-09-10 13:22:47 | python
jupyter notebook で二次関数 f(x) = ax^2 + bx + c のパラメータ a, b, c をインタラクティブに変更してグラフを描画できるようにしてみました。
%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

def f(a, b, c, x):
    return a * x**2 + b * x + c

def plot_f(a, b, c):
    x = np.linspace(-5, 5, num=100)
    y = f(a, b, c, x)
    
    fig, ax = plt.subplots()
    ax.plot(x, y)
    ax.set_xlim(-5, 5)
    ax.set_ylim(-10, 10)
    plt.show()

interact(plot_f,
	a=(-5.0, 5.0, 0.1),
	b=(-5.0, 5.0, 0.1),
	c=(-5.0, 5.0, 0.1))



Windows に jupyter notebook をインストール

2023-08-24 21:27:46 | python
Windows10 に jupyter notebook をインストールした際のメモです。
全体の手順は以下の通り。
1. pyenv のインストール
2. python のインストール
3. jupyter notebook のインストール

■1. pyenv のインストール
git clone https://github.com/pyenv-win/pyenv-win.git /Users/{ユーザ}/.pyenv/


インストール後に環境変数の設定を行います。
環境変数は 設定 > システム > 環境変数 で設定を行うことができます。
PYENV="/Users/{ユーザ}/.pyenv/pyenv-win"
PYENV_ROOT="/Users/{ユーザ}/.pyenv/pyenv-win"
PYENV_HOME="/Users/{ユーザ}/.pyenv/pyenv-win"

path に以下を登録します。
C:\Users\{ユーザ}\.pyenv\pyenv-win\bin
C:\Users\{ユーザ}\.pyenv\pyenv-win\shims

■2. python のインストール
pip を最新化しておきます。
pip install --upgrade pip

次に python をインストールします。
pyenv install 3.9.6
pyenv global 3.9.6


■3. jupyter notebook のインストール
pip install notebook

jupyter notebook を起動するには、コマンドプロンプトで以下を実行します。
jupyter notebook


BigQuery で array にデータを追加

2022-12-15 23:47:44 | python
BigQuery で array にデータを追加する方法のメモ。

■テーブル定義
create table test1.array_test1 (
  id        string,
  features  array<struct<key string, value string>>
);

■データ登録
insert into test1.array_test1 (id, features) values ('id_01', [struct('key_01' as key, 'value_01' as value)]);

■データ更新(array にデータを追加)
update
  test1.array_test1
set
  features = array_concat(features, [struct('new_key_01' as key, 'new_value_01' as value)])
where
  id = 'id_01'
;

■テーブル登録内容確認
id_01    key_01        value_01
         new_key_01    new_value_01

■データ登録
insert into test1.array_test1 (id) values ('id_02');
■データ更新
select ndores = array_concat(ifnull(features, []), [struct('new_key_02' as key, 'new_value_02' as value)])
where
  id = 'id_02'
;

■テーブル登録内容
id_01    key_01        value_01
         new_key_02    new_value_01
id_02    new_key_02    new_value_02


python で list の要素を置換

2022-11-04 23:41:47 | python
python で list の要素を置換する方法のメモ。
■プログラム
a[2:5] を 10 に置換します。
a = [i for i in range(10)]
print(a)

a[2:5] = [10]
print(a)

■実行結果
以下の通り、a[2:5] が 10 に置換されました。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 10, 5, 6, 7, 8, 9]


lxml で xpath で text を検索した際の返却値のクラス

2022-10-12 23:07:41 | python
lxml で xpath で text を検索した際の返却値のクラスは lxml.etree._ElementUnicodeResult のリストです。
返却値を str クラスにするには、str(...) で str クラスに変換します。
import sys
import lxml.html

htmlstr = """
<html>
<body>
  <div class="d1">
    <div id="d2-1">
      <div id="d3-1">
        <p id="p4-1">p4-1 text</p>
        <p id="p4-2">p4-2 text</p>
      </div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <p id="p3-3">p3-3 text</p>
      <p id="p3-4">p3-4 text</p>
    </div>
  </div>
</body>
</html>
"""

dom = lxml.html.fromstring(htmlstr)

texts = dom.xpath("//div/p/text()")
for text in texts:
    print(f"text: {type(text)}: [{text}]")
    print(f"str:  {type(str(text))}: [{str(text)}]")


外接矩形で画像をクロップ

2022-09-24 22:57:10 | python
外接矩形で画像をクロップする方法のメモ。
import sys
import cv2

def main():
    in_file = sys.argv[1]
    out_file = sys.argv[2]
    
    img = cv2.imread(in_file)

    # グレースケール
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    res, img_bw = cv2.threshold(img_gray, 0, 255,
                                cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    # 輪郭
    cs, h = cv2.findContours(img_bw,
                             cv2.RETR_EXTERNAL,
                             cv2.CHAIN_APPROX_SIMPLE)
    
    # x, y の最小, 最大でトリミング
    min_x, min_y, w, h = cv2.boundingRect(cs[0])
    max_x = min_x + w
    max_y = min_y + h
    
    for i in range(1, len(cs)):
        x1, y1, w, h = cv2.boundingRect(c)
        x2 = x1 + w
        y2 = y1 + h

        if x1 < min_x: min_x = x1
        if y1 < min_y: min_y = y1

        if x2 > max_x: max_x = x2
        if y2 > max_y: max_y = y2

    # トリミング
    tgt_img = img[min_y:max_y, min_x:max_x]
    cv2.imwrite(out_file, tgt_img)
    
    return 0

if __name__ == '__main__':
    res = main()
    exit(res)


Selenium で User Agent を変更する方法

2022-09-23 19:53:46 | python
Selenium で User Agent を変更するには、set_preference() で
general.useragent.override に User Agent を指定します。
■プログラム
import time
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

opts = Options()
opts.headless = True
opts.set_preference('general.useragent.override', 'test-user-agent')
driver = webdriver.Firefox(options=opts)

url = 'http://localhost/?ua_test'
driver.get(url)
time.sleep(3)
driver.close()

■web サーバのログ
127.0.0.1 - - [23/Sep/2022:03:49:58 -0700] "GET /?ua_test HTTP/1.1" 200 141 "-" "test-user-agent"


python で selenium を使ってクロール

2022-09-16 23:19:53 | python
python で selenium でウェブページをクロールする方法のメモ。
selenium でブラウザを使ってクロールすると、javascript も実行してくれます。

■firefox のインスト―ル
sudo yum install firefox


■gecodriver のインストール
https://github.com/mozilla/geckodriver/releases/tag/v0.31.0 から gecodriver をダウンロードします。
gtar zxvf geckodriver-v0.31.0-linux64.tar.gz
sudo cp geckodriver /usr/bin


■プログラム
import time
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

opts = Options()
opts.headless = True
driver = webdriver.Firefox(options=opts)

urls = [
    'https://www.goo.ne.jp/',
    'https://news.goo.ne.jp/',
    'https://search.goo.ne.jp/',
]

for url in urls:
    print(url)
    driver.get(url)
    time.sleep(3)
    html = driver.page_source
    print(html)

driver.close()


Python で MySQL の blob にデータを登録

2022-09-12 23:51:03 | python
Python で MySQL の blob にデータを登録する方法のメモ。
■登録
import sys
import requests
import MySQLdb

def main():
    db = MySQLdb.connect(
        host='localhost',
        user='***',
        passwd='***',
        db='***'
    )

    url = 'https://www.goo.ne.jp'
    resp = requests.get(url)

    sql = f"insert into test_blob1 set url = %(url)s, body = %(body)s"
    cursor = db.cursor()
    cursor.execute(sql, {'url': url, 'body': resp.content})
    db.commit()
    cursor.close()

    db.close()

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

■検索
import sys
import requests
import MySQLdb

def main():
    db = MySQLdb.connect(
        host='localhost',
        user='***',
        passwd='***',
        db='***'
    )

    url = 'https://www.goo.ne.jp'
    sql = f"select * from test_blob1"
    cursor = db.cursor()
    cursor.execute(sql)
    rows = cursor.fetchall()
    for row in rows:
        print(f"url: {row[0]}")
        print(f"body: {row[1].decode('utf-8')}")
    cursor.close()
    db.close()
    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

■実行結果
url: https://www.goo.ne.jp
body: <!DOCTYPE HTML>

<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="referrer" content="unsafe-url">
<!--[if !IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
...


python での例外発生時の except と finally の実行順序

2022-09-09 12:29:20 | python
python で例外が発生した場合の except と finally の実行順序を調べてみました。
例外発生時は except を実行後に finally を実行し、except 内の raise によろ呼び出し元で例外が補足されます。
以下のプログラムで検証を行いました。

■プログラム
def func1():
    try:
        print("func1: start")
        func2()
    except Exception as e:
        print("func1: except")
        raise
    finally:
        print("func1: finally")

    print("func1: end")


def func2():
    try:
        print("func2: start")
        func3()
    except Exception as e:
        print("func2: except")
        raise
    finally:
        print("func2: finally")

    print("func2: end")

def func3():
    try:
        print("func3: start")
        raise
    except Exception as e:
        print("func3: except")
        raise
    finally:
        print("func3: finally")

    print("func3: end")

try:
    func1()
except Exception as e:
    pass

■実行結果
func1: start
func2: start
func3: start
func3: except
func3: finally
func2: except
func2: finally
func1: except
func1: finally


python で xlsx ファイルから tsv ファイルを生成

2022-08-07 17:13:21 | python
python で xlsx ファイルから tsv ファイルを生成する方法のメモ。
pandas の to_csv() で sep='\t' でセパレータにタブを指定することで、xlsx ファイルを tsv に変換することができます。
import sys
import pandas as pd

xlsx_file = 'test1.xlsx'
df = pd.read_excel(xlsx_file, sheet_name=0)
df.to_csv(sys.stdout, header=True, index=False, encoding='utf-8', sep='\t')


python で実行中のメソッド名を取得する方法

2022-08-01 23:45:53 | python
python で実行中のメソッド名を取得する方法のメモ。
実行中のメソッド名は inspect.currentframe().f_code.co_name で取得できます。

■プログラム
import inspect

def method1():
    print(inspect.currentframe().f_code.co_name)
    return

def method2():
    print(inspect.currentframe().f_code.co_name)
    return

def main():
    method1()
    method2()
    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

■実行結果
method1
method2


tsv ファイルから excel ファイルを生成

2022-07-30 00:03:23 | python
tsv ファイルから excel ファイルを生成する方法のメモ。

pandas の to_excel() で .xlsx ファイルを生成することができます。
header = False でヘッダを無効化し、index = False で行番号を無効かしています。
import sys
import pandas as pd

xlsx_file = sys.argv[1]
df = pd.read_csv(sys.stdin, sep='\t', header=None)
df.to_excel(xlsx_file, header=False, index=False)