Firefox拡張入門第4回(某占いサイトをスクレイピング)
Firefox拡張はスクレイピングの最終兵器です。
今日は、某占いサイトをスクレイピングして、自分の星座のお告げを抜き出します。
某占いサイト
スイーツ(笑)テーブルレイアウトです。
先にFirebugで、抜き出したいところのXPathを調べておきます。
個人的にCSSセレクタのほうが好きなので、XPathとCSSセレクタの対応表をあげておきます。
- John Resig - XPath and CSS Selectors
- Latest topics > CSS3セレクタとXPathでの表現の対応表 - outsider reflex
- Latest topics > getElementsByなんちゃら の代わりにXPathを使う - outsider reflex
Firefox拡張入門第3回(全てのタブからはてダのリンクを作る)
それでは実際にFirefox拡張を作ってみましょう。
全てのタブの、アドレスとタイトルを取得して、はてなダイアリーのリンクにするサイドバー拡張を作ります。
タブの情報は、メインウィンドウのwindow.gBrowser変数に入っています。タブブラウザ用コード - MDC
さて、サイドバーとメインウィンドウとではwindowが違います。
要素 - サイドバーの
要素 <- いまここ 要素 - Webページを表示する
要素 - ...
- Webページを表示する
- サイドバーの
サイドバーのwindowからメインウィンドウのwindowを取得するには、3種類の方法があります。
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebNavigation) .QueryInterface(Components.interfaces.nsIDocShellTreeItem) .rootTreeItem .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIDOMWindow);
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); var mainWindow = wm.getMostRecentWindow("navigator:browser");
var mainWindow = getTopWin();
getTopWinは chrome://browser/content/utilityOverlay.js が定義しています。他にも便利な関数が入っているので一読おすすめ。
では実装しましょう。
続きを読むFirefox拡張入門第2回(MozReplでFirefoxを探検しよう)
windowオブジェクトの入れ子について
いつもwindow.alertなどで見る"Webページのwindow"のさらに上には、ブラウザ全体を支配する"XULのwindow"があります。
もちろんWebページ側からは触れませんが、Firefox拡張ならXULのwindowをいじれます。
ブラウザはこのようになっています。
要素 - サイドバーの
要素 要素 - Webページを表示する
要素 - ...
- Webページを表示する
- サイドバーの
そして
これはHTMLでiframe要素がそれぞれにwindowを持っているのと同じです。
詳細はこちらchrome コードでウィンドウを取り扱う - MDC
Firefox拡張入門第1回(開発の準備)
開発者必携ツール
- DOM Inspector 右クリックメニューを拡張したいんだけどデータどこにあんねん、というとき便利。
- QuickRestart ブラウザを再起動して拡張プログラムをリロードするとき便利。
- Console2 Javascriptコンソールの強化版。エラーメッセージをよりわけできて便利。
- SQLite Manager ブラウザ内蔵のSQLite RDBMSをGUIで操作できて便利。
- Venkman JavaScript Debugger Javascriptデバッガです。わりと便利。
MozReplも必携です。Firefox内部のJavascriptインタープリタにtelnet接続できます。
私の開発の流れは、
- サイドバーで動く拡張プログラムを作る
- サイドバーをパカパカしてプログラムをリロードして動作確認
- 小さなプログラムの断片は、MozReplでインタープリタに打ち込んで動作確認
- 安定して動いたらプログラムを現場に移す
です。
プログラムを変更するたびにブラウザを再起動なんて遅くてやってらんないので、できるだけサイドバーパカパカで済ませます。
Firefox拡張簡単キット"マッチFOX"
Firefox拡張を作りたいけど、ややこしくて手がつけられない、そんなあなたに・・・!
簡単キット"マッチFOX"。Ruby on Rails みたいに、scaffold(骨組み)を作ってくれます。
この骨組みには、はてなブックマーク拡張から取り出したエッセンスが入っていて、
その道のプロフェッショナルと同じスタートラインから開発できます。
- 人柱版(RC2)
- 正式版
- https://addons.mozilla.org/ja/firefox/addon/47147/
- Firefox3が必要です。
- XP, Vista, Linuxで動作確認。
"どぼん on BiwaScheme"をJavascriptに移植した
zickさん作の"どぼん on BiwaScheme"をJavascriptに移植した。
元が美しいSchemeコードだったので流れるように移植できた。
これだけ複雑なトランプゲームをBiwaSchemeで書いてしまうzickさんはすごい。
安易に多次元配列を使わないところもいい。
その上、Cardクラスな抽象化をせずにベタ書きしてて驚いた。
こういう芸当は、脳内に積めるスタック量が並外れてないとできないと思う。
恐るべし。自分だったら脳みそが鼻からでてしまう。
ちょっとした改善点
- CSS Spritesで画像のロードを高速化。
- IE7、Firefox3、Opera9で動作確認。
- Google ガジェット化。http://hosting.gmodules.com/ig/gadgets/file/108238819228059208534/dobon.xml
それにしても・・・10年前はトランプゲームを書いた日にゃシェアウェアにしてお金がとれたよ。
いい世の中になったもんだ。
Gauche-XMPPのリファレンスマニュアル
Class: <xmpp-connection> サーバへのXMPPコネクションを保持するオブジェクト。以下の公開スロットがあります。 stream-id: 接続時にサーバが提示したXMPPストリームのid。文字列。 features: 接続時にサーバが提示した<features>の内容。SXML。 Condition: <xmpp-error> サーバから接続が切られた場合や、サーバの返したXMPPレスポンスのフォーマットが正しくない場合に 投げられるコンディションです。<error>を継承します。 Function: xmpp-connect host &keyword port jid-domain-part サーバに接続します。 portで接続ポートを指定できます。デフォルトは5222です。 jid-domain-partで例えば"gmail.com"と指定することで、Google Talkのような 「サーバは"talk.google.com"だけどXMPPアドレスは"romeo@gmail.com"」、という場合に対応できます。 Function: xmpp-disconnect conn 切断します。 Function: call-with-xmpp-connection host proc &keyword port jid-domain-part 高水準の便利関数で、サーバーに接続し、与えられた手続きを呼び、切断します。 hostへの接続が成功したら、procが引数を1つ、<xmpp-connection>のインスタンスをとって、呼ばれます。 procから返ったときに切断され、procの返り値がcall-with-xmpp-connectionから返されます。 例外がなげられたら、その例外がcall-with-xmpp-connectionから外へでる前に切断されます。 キーワード引数はxmpp-connectionと同じです。 Function: xmpp-receive-stanza conn stanzaを受信しSXMLで返します。受信するまで処理がブロックします。 Macro: xmpp-iq (conn &keyword id to type) body Info/Query stanza <iq ...>...</iq> を送ります。 id IQの id属性の文字列。 to IQの to属性の文字列。宛先です。 type IQのtype属性の文字列。デフォルトは"get"です。 body IQの内容のSXML。 例えばxmpp-bindは以下です。 (xmpp-iq (conn :id "bind_2" :type "set") `(bind (|@| (xmlns "urn:ietf:params:xml:ns:xmpp-bind")) (resource ,resource))) Macro: xmpp-iq-query (conn &keyword id to type xmlns node) body IQ stanza <iq ...><query ...></query></iq> をxmpp-iqより簡単に送れます。 id to type は xmpp-iqと同じです。 xmlnsはqueryのxmlns属性の文字列。 nodeはqueryの node属性の文字列。 例えばxmpp-roster-addは以下です。 (xmpp-iq-query (conn :id "roster_2" :type "set" :xmlns "jabber:iq:roster") `((item (|@| (jid ,jid) (name ,name)) (group ,group)))) Function: xmpp-discover conn &keyword to type node Service Discovery IQを送ります。 to type node はxmpp-iq-queryと同じです。 Function: xmpp-registration-requirements conn アカウント登録に何が必要かを問うIQを送ります。 Function: xmpp-register conn username password name email アカウント登録するIQを送ります。 username 登録するユーザ名の文字列 password 登録するパスワードの文字列 name 登録する本名の文字列 email 登録するEメールアドレスの文字列 Function: xmpp-cancel-registration conn アカウント登録を削除するIQを送ります。 Function: xmpp-change-password new-password アカウントのパスワードを変更するIQを送ります。 new-password 新しいパスワードの文字列 Function: xmpp-auth-select-mechanism conn mechanism 認証方法を選択するIQを送ります。 Function: xmpp-auth-requirements conn username 認証要求するIQを送ります。 Function: xmpp-bind conn resource リソースバインドIQを送ります。 resource リソースの名前の文字列。"Home"や"Office"など。 Function: xmpp-session conn セッションセットIQを送ります。 Function: xmpp-presence conn &keyword to type status show priority プリセンス <precense .../>を送ります。 to presenceの to属性の文字列。宛先です。 type presenceの type属性の文字列。 status presenceの status属性の文字列。状態です。 show presenceの show属性の文字列。 priority presenceのpriority属性の文字列。 Macro: xmpp-message (conn &keyword id to type lang) body ... メッセージ <message ...><body>...</body>...</message>を送ります。 id messageの id属性の文字列。 to messageの to属性の文字列。宛先です。 type messageの type属性の文字列。デフォルトは"chat"です。 lang messageのxml:lang属性の文字列。 Function: xmpp-request-subscription conn to 相手に友人登録をリクエストするプリセンスを送ります。 to 相手の宛先。 Function: xmpp-approve-subscription conn to 相手を友人登録するプリセンスを送ります。 to 相手の宛先。 Function: xmpp-unsubscribe conn to 相手を友人登録解除するプリセンスを送ります。 to 相手の宛先。 Function: xmpp-cancel-subscription conn to 相手からの友人登録のリクエストを拒否するプリセンスを送ります。 to 相手の宛先。 Function: xmpp-get-roster conn 自分のRoster(友人リスト)を取得するIQを送ります。 Function: xmpp-roster-add conn jid name group 誰かを自分のRosterに追加するIQを送ります。 jid その人のXMPPアドレス name その人につける名前 group その人を加えるグループ Function: xmpp-roster-remove conn jid 誰かを自分のRosterから削除するIQを送ります。 jid その人のXMPPアドレス Function: xmpp-get-privacy-lists conn 自分のプライバシーリスト全てを取得するIQを送ります。 Function: xmpp-get-privacy-list conn name 自分のnameというプライバシーリストを取得するIQを送ります。 name プライバシーリストの名前 Function: xmpp-auth conn username password サーバが提示する認証方法から適当なものを自動的に選択して認証します。 digest-md5認証を最優先し、次にplain認証、anonymous認証を選びます。 username ユーザ名です。 password パスワードです。 Function: xmpp-sasl-digest-md5 conn username password digest-md5認証します。 Function: xmpp-sasl-plain conn username password plain認証します。 Function: xmpp-sasl-anonymous conn anonymous認証します。
xmpp-message が関数じゃなくて、マクロなのはなんで?
関数だとキーワード引数が後ろに来てしまうのを嫌ったからです。
(xmpp-message conn "hello, world" :to "juliet" :type "chat")
よりも
(xmpp-message (conn :to "juliet" :type "chat") "hello world")
のほうがいいでしょ?
xmpp-message が本文の後に更に引数を取れるのはなんで?
XEP-0071:XHTML-IMに対応するためです。こう使います。
(xmpp-message (conn :to "juliet" :type "chat") "太字だよ" '(html (@ (xmlns "http://jabber.org/protocol/xhtml-im")) (body (@ (xmlns "http://www.w3.org/1999/xhtml")) (p (@ (style "font-weight:bold")) "太字だよ"))))