ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

Titanium Desktopを使って、Python呼び出しはどれだけ楽か?

Titanium Desktopが Python, Ruby, PHPで呼び出すGUI開発に便利だよ〜と言う記事を前に読みまして、どれだけ便利かインストールして試してみました。


Titanium Desktopが どんなものか?どんな事が出来るか?については、上のWeb siteを見た方が良いでしょう。

ここでは、Pythonとの連携性がどれだけのものか、自分で試してみたメモです。

インストール

Titanium Desktopを使った開発を行うには、本家でセットアップをダウンロードしてインストールします。

の真ん中辺りに、Windows / Linux / Mac OSXの三種類のセットアップが用意されているので、ダウンロードして実行&インストールします。

ちなみに、Windows版のセットアップのサイズは5〜6MB程度でした。
(バックグランドで本体をダウンロードしているんでしょう)

プロジェクトの新規作成

インストールが完了したら、スタートメニューからTitanium Developerを起動して、プロジェクトを新規作成します。
上のLinkの説明でも書いてありますが、このTitanium Developerアプリケーションはプロジェクトの管理能力しか無いようで、Visual StudioDelphiのようなポトペタ開発は出来ません。あしからず。
(ソース管理や編集も出来ません。かなり潔いです)


まずは、画面上部の「New Project」アイコンをクリックしますと、プロジェクトの設定を求められますので適当に入力します。
7
7 posted by (C)wacky

気をつけるべき点は、「Project Type」を「Desktop」に設定する事と、「Directory」でプロジェクトの保存フォルダを指定する事、「Language Modules」に使用する言語にチェックする事でしょうか。
入力後、「Create Project」をクリックすると、プロジェクトの作成はOKです。


後から設定を変更したかったら、左欄の「PROJECTS」欄に表示されているプロジェクトを指定しつつ「Edit」欄をクリックすると表示される項目を修正して、「Save Changes」すればOKのようです。

とりあえず動かす

先ほど作ったプロジェクトから、いきなり動かす事ができます。
「Test & Package」を選択し、「Launch App」ボタンを押すと、何やらビルドが始まります。
2
2 posted by (C)wacky


ちょっと待っていると、以下のような「Welcome Titanium」アプリケーションが起動します。
3
3 posted by (C)wacky


ちなみにビルドすると、プロジェクトのフォルダ下に、「dist\win32\<プロジェクト名>」というサブフォルダが出来て、そこに実行バイナリが出来ています。
これをダブルクリックするだけでも、簡単に動作させる事が出来ます。


出来たアプリケーションをチェックしてみたんですが、Webkit.dllやPython25.dllの他、色んなDLLが起動しています。
その割には、起動は まぁまぁ早いです。(代わりに、終了が遅い。自分のボロマシンだと2〜3秒程度待たされる)

Pythonコードを組み込む

さて、先のテンプレートアプリケーションに、Pythonを呼び出すコードを組み込んでみます。

「Resources」フォルダに「index.html」ファイルがあり、これがアプリケーションの外見を司りますので、一部いじりましょう。

index.html:

<html>
<head>
<title>hello Titanium</title>
<script type="text/python" src="test.py"></script>
</head>
<body style="background-color:#1c1c1c;margin:0">
<div style="border-top:1px solid #404040"><div style="color:#fff;;padding:10px">Welcome to Titanium</div></div>
<input type="button" onclick="test_call()" value="RUN"></input>
</body>
</html>

やっている事は、「RUN」という名前のボタンを設置し、それが押されたら「test_call()」メソッドを呼び出すというものです。


次に、「test_call()」メソッド本体を、Python言語で記述します。
これは、「test.py」という名前にしました。

test.py:

from winsound import *

def test_call():
	MessageBeep()

#test_call()

やっている事は、単にサウンドを鳴らすだけです。


再度「Launch App」でビルドして動かします。
6
6 posted by (C)wacky

「RUN」ボタンを押すと、「ポン」「ポン」と音が鳴り、ちゃんと呼び出されている事が判ります。

感想

