「未分類」カテゴリーアーカイブ

WindowsのPythonにmysqliclientをインストールする方法

TL;DR

PyPiからダウンロードしましょう。

本題

Ubuntuでも入れるのに多少苦労するmysqliclientですが、Windowsだと多少苦労どころじゃ済まされません。

恐らくVisual Studioなりを入れてネイティブの開発環境を整えた上で、パスなどを完全にセットアップしてコンパイルする必要があるのではないでしょうか。

ありがたいことに既にコンパイル済みの物が配布されているので、そちらを使いましょう。


そういえば、Python3.6 for Windowsのインストーラがだいぶ素敵な感じになっていました。

Visual Studioと連携して開発パッケージを入れるみたいな項目もあった気がするので、この機会にmysqlclientのコンパイルに挑戦してみても良いかもしれませんね。。

Pythonの参照制限(アンダースコア)がモジュールでは効かなかった話

思ってたのと違ったのでメモ。

Pythonは_(アンダースコア)から始まるオブジェクトは外部から参照しないようにする習慣があります。

また、__(アンダースコア2つ)から始まるオブジェクトは外部からの参照ができません。

実際、これを破ろうとすると実行時にエラーが出ます。例えば、次のようなプログラムを実行する時。

class TestClass:
    __private_value = "Secret!!!"

    def _pre_private_method(self):
        print(self.__private_value)

    def __private_method(self):
        print(self.__private_value)


def test_scope():
    test = TestClass()
    test._pre_private_method()
    test.__private_method()


if __name__ == "__main__":
    test_scope()

最初の_pre_private_methodは成功しますが、2つ目の__private_methodの呼び出しはちゃんと失敗してくれます。

AttributeError: 'TestClass' object has no attribute '__private_method'

やろうと思えばスコープの設定がきちんと行えるのは素晴らしいですね。

しかし、モジュール内で宣言された関数ではこの規則は効いてくれませんでした。

test_module.py

def _pre_private_method():
    print("Pre private!!!")


def __private_method():
    print("Absolutely private!!!")

test_caller.py

import test_module


if __name__ == "__main__":
    testmodule._pre_private_method()
    testmodule.__private_method()

test_callerを実行すると、

Pre private!!!
Absolutely private!!!

このように、プライベート宣言した関数にアクセスできてしまいます。

一応ディレクトリを分けてテストしてみましたが、こちらも同様にアクセスできてしまいました。

それと、書いていて気づきましたが、アンダースコア1つの場合はPEP8から「Access to a protected member」という警告が出るのですが、2つの方は警告すら出ませんね・・・

しっかりとスコープの設定をしたいならクラスを定義してちゃんとしたオブジェクト指向をしろという事でしょうか。確かにそんな気もする。

以上、ちょっとした備忘録でした。

Raspberry Piのアップデートが死ぬほど遅い時

Raspberry Pi公式のサーバーは恐ろしく遅いです。

raspbianイメージのダウンロードも公式から行うとめちゃくちゃ時間がかかるので、ほとんどの人はミラーサイトから落としているのではないでしょうか。

aptも例外ではなく、デフォルト設定でapt upgradeを行おうものなら、おそらく永遠に終わらないでしょう。

apt-get upgrade taking forever!

こんな事に時間をかけている場合ではないので、aptの仕向け先もミラーサイトにしてしまいましょう。

ちなみに、jaistから落としたイメージには予めミラーの設定が行われているのでこの作業は必要ありません。

/etc/apt/source.listを以下のように編集します。

deb http://ftp.jaist.ac.jp/raspbian/ stretch main contrib non-free rpi
deb http://mirrors.ustc.edu.cn/archive.raspberrypi.org/debian/ stretch main ui

1行目に通常パッケージに対してjaistのミラーを設定しています。

ただ、これだとfirmwareの更新などにarchive.raspbian.orgが使われてしまうので、こちらのサイトを参考に2行目のミラーを設定しています。

正直この設定がベストではない気がしますが、動いたので良しとします。

それにしてもこの遅さ、昔のubuntu公式を思い出しますね・・・もう少し何とかしてほしいものです。

cordovaでNo android targets (SDKs) installed

cordova requirementsを実行した際に、

No android targets (SDKs) installed!

エラーが出てしまいました。

どうやら以下2ファイルのSDKバージョンをインストールしてあるものに変更する必要がある模様。

  • (cordova_project)/platforms/android/project.properties
  • (cordova_project)/platforms/android/app/src/main/AndroidManifest.xml

また、ここを参考にminSdkVersionも設定する必要があります。

私の場合、Android SDKマネージャにてNougat(SDKバージョンは24)が入っており、Cordovaのバージョンは8.0.0でした。

project.properties

target=android-24

AndroidManifest.xml

<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />

こちらは8.0.0の記述はありませんでしたが、最新の7.0.0は19からだったので19に指定しました。

PQI Air Card向けにcurlをコンパイルする作業をDockerで自動化

随分と前の記事ですが、以前PQI Air Cardに向けてcurlをコンパイルする記事を書きました。

最近こういうことはDocker内で済ませると手間が省けてよいのではという知見を得たので、サクッとDockerに閉じ込めることにしました。

リポジトリはこちらです。

git clone https://github.com/Sakaki/PQICC.git
cd PQICC
docker-compose up

成功するとbin/curl以下にcurlのバイナリが作られていると思います。

ただし、このバイナリは以前の記事を参考に作成しただけなので、動作しない可能性が高いです。申し訳ありません・・・

実機で動かしてみて、ちゃんと動作するようにしたい・・・したい・・・

Dockerfile+aptでHash Mismatchエラー

Dockerでubuntuを元にしたイメージを作っているとき、以下のエラーに遭遇。

Dockerfileを使いaptでいろいろとインストールしている時でした。

Err:101 http://archive.ubuntu.com/ubuntu xenial/main amd64 fakeroot amd64 1.20.2-1ubuntu1
  Hash Sum mismatch

そこでaptを使う際に以下の警告が出ていたことを思い出します。

WARNING: apt does not have a stable CLI interface.

最初はちょっと意味が分かりませんでしたが、aptはCUIコマンドではあるもののCLI、つまりスクリプト等からの実行はサポートされていないみたいです。

Dockerfile内のコマンドをaptからapt-getに変更したところうまくいきました。

警告にはちゃんと従うべきですね・・・

Dockerでプログラムのビルドを自動化した話

Dockerが面倒なプログラムのビルドに便利だったという話です。

普段は使わないけど、たまにビルドしたいプログラムとかは環境設定が面倒ですよね。

それをDockerを用いて環境構築を行うことでとても快適にできたので備忘録として書いておきます。

具体的にはDockerfileで環境構築を行い、イメージの実行時にビルドします。

Dockerfileではビルドに必要な環境をなるべく整えておきます。例えば、

  • 必要なシステムライブラリのインストール
  • ツールチェーンやコンパイラのダウンロード・導入
  • 環境変数のエクスポート
  • ビルドするプログラムのコピー
  • コンパイラに必要な外部ライブラリのインストール

などがありますね。一度ビルドしてしまえば再利用が効くので、重い処理は全てここでやってしまいましょう。

環境変数のエクスポートが地味に便利で、ビルドオプションをあらかじめターゲットに絞って設定できます。

私はたまにarm向けのバイナリをコンパイルする時があるので、コンテナ内だけで有効な環境変数が設定されるのは重宝しています。

ここまで行えれば、あとはビルドするスクリプトをイメージ実行時に走らせれば良いだけです。

また、イメージにはビルドに必要な環境が整っているので、サンドボックス的な使い方もできます。

Dockerはサーバー向けみたいな勝手なイメージがありましたが、こういう作業にも向いているんですね。

今回は仕事で行った作業の備忘録だったので具体的な事は書けませんでしたが、いずれ具体的な利用法を書こうと思います。

Python+seleniumの描画時に要素配置を待機する