恒例の利用しての感想です。

  • イメージ的には、バイナリ化+スクリプト言語で記述できるHTA(HTML Application)。
  • (終了は遅いけど)起動が早いのは、好感度アップ。
  • Titanium Developer本体は、プロジェクト管理だけの機能だけど、中途半端なものを付けられるくらいなら これで十分。

方言

近所の人と話していて、ちょっとした方言を教えてもらいました。

  • やっちし
    余計なお世話をする人とか、そういった行為の意味
  • ちっくし
    知○の足りない人とか


…よく考えると、方言って けっこうきつい表現が含まれているんですよね。
今の「常識」では考えられない差別用語もあるし。
そういうのを考えていると、「常識」って日々変わり続けるものなんだな。って思いますよね。

assertマクロのような実行関数行のトレース文字列表示を行う

C/C++言語だと、プリプロセッサマクロの #演算子 の文字列リテラル化機能を使って、実行行の文字列を表記するなんてマクロが簡単に書けます。
例えば、以下のように。

#define	COM_CHK(hr)	_com_chk(#hr, hr)

inline HRESULT _com_chk(const char* msg, HRESULT hr)
{
	System::Diagnostics::Trace::WriteLine(String::Format("{0} = 0x{1:X}", gcnew String(msg), hr));
	if(FAILED(hr)) throw gcnew COMException(gcnew String(msg), hr);
	return hr;
}

...
COM_CHK(m_graphBuilder->RenderFile(filename, NULL));
COM_CHK(m_videoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));

上のコードは、COM_CHK マクロで、囲った内部の呼び出しコードを、片方は文字列リテラル化、片方は呼び出した返値を渡して、トレース出力しちゃおうという代物です。
こうすれば、いわゆるエラーチェック付きデバッグプリントが簡単に実現できます。


で、C#でこのような機能を実現するには、どうしたら良いのか?という問題です。
色々と調べていたんですが、どうもうまく行きそうにない。


で、上のURLのコードをじ〜っと眺めていて、もう力技で作ってしまおう。と思いました。
以下が力技の例です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DirectShowLib;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using DBG = System.Diagnostics.Trace;

namespace Test03
{
    /// <summary>
    /// Geekなぺーじ : 自作ウィンドウに表示する
    /// http://www.geekpage.jp/programming/directshow/ivideowindow-3.php
    /// の、C#版みたいなもの。
    /// </summary>
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        IGraphBuilder m_graphBuilder = null;
        IMediaControl m_mediaControl = null;
        IVideoWindow m_videoWindow = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            m_graphBuilder = new FilterGraph() as IGraphBuilder;
            m_graphBuilder.RenderFile(@"F:\Wacky\hoge.wmv", null);
            m_mediaControl = m_graphBuilder as IMediaControl;
            m_videoWindow = m_graphBuilder as IVideoWindow;
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            COM_CHK(m_videoWindow.put_Owner(this.Handle));
            COM_CHK(m_videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings));
            COM_CHK(m_videoWindow.SetWindowPosition(0, 0, this.Width, this.Height));
            COM_CHK(m_videoWindow.put_Visible(OABool.True));
            COM_CHK(m_videoWindow.SetWindowForeground(OABool.True));
            m_mediaControl.Run();
        }

#region デバッグ用

        static Dictionary<string, string[]> s_stackFileArray = new Dictionary<string, string[]>();

        int COM_CHK(int hr)
        {
            StackTrace stkTrace = new StackTrace(true);
            StackFrame stkFrame = stkTrace.GetFrame(1);
            string fileName = stkFrame.GetFileName();
            if (s_stackFileArray.ContainsKey(fileName) == false) s_stackFileArray[fileName] = File.ReadAllLines(fileName);
            DBG.WriteLine(string.Format("0x{0:X} = {1}", hr, s_stackFileArray[fileName][stkFrame.GetFileLineNumber() - 1].Trim()));
            if (hr < 0) DsError.ThrowExceptionForHR(hr);
            return hr;
        }
#endregion

    }
}


上を実行すると、以下のようにデバッグプリント出来ます。

0x0 = COM_CHK(m_videoWindow.put_Owner(this.Handle));
0x0 = COM_CHK(m_videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings));
0x0 = COM_CHK(m_videoWindow.SetWindowPosition(0, 0, this.Width, this.Height));
0x0 = COM_CHK(m_videoWindow.put_Visible(OABool.True));
0x0 = COM_CHK(m_videoWindow.SetWindowForeground(OABool.True));


StackTrace(true) を呼ぶと、詳細なスタックトレース情報が取れるので、そこから呼び出し元のファイル名と行数を取得し、直接ソースコードを取得して、プリント出力に回す。という恐ろしく力技を使っています。


とはいえ、とりあえず、少々遅くても 呼び出しの動きが見たかっただけなので、これで良しとしますか。

よく知っているはずの知らない世界

ふと思い立って、実家から中学に通っていた道順を、自転車でふらふらとしてきました。


毎日通っていて、その当時は目をつむっても学校まで行けるのじゃなかろうか?という程 記憶していたのに、今になって辿ろうとすると、あっという間に迷い子になっていました。


あれ?そんなはずじゃなかったのに。


知らない道、知らない建物、知らない人。
だけど、時折 記憶と適合する店や、建物、樹木があったりして、ほっとする。
ここで、帰りにゲームしたんだよなぁ。とか、立ち読みしたよなぁ。とか。
面影も無いほど、綺麗になった遊歩道を辿る中に、何故か記憶していた柳の木を見つけたり。


そんなに変化するような町じゃないはずなのに、結構変わっているものなんですね。
記憶にあるはずの他の道も辿ってみようかな?と思った一日でした。

WebKitのビルドが出来た(for Windows)

先日のねたから、ずっとWebKitのビルドに挑戦し続けていましたが、何とかWebKitのビルドが出来ましたよ!
(再現できるか、全然自信が無いけど)

参考リンク

本家は、ここ。


日本語での参考リンクは、これあたりですかね。(多謝、多謝)


英語で役に立ったのは、以下でした。

ビルドに至るまでの道程

WebKit Nightly Buildsより、ソースファイルをゲットして展開します。
自分が使ったのは、以下のファイルです。


日本語参考リンクの助言に従い、以下を実施しました。

  1. WindowsSafariをインストールする。
  2. Visual Studio 2005のサービスパックを最新に更新
  3. KB918559などのHotfixを当てる
  4. cygwin-downloader.zipをダウンロードして展開し、setup.exeを実行して、Cygwinを更新。
  5. QuickTime SDKをインストール
  6. Windows Server 2003 R2 Platform SDKをインストール
  7. Visual Studio 2005を起動し、「ツール」→「オプション」から、「プロジェクトおよびソリューション」→「VC++ ディレクトリ」を開き、Windows Server 2003 R2 Platform SDKQuickTime SDKの各bin, lib, includeファイルの各パスを設定する。
    何を設定すれば良いかは、日本語参考リンクの各説明に書いています。
  8. WebKit Support LibrariesWebKit Auxiliary Libraryをダウンロード。
    (詳しくはsafari for windows, co-wiki, room1 - WindowsとCore Services DLLのページ参照)
  9. WebKit-r58638.tar.bz2 を展開し、展開先ルートに先ほどダウンロードした、WebKitAuxiliaryLibrary.zipとWebKitSupportLibrary.zipを配置。
    と、いいつつ、後で手動展開しました。(後述)
  10. コマンドプロンプトを起動し、カレントディレクトリを展開先ルートに合わせる。
  11. 次に、Visual Studio 2005のフォルダにある、vsvars32.batを実行し、コンパイラの実行パスを追加。
    (デフォルトでは、"C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat"にあります)
  12. WEBKITLIBRARIESDIRとWEBKITOUTPUTDIRの環境パスを手動設定する。(後述)
  13. 'bash[enter]'を入力して、Cygwinのシェルを起動。
  14. WebKit/WebKitTools/Scripts/update-webkit」を呼び出す。
  15. WebKit/WebKitTools/Scripts/set-webkit-configuration --debug」を呼び出す。
  16. WebKit/WebKitTools/Scripts/build-webkit」を呼び出す。
  17. 暫くすると、ビルドが終了する。
    (とかいいつつ、後述するように WebKit-r58638.tar.bz2 のファイルは一部修正しましたけど)
  18. WebKitTools/Scripts/run-safari」と打ち込むと、以下のようにビルドしたバージョンのSafariが起動します。
    1
    1 posted by (C)wacky
  19. ビルドバージョンかどうかは、Process Explorerでチェックすれば一目瞭然です。やった。
    2
    2 posted by (C)wacky