seleniumを使ってのスクレイピングは強力ですが、非同期で実行されるのでrequestsやcurlのような確実性が失われてしまいます。

フォーム入力などの操作を確実に行うためには、対象の要素が描画されるまで待機する必要があります。

例えば、ログインページでユーザー名を入力する際は、以下のようなコードで要素が入力可能になるまで待機するのが安全です。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions

driver = webdriver.Firefox()
driver.get(login_page_url)
WebDriverWait(driver, 20).until(expected_conditions.element_to_be_clickable((By.NAME, "username")))

また、ログイン後に何か操作を行う場合は、ログイン後にリダイレクトされるページがきちんと描画されていることを確認した方が良さそうです。

確認には適当なIDを持つ要素を選び、それが描画されるのを待つのが良いと思います。

WebDriverWait(driver, 10).until(expected_conditions.presence_of_element_located((By.ID, "some-element-id")))

これらに気を使わないと意外とうまくいきません。

Pythonを書いているのに非同期に気を使っていると、別言語を書いている気分になりますね(ブラウザを操作しているので当然ですが・・・)。

Python+seleniumでwebdriverとしてheadlessなFirefoxを使う方法

Python+seleniumでスクレイピングをする際webdriverとしてPhantomJSを使っていましたが、前々からPhantomJSは非推奨という警告が出ていて気になっていました。

また、PhantomJSの開発者の方も別のヘッドレスブラウザを使ってほしい意向を示しているようです。

替わりの選択肢(ヘッドレス機能があるもの)としてはFirefoxかChromeくらいしか思い浮かびませんが、今回はデスクトップ版のUbuntuをターゲットとしたプログラムを書いていたためデフォルトで入っているFirefoxを使う事にしました。

seleniumからFirefoxを扱う際は、geckodriverというプロキシを経由して操作を行うようです。

最新版は、ここからダウンロードできますので、Pythonからそのパスを指定します。

geckodriverディレクトリ内にWindows(geckodriver.exe)とLinux(geckodriver)のバイナリを配置しています。

import os
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

if os.name == 'nt':
    geckodriver_path = "geckodriver/geckodriver.exe"
else:
    geckodriver_path = "geckodriver/geckodriver"
options = Options()
options.set_headless(Options.headless)
driver = webdriver.Firefox(executable_path=geckodriver_path, options=options)

これでFirefoxがインストールされていれば動作するはずです(Windows機しかなかったのでこちらでしかテストしていませんが・・・)。

後でLinuxでの動作確認も行おうと思います。

ubuntuで再起動が要求される際に更新されるパッケージの内容を調査

サーバーのメンテでカーネルを更新したのですが、再起動後も「再起動が必要です」という表示が出ていました。

実行中のカーネルのバージョンも最新だったので、なぜ再起動が必要かを調査してみました。

まず、再起動が必要な場合 /var/run/reboot-required 内にその旨が記述されています。

$ cat /var/run/reboot-required
*** システムの再起動が必要です ***

また、 /var/run/reboot-required.pkgs を参照すると再起動が必要なパッケージの理由を閲覧できます。

$ cat /var/run/reboot-required.pkgs
linux-base

linux-baseというとカーネル関連のアップデートですが、その詳細がよく分かりませんね・・・

どうやら /usr/share/update-notifier/notify-reboot-required というスクリプトが実行されることでこの文章が記録されるらしいです。

スクリプト中に次の記述があります。

if [ "$0" = "/etc/kernel/postinst.d/update-notifier" ]; then
    DPKG_MAINTSCRIPT_PACKAGE=linux-base
fi

驚いたことにlinux-baseという文章は決め打ちで記述されているようです(だったらreboot-required.pkgsは必要ないのでは・・・)。

また、update-notifierはOSのアップデートやクラッシュレポートなどを監視・報告するプログラムのようです。

具体的に再起動で適用されるパッケージを表示したかったのですが、少し調べた限りでは方法が分かりませんでした。

とりあえず再起動を行って様子を見ようと思います。