以降は、引っかかったポイントを幾つかメモします。
(とかいいつつ、日本語参考リンクの言い回しそのままですが)

ポイント:WEBKITLIBRARIESDIRとWEBKITOUTPUTDIRの環境パスを間違えるな

以下のWeb siteでも指摘されておられますが、ビルドして失敗した時、WEBKITLIBRARIESDIRとWEBKITOUTPUTDIRの環境パスが望ましい設定値になっているか、よくよく確認しましょう。


例えば、自分が使用したソースのルートパスが、以下の場合

F:\Wacky\Test\webkit\WebKit_

環境パスは、以下であるべきです。

set WEBKITOUTPUTDIR=F:\Wacky\Test\webkit\webkit_\WebKitBuild
set WEBKITLIBRARIESDIR=F:\Wacky\Test\webkit\webkit_\WebKitLibraries\win


自分は、この環境パス設定を間違えて、あらぬ場所にコンパイル途中のファイルを生成させてしまい、何度もリビルドを繰り返してしまいました。

ポイント:エラーが発生したら最初のBuildLog.htmを見よう

以下のWeb siteでも言及されていますが、ちゃんとBuildLog.htmを見ましょう。
しかも、最初にエラーになった奴を。


例えば、自分の場合、ビルドに失敗したので、BuildLog.htmを見たんですよ。
すると、以下のエラーメッセージが。

####### COMPILING 1 FILES USING AT MOST 2 PARALLEL INSTANCES OF cl.exe ###########
ThreadGlobalData.cpp
..\platform\ThreadGlobalData.cpp : error C2220: 警告をエラーとして扱いました。'object' ファイルは生成されません。
..\platform\ThreadGlobalData.cpp : warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
プロジェクト : warning PRJ0018 : 以下の環境変数が見つかりませんでした:


んん?と思って、ThreadGlobalData.cppを開いてみたら、以下の場所が見つかったんですよ旦那。

 71:    // This constructor will have been called on the main thread before being called on
 72:    // any other thread, and is only called once per thread 窶・this makes this a convenient
 73:    // point to call methods that internally perform a one-time initialization that is not

72行の文字化け部分をカットしたら、ちゃんとビルド出来たんですね。これが。
という訳で、BuildLog.htm重要です。

ポイント:Cygwinは、システムドライブのCygwinフォルダに入れましょう

これは、英語のWeb siteの言及を、英日機械翻訳を掛けて眺めていた+BuildLog.htmのエラーを見ていて気づきました。


自分は、Cygwinをとあるフォルダに突っ込んでいたので、ジャンクションを使って、「C:\Cygwin」フォルダにパスを貼り直しました。

ポイント?:WebKit-SVN-source.tar.bz2 はあまり お奨めしません

ビルドするソースの入手手段として、幾つか用意されているのですが、
http://nightly.webkit.org/files/WebKit-SVN-source.tar.bz2
は、正直 あまりお奨めできません。


WebKit Nightly Buildsのtar.bz2アーカイブか、SVNコマンドを使ったチェックアウト(svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit)が良いと思います。


何故かと言うと、2つあります。

  1. アーカイブファイルが500MB超ある。
    光速回線な人はどうでも良いのでしょうけど、Nightly Buildのtar.bz2が20MB程度なのを考えるとねぇ。私の型落ちマシンでは、展開にえらい時間を喰いましたよ。

  2. ACLが変になるので、いざファイルを削除する際、困る。
    これが一番大変でした。

    展開に使用したアーカイバも悪いのでしょうけど、生成されたファイルのACL権限がプロテクトな設定になるらしく、後で削除しようとすると「ファイルのアクセスが拒否されました」エラーが連発しました。

    しょうがないので、caclsコマンドでACLを追加して、フルアクセスにして、ファイルも大量なので一気に削除しようとすると反応が返ってこないので、少しずつファイルを削除するという苦行を味あわせてもらいましたよ。
    もう、二度としたくありません。はい。

ポイント?:WebKitAuxiliaryLibrary.zipとWebKitSupportLibrary.zipを手動展開する場合

本当は必要ないのでしょうけど、WebKitAuxiliaryLibrary.zipとWebKitSupportLibrary.zipを手動展開した際、突っ込むべきフォルダは、「WebKitLibraries\win」です。


これは、update-webkitスクリプトだっけを動かした際のメッセージを眺めていると判ります。
私の環境では、Cygwinで両ZIPをCURL?でダウンロードした後、配置する際に失敗しているようだったので、手動展開した次第です。

最後に

ここまで書いておいて何ですが、自分のビルド手順&ポイント事例は、これで正しいのかどうかよく判っていません。
本来なら仮想マシンを立ち上げて、検証を繰り返すべきなんでしょうけど、今日はビルドできただけで、もうお腹いっぱいです。

wxWebKitを使って、WebKitエンジン製の簡易なブラウザを作ってみる

最近、WebKitと その派生版が流行っておりまして、自分も色々と勉強中です。
で、WindowsWebKitを扱うのに便利なライブラリは無いかしら?と思って色々と調べていました。


で、現時点で、自分が理解した事を、簡単にメモしておきます。(嘘が入っているかも知れません)

  1. WebKitは外部からActiveXコントロール制御できない。
    どうやら商用でActiveXコントロール化した派生はあるようなんですが、WebKit自身はActiveXコントロール化されていない模様で、各種言語から CreateObject 等を使って外部から制御する事は出来ないようです。
  2. Windows版の内部実装は、COM実装されている模様。
    少なくとも、Windows版は AcitveXの基底技術である COMで実装されています。
    ただ、OLEオートメーションで必要なインタフェースを実装していないので、外部から制御できないと。
  3. WebKit技術を使ったライブラリは幾つかあるが、上記理由の為、実装が各ライブラリ専用に留まる。
    ライブラリ毎にWebKitが小分けになっているので、C#用のライブラリをセキュリティアップデートしたからと行って、QT用のライブラリの中身が入れ替わるという事は無いようです。
    イメージ的には、IEのライブラリはDLLに対するラッパー実装。WebKitのライブラリはスタティックLIB実装。って感じですかね。
  4. 派生ライブラリとしては、.NET用、wxWindows用、QT用、GTK用 等がある。
    ちなみに、各ライブラリ共 ほぼオレAPI化されており、互換性はあまり無いと思った方が良いと思います。
    (IEは、ActiveX化されているので、APIは ほぼ統一)


WebKitを調べる際、WebKitの外部制御のサンプル事例(Mac OS除く)が IEに比べて異様に少ないなぁと思ったのですが、通常だとC++言語+ソースコードを用意しないと手が出せない。各種ライブラリがオレ実装状態。じゃぁ、しょうがないなぁ。という感じですね。

上記状態からして、巷でよく見るように、WebKitIEを比べるのは意味が無いなぁ。と感じました。
実装形態が全く違う(汎用のIE、専用のWebKit)ので、速度やセキュリティに差が出るのは当然かなぁ、という感じです。

Windowsで使えそうな派生ライブラリ

で、話を戻しまして、Windows上でWebKitエンジンを簡易に使えるライブラリとして、どんなものがあるか少し調べてみました。
ちなみに、Pythonバインディング中心です。(他の言語は、あまり勉強していないので真面目に調べていません。ははは)


1.WebKitオリジナル
C++コンパイラを用意できるなら、WebKitの本家からソースコードをダウンロードしてきて、ビルド環境を揃えて、ビルド出来たら使えます。

正直難易度が高いです。


2..NET用ライブラリ
WebKit.NETという.NET用のライブラリを作っている所があります。


Windowsプログラマだったら、一番これが扱いやすいかな?と思います。
何しろ、ライブラリ一式をダウンロードした後、ファイルを展開し、アセンブリを参照して、フォームに WebKitコントロールを ぺたっと貼り付けるだけですからね。
APIも、IEを意識しているようで、かなり似せています。


3.Python用のwxWebKitライブラリ
まだプレビュー版ですが、wxWebKitというwxPythonWebKit専用ライブラリがあります。


おっPy派なら、多分これが扱いやすいかな?と思います。
とりあえず、Windowsインストーラー形式でライブラリが配布されているので、ぽんぽんインストールして、少しスクリプトを書くだけで使えますからね。
今回のネタは、これを使って簡易ブラウザを作っています。


4.Python用のpyWebKitGtkライブラリ
これも開発中のようですが、pyWebKitGtkというpyGTK用のライブラリがあります。


スクリーンショットを見るとWindowsでも扱えるようなのですが、ソースだけの配布なので少々難易度が高めです。
Wikiメーリングリストを眺め回してみたんですが、開発者の方々はLinuxメインのようで、Windowsポートについてあまり言及している箇所が見つからなかったんですね。


5.QT用のWebKitライブラリ
QT用にもWebKitライブラリがあるようです。


が、まだ試していません。
QWebView クラスの説明では、WebKit云々と書いてあるので、多分使えると思います。

wxWebKitをインストールする

長い話でしたが、wxWebKitを使って、Pythonで簡易ブラウザを作ってみましょう。

今回は、Python 2.6を入れた後、以下のWindowsインストーラを入れました。

  • wxPython2.8-win32-unicode-2.8.10.1-py26.exe
  • wxWebKit-win32-wx2.8-Py2.6-preview1.exe


これを入れた後、Pythonを立ち上げて 以下を手打ちしてみて下さい。

$ python
Python 2.6.1 (r261:67517, Dec  4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> import wx.webview
>>> app = wx.PySimpleApp()
>>> frame = wx.Frame(None)
>>> w = wx.webview.WebView(frame)
>>> w.LoadURL("http://www.google.com")
>>> frame.Show()
True
>>> app.MainLoop()

以下のウィンドウが表示されたらOKです。(ウィンドウが前面に出ないので、タスクバーをよく見てください)
1
1 posted by (C)wacky

結構簡単ですよね?

wxWebKitを使って、簡易ブラウザ

では、次に簡易ブラウザを作って見ましょう。
以下にコード例を示します。

# -*- coding: utf_8 -*-  
import sys
import pdb
import wx
import wx.webview

class MyWindow(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, u"WebViewを使ったWebブラウザ", size=(640,400) )
        
        box = wx.BoxSizer(wx.VERTICAL)
        sz1 = wx.BoxSizer(wx.HORIZONTAL)
        if True:
            self.urlLabel = wx.StaticText(self, -1, "URL:")
            self.urlText  = wx.TextCtrl(self, -1, "http://www.google.com", size=(300, 20) )

            self.goButton = wx.Button(self, label="GO!")
            self.Bind( wx.EVT_BUTTON, self.OnSubmit, self.goButton )
            
            sz1.Add(self.urlLabel, 0, wx.LEFT, 20)
            sz1.Add(self.urlText,  0, wx.LEFT, 20)
            sz1.Add(self.goButton, 0, wx.LEFT, 20)
        
        self.web = wx.webview.WebView(self, size=(300, 400))
        self.web.Bind(wx.webview.EVT_WEBVIEW_LOAD, self.OnLoad)
        
        box.Add(sz1, 0, wx.EXPAND)
        box.Add(self.web, 1, wx.EXPAND)
        
        self.SetSizer(box)
        self.SetAutoLayout(True)
        box.Fit(self)

    def OnSubmit(self, event):
        print "set URL:", self.urlText.GetValue()
        self.web.LoadURL(self.urlText.GetValue())
    
    def OnLoad(self, event):
        print "load state:", event.GetState()
        if event.GetState() == wx.webview.WEBVIEW_LOAD_DL_COMPLETED:
            o = self.web.GetMainFrame()
            html_code = o.GetPageSource()       # HTML code
            print type(html_code)
            print html_code.encode("cp932", "ignore")

if __name__=='__main__':
    app=wx.PySimpleApp()
    frame=MyWindow(parent=None,id=-1)
    frame.Show()
    app.MainLoop()

上記コードを実行すると、以下のようになります。
2
2 posted by (C)wacky


たった、これだけのコードで、簡単なブラウザが作れました。

最後に

いかがでしたでしょうか?
WebKitを素のままで使うのは少々骨が折れますが、スクリプト言語サポートを介してなら、比較的簡単に制御できます。


ちなみにここまで書いておいて何ですが、リンクするだけでOKなWebKitライブラリのバイナリ版無いですかね?
ソースコードから何度もビルドしようとしているんですが、全然うまく行かないです。orz

2010/05/16: 追記

WebKitは外部からActiveXコントロール制御できない。」の所ですが、どうも「ActiveX登録すれば OLEオートメーションによる制御が可能」のような感じ。
register serverしたら、もしかしたらうまく出来るのかなぁ?

[python] HTMLをWebDAV経由でiPod touchに送って、オフライン閲覧しよう

今更ですが、最近iPod touchを購入しました。
何の為かというと、

  • 先日長距離出張がありまして、本を読むのだけじゃヒマになりそうだなぁ。というのが発端。
  • 机に向かっていると、段々 お○が痛くなるので、ベッドや安楽イスでネットでカウチをしたいなぁ。というのが本音。
  • 値段をチェックすると、結構安い事に気付いた。というので決定。

という次第です。
ちなみに、iPhoneにしなかったのは、常時ネット接続すると自分で歯止めが効かなくなりそうだな。と思ったのです。


購入してから暫くいじってみて、確かにユーザーインタフェースが優れているなぁと感心しました。
後、ごてごてしていない機能デザインも良いですね。
自分には逆上がりしても真似出来ないですね。(周りの要求に屈しやすい私)

オフラインなiPod

とまぁ、前振りはさておいて問題です。
iPod touchはネットワーク環境として Wi-Fiが使える訳ですが、外に出ると このWi-Fiって、意外と使える所が少ない訳です。
そういう人の為に、PHSや携帯のネットワークに繋ぐアダプタが売られているようなんですが、自分はそこまでネットワークへの強い渇望がある訳じゃないんですね。


会社への行き来で空いたヒマな時間を潰せれば十分なんです。
だから、例えばオンライン状態(家とか)で、ちょこちょこコンテンツをダウンロードしておいて、ヒマな時間で見るのでも(今は)十分事足りるんですね。


ニュースサイトとかは専用アプリで、オフラインでも読めるものがあったので、早速使っているのですが、問題は個人のWeb site。
自分は、定期的にいつも見ている個人Web siteがあるので、これをオフラインで見られると良いだろうなぁ。と思いました。
が、標準のWebブラウザは、お気に入りの保存程度しかない。
手動でWebをHTMLに落としおいて iPod touchへUSB経由でコピーし、後で見る? …面倒でやってられません。


何か方法が無いか?と思って調べてみました。


・候補1.「Read it Later」などの後で読むサービスを使う
以下に示すように、「Instapaper」と「Read it Later」が有名なようです。

無料版をちょっと試してみたんですが、

  • 「読んだ」ボタンを押すとブックマーク?が消える。
  • 残したブックマークも、ブックマークした時点の情報しか残ってないので、定期的に見る事が出来ない。

という自分的使い方に沿わない問題がありました。
何か他の方法がある気もしたんですが、Blogでの体験記事を見る限り、自分の目的とは別の使い方をされているようで…。これ以上の調査を諦めました。


・候補2.「iWebSaver」と「Web2Touch」でオフラインなブックマークを使う
以下に示すように、ブックマークにコンテンツ情報を記録する事で、オフラインでも閲覧できるようです。

見つけた時は、「キタ、コレ!」と思いました。
が、少し問題が。

  • 一々 iTunes を立ち上げるのが面倒(マシンが古くて、iTunesの起動がもっさりなので)。
  • USB接続なんぞ面倒でしたくねぇ(毎日コネクタ挿抜なんて怖いよぅ)。

という個人的わがままです。(ヤレヤレ

AirFilesとWebDAV

何か良い方法は無いかな?と思ってWebサーフィンしていたら、ふと、ファイルをWi-Fi経由で送り込んで iPod touch上で見る事ができるソフトがある事を思い出しました。

そういえば、HTMLヘルプを iPod touchで読みたいが為に、AirFiles というソフトを購入していたのだった。


これを使うと、WebブラウザWebDAVクライアントを使って Wi-Fi経由で iPod touchに送れるんですね。


これを思い出した結果、

  1. HTMLファイルを定期巡回してローカルにダウンロード
  2. WebDAVクライアントを使って、ダウンロードしたHTMLファイルを iPod touchに転送
    (Webブラウザを使わないのは、自動化が面倒そうだから)
  3. iPod touchのAirFilesで、HTMLファイルをオフライン閲覧

という自分的解決方法を思いつきました。

WebDAVを使った自動転送の実装

大分寄り道しましたが、いよいよ実装です。
今回は、わたなべさんのBlogで公開されている PythonWebDAVクライアントライブラリを、利用させてもらう事にしました。ありがとうございます。


そのままでは使う事が出来なかったので、以下のWeb siteの資料を眺めつつ、勝手にリファインさせて頂きました。


改造したコードと、それを使った自動化転送用のスクリプトとバッチファイルは、↓ここに置いています。ご自由にどうぞ。

プログラムの説明

上記の圧縮ファイルには、以下の3ファイルが入っています。

  • gethtml.py
    Webショートカットを読み取って、WebからHTMLファイルにダウンロードするスクリプト
  • filesys.py
    ローカルのHTMLファイルを、WebDAVを使ってiPod touchのAirFilesストレージにアップロードするスクリプト。(わたなべさんのソースを弄っています)
  • up_air.bat
    上の2つを連動させるバッチファイル。単に連続して呼び出しているだけです。


以下のように処理を行う流れを想定しています。

  1. 定期的に巡回したいWeb siteを、Webショートカットファイル(お気に入りの実体ファイル)として、適当なフォルダに配置する。
    仮に、'C:\LINK'フォルダに置くとします。
  2. gethtml.pyを呼び出して、Webショートカットを入れたフォルダを指定し、WebからHTMLファイルをダウンロードして指定フォルダに保存する。
    例えば、「python gethtml.py C:\LINK\* C:\HTML」とすると、'C:\LINK'にあるWebショートカットファイルを順次、'C:\HTML'フォルダに保存します。
  3. iPod touchから AirFiles アプリを起動して、タイトル画面の「Wi-Fi 情報」が出た所で、一旦止める。
    (AirFilesのサイト画像より)
  4. filesys.pyを呼び出して、ローカルのHTMLファイルを iPod touchの AirFilesの管理ストレージにアップロードする。
    例えば、AirFilesの起動メッセージが「http://192.168.2.103:8080」とあれば、「python filesys.py --upload http://192.168.2.103:8080/Myfiles/ C:\HTML\*.htm」とすると、'C:\HTML'フォルダの全てのHTMファイルを iPod touchに転送します。

終わりに

  • まずは作ってみたので、これで どれだけ使い物になるか暫く使ってみようかな、と。
  • 正直、リッチなHTMLでなくてもOKなので、w3mとかLynxを使って、テキストに落としたものを見るようにしようかなぁ。
  • WebDAVクライアントのパッチ修正なんですが、非常にテキトーです。
  • AirFilesのストレージは、WebDAVから見ると、/Myfilesの下に既定フォルダが並んでいる点にご注意を。
    /(ルート)の直下にファイルを置くと、AirFilesの画面に何も現れない事になります。
  • iPhone4.0とかやっているけど、スクリプト言語をアプリに登録してくれないかしらん?
    ○獄すりゃOKのようですけど。
  • filesys.pyは、FTPクライアントも実装しているので、FTPサーバーを持つiPodアプリ(iComicとか)に応用が利くかも。