AutoFollowersBlocker

GAE 上で動作し, cron で呼び出されて, twitter アカウントの follower を監視し,
プロファイルの文字列によって自動ブロッキングをするスクリプトを作成した.
きっかけは,昔むかし,山のように spammer からフォローされまくって,鬱陶しかったため.
当時の記事はこちら → twitterのspammerのfollowが多い

で,作ってみたのが, twitter を OAuth 認証でアクセスするためのクラス twit_oauth.py
そして,呼び出し元の AFBsample.py
いずれも分量が多いので,ソース自体はリンク先を参照されたい.

また,GAEで使うためのyamlファイルもついでに貼り付けしておく.

application: afb-sample
version: 10
runtime: python
api_version: 1

handlers:
# handling mode
- url: /cron
  script: AFBsample.py
  login: admin
# viewer mode
- url: /.*
  script: AFBsample.py
cron:
- description: polling job
  url: /cron
  schedule: every 5 minutes

さてこれで,次の4つを GAE へ放り込めば動く.
GAE の使い方については,web を参照されたいが,以前に hadacchi が調べたメモもある → twitterのspammerのfollowが多い
これでも,多少は参考になるかも知れない.

  • AFBsample.py
  • twit_oauth.py
  • app.yaml
  • cron.yaml

さて,今回のハマりポイントは,呼出 URL による処理の振り分けだった.

handlers:
# handling mode
- url: /cron
  script: AFBsample.py
  login: admin
# viewer mode
- url: /.*
  script: AFBsample.py
application = webapp.WSGIApplication([
    ('/cron', AutoFollowerBlocker),
    ('/', AFBview)
    ])

def main():
    wsgiref.handlers.CGIHandler().run(application)

当初は app.yaml の url 行を修正すれば呼び出し URL に応じて処理を振り分けできると思っていたが,
呼び出される側の python スクリプト内の webapp.WSGIApplication() の意味に気付いていなかった.
こいつの引数は,長さ 2 のタプルのリストであるが,タプルの第 1 要素は呼び出しURLになっていて,
ここでも呼び出し URL に応じて処理クラスを振り分けできる.
きちんと GAE の処理を読んでいないが,多分 app.yaml による振り分けは login 行におけるパーミッション制御や,
スクリプトファイルを分けることにより,クロスサイトスクリプティングみたいなアタックに対してある程度の
対処をしたい場合などに使うのが良いのかも知れない.

今回の構成では,
http://pjname.appspot.com/ へのアクセスで前回の実行結果を表示し,
http://pjname.appspot.com/cron へのアクセスでフィルタを手動実行する.

他の工夫としては,運用面で使い易くするため,自動 BLOCK 後に手動で UNBLOCK したユーザは対象から除外するようにしたり,
AND/OR 検索で重複マッチを走らせないようにしたり,
空フィールドに対して None が返却されるので事前に置換しておいたり,(デバッグの時にはjsonファイルを直接食わせる関係から,
マッチ関数内にもNoneの処理は残しているが…)
といった小細工は少ししてみた.

今後の課題としては,プロファイルを 1 call で 100 id 分まで抜ける API を見落としていたことが
分かったので,この API へ対応させた上で, follower が 10000 を越えるユーザでも TwitterAPI の
呼出制限にかからないよう初期化する実装を行なうことがある.
と難しく言ってみたものの,既チェック ID をパスするロジックなので, API の回数制限にかかる手前で
ループを break させてしまえば良いだけである.

参考にした web site は, Python アプリケーション設定 - Google App Engine - Google Code などの GAE のオンラインドキュメントと,
REST API Resources | Twitter Developers などの Twitter のオンラインドキュメントに加え,
前回までの記事 twitterでspammerのfollowを自動block 及び twitterのspammerのfollowが多い 内で参照している各ページである.

twitterでspammerのfollowを自動block

-- 追記2
ごめん,バグあった.文字列操作まわりのencodingがかなり怪しい.
空の時,Noneが入ってくるのは空文字列に置き換えるべきか.

-- 追記
きっと誰も AND/OR 検索を実装してくれないので,実装した.
ついでに, twit_oauth.py を更新して,フォロワだけでなくフォローしてる人の一覧も取れるようにした.

先の記事twitterのspammerのfollowが多いでも書いた,spammerのキーワード抽出について.
GMail からの PUSH 通知をトリガとした動作がうまく実装できなかったので (なぜか python2.5.xでは,imaplib2 がうまく動かない)
とりあえずトリガーは何も考えてません.cron でも,IMAP/IDLE でも,好きに実装してください.

twitter を変なライブラリなしで OAuth 認証で動かすクラスは,こんな感じで実装してます → twit_oauth.py
で,こいつを使って,下記のように使うとスパムフィルタのできあがり.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import simplejson,re
from twit_oauth import twit_oauth

__KEYWORDS = [(re.compile(u'キーワード1'),),
              (re.compile(u'キーワード2-1'),re.compile(u'キーワード2-2'))
             ]

# プロファイルリスト取得関数
def getProfiles(followers,pobj):
    profiles = {}
    for f_id in followers:
        profs=simplejson.loads(pobj.callAPI('profile',`f_id`))
        if profs['name']==None: name=''
        else: name=''.join(profs['name'].split('\n'))
        if profs['description']==None: desc=''
        else: desc=''.join(profs['description'].split('\n'))
        profiles[`f_id`]=(name,desc)
    return profiles

# テキストマッチ関数
def filterByKeys(profiles):
    fil_list = []
    for (id,prof) in profiles.items():
        # __KEYWORDS のいずれかの要素1つでも合致すればブロック (OR)
        for keys in __KEYWORDS:
            fil_list.append(id)
            # __KEYWORDS の1要素の中の,全てのマッチが成功すればブロック (AND)
            for k in keys:
                if not k.search(prof):
                    del fil_list[-1]
                    break
            # 重複登録回避
            if len(fil_list) != 0 and fil_list[-1] == id: break
    return fil_list


pobj= twit_oauth('xxxxxxxxxxxxxxxxxx','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
                 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')


# 自分の username を入れて,フォロワーを取得
followers = simplejson.loads(pobj.callAPI('getfollowers','username'))
# フォロワーのプロファイルを取得
profiles  = getProfiles(followers,pobj)
# キーワードマッチでフィルタ対象を取得
fil_list  = filterByKeys(profiles)
# ブロック
for fid in fil_list:
    print pobj.callAPI('block',fid)
# report_spam 自動処理で報告してしまうので,非推奨
# for fid in fil_list:
#    print pobj.callAPI('report_spam',fid)

report_spam を呼んでないのは,巻き添えレポートを防ぐため.
キーワードに絶対の自信があれば,使ってください.
and検索,or検索したい場合は,k.search(prof) の所を工夫してください.
実装済.

twitterのspammerのfollowが多い

級にspammerが来始めたので,なんか炎上してた人をフォローしたせいか,大手画像サイトとかをフォローしたせいだろうなぁ.
で,私のfollowerリストから更に他の人に飛び火すると悪いので(もう遅いかも知れんが…),一旦非公開アカウントにしました.
spammerの自己紹介や行動には,一目見て分かるほど特徴が沢山あるので,非公開にしているうちに,自動blockするスクリプトを作ることにした.
これまでの経験上,誰かが私をfollowするのは,頻度が高くても1人/週程度なので,1週間を目処に解決を目指そう.

前提

  • 今借りているレンタルサバ上でwebに溢れているサンプルコードを動かそうとすると,モジュールが足りない
  • pythonのモジュールは,同じディレクトリに置けば動かんこともないが,twitter関係の操作に必要なモジュールを1から入れようとすると,依存関係のため入れるべきモジュールが多い上,それぞれのimport文に対応するよう配置しないといけないので大変すぎる.
  • 自宅PCは最近は1~2回/週しか立ち上げないので,それではspammerのやりたい放題

つーことで,新たな常時起動しているサバを用意するか,コードをある程度自作する必要があることが分かった.
とか思考を全部書いていくと時間が足りないので結論だけ書く.
Google AppEngineでpythonコードを動かすか,標準モジュールだけでpythonコードを動かすかの両睨みができる方法を取ることにする.
具体的には,標準モジュールだけでTwitter APIを操作できるようにしながらも,GAEの開発環境は用意し呼出し部は2パターン作った.

で,cronを使うよりも,twitterでfollowされる度に飛んでくる通知メールをGMailで受け取って,それをトリガーに動作させてみたいと思い,GAEに挑戦することにした.
追記: GAEだもの,GMail くらい直接触れるでしょ,なんて思い込みがあったが,触れないことが分かった.オーノー

GAEについて

pythonしか試していないのでpythonのことを書く.
Google AppEngine より,登録してSDKを落とす.
Windows版はmsiファイル,Linux版はただのzipファイル.
Win版は,C:\Program Files (x86)\Google\google_appengineへインストールされる.Linux版は,unzipして展開するだけ.
python2.5.x でないと動かない.

$ python (PATH)dev_appserver.py demos/guestbook

と実行すれば,サンプルが動作する.

guestbookと同じように,app.yamlとそこから呼び出されるpyファイルを配置すればOK.
制限をかけたい場合は,app.yamlの制限したいscriptを定義しているscript行の下あたりに,login: required (Googleアカウントでログインしてないとダメ) とか, login: admin (GAEの該当プロジェクトの管理者権限がないとダメ) とか書く.
GAEへアップロードするには,

$ python appcfg.py update project_name

とかする.
アクセス先は GAE の dashboard の application settings にあるが,http://application_name.appspot.com とかだと思う.
サンプルみたいに wsgiref.handlers.CGIHandler().run(application) で呼び出してもいいが,デバッグしたい時は,from google.appengine.ext.webapp import utilとインポートしておいて,util.run_wsgi_app(application)とすると,ブラウザ上にデバッグメッセージが表示される.
どうせ開発環境では,dev_appserver.pyを呼び出している窓にも同じメッセージが表示されるけど.
詳しくは,ユーティリティ関数 - Google App Engine - Google Codeとかを参照のこと.
あと,simplejsonとか,ちょっと欲しいモジュールは入っていたりするけど,oauthtwitterとかニッチなのはない.
外部ファイルからクラスをインポートしたい時は,同じフォルダにpyファイルを置いてimportすれば,開発環境では動く.GAE上では試してないので不明.

twitterAPIについて

仕様がよく変わるので,公式の最新のもの(英語)Documentation | Twitter Developersの REST API を見た方が早い.
BASIC認証はもう使えないらしいので,OAuth認証を使う覚悟をする.
情報取得系はGETで叩き,情報更新系はPOSTで叩くRESTful I/F.
応答はJSONかXML.
アクセストークンの発行が死ぬほど面倒くさいので,頑張る.私は,やる夫と Python で学ぶ Twitter の OAuth - YoshioriのBlogを参考にした.
どうせReadもWriteもやりたくなるので,Read/Writeは少なくともつけておく.
QUERYをトークンをキーに符号化したものを署名としてHTTPヘッダへ埋め込み,肝心のQUERYは上記の通りGETかPOSTで投げるので,二重に必要なことを忘れない.

で,上に記載のやる夫と Python で学ぶ Twitter の OAuth - YoshioriのBlogのソースコードを改変して作ったのがこんなクラス → py_twit.py 更新しました → twit_oauth.py
無駄に書いてるimportとかはそのうち消します.
なお,screen_nameをuser_idとする場合,idは文字列で渡すこと.
また,statuses/updateは同じ発言を2回書くと403を返す,など応答については各々調べること.

あんま関係ないが,pythonのこと調べてると,大学時代の同級生がたいてい出てくるので,よくビビる.
今回の案件では,コードの美しさというよく分からん評価軸について語っていたので,反映しなかった.

weblogの記事をSQL叩いて修正

前のblogが,何故か管理者ページから更新できなくなってしまったので,mysqlを勉強した.

update db_name set key=value where condition1;

where句で指定するエントリの特定キーだけアップデートできるんだ,と分かって安心した.
レンタルサーバ上で日本語の修正をするのは面倒そうだが,公開/非公開とか,日付変更とかなら問題ない.
日本語修正する場合は,ファイルからのリダイレクトでコマンド実行してやれば,なんとかなりそうな気がする.

VirtualBoxへUbuntu11.04

VirtualBoxも,Ubuntuも,かつて使っていたソフトなりOSであるが,すっかり使い方を忘れてしまった.
ハマったポイントを改めて書いておく.

  • Ubuntu serverを入れる場合,日本語を選択すると後で言語設定をやりなおすハメになるので,Englishを選んでおく方が無難.
    X入れる場合は気にしなくていいけど.
  • インストールが終わったら,まずはGuest Additionsをインストールすること.
    具体的な手順は,

    1. ゲストOS起動
    2. デバイス>Guest Additionsをインストール
    3. sudo mount /dev/cdrom /mnt
    4. sudo /mnt/VBoxLinuxAdditions.run
  • ネットワークアダプタの設定を,「ブリッジアダプタ」または「ホストオンリーアダプタ」あたりにして,ホストとの直接通信が可能なようにする.
    しなくてもwwwには接続できるけど,不便で仕方がない.
  • sshd_configで,passwordloginをyesにしておく

これだけやっておけば,普通にLAN上に新しいUbuntuサーバを立てたのと同じところからスタートできるはず.

前から好きだった作品で,今日は,なんとなく読み返した.
美術学校の学生の4コマで,結構勉強になる.

私は高校の選択芸術をとっていただけの浅い経験しかないものの,それでもこの漫画を読むと,つい高校の美術の時間を思い出して,絵筆を執りたくなる.
とはいえ,私が一番好きだった油彩は,用意するも描くのも片付けるのも大変な上,画材の種類が多い上に高く,気軽に始められない.
ということで,もう10年以上も握っていない鉛筆を買ってきた.HBと2Bの一番安いやつを買ったが,しかし実際に描いてみてると3Bか4Bかを買っておくべきだったと後悔した.
あと,安い画材ということで色鉛筆…学生用の600円の色鉛筆を買った.(高いやつは1万円を越える…)
スケッチブックは,画材屋の少しページが多くて,簡単に本体から切り離せるタイプのもの(ミューズ ザ・スケッチ B4)を購入した.
で,後から気付いたのが,ねり消しを買い忘れていたこと.プラスチック消しゴムだと,カスが出て面倒な上,グラデーション表現を薄くするのに使えないんだよね…デッサンを始めるまで,本当にすっかり忘れていて、まだ買っていない…

デッサン1
デッサン1

で,とりあえずブランクがどの程度かと,腕試しに1時間ばかしデッサンをしてみた.
とにかく簡単なモチーフからということで,息子の積み木から1つ選択した.
この積み木は円柱を半分に切ったもので,面取りをしてあり怪我をしづらく拵えてある.
このような幾何学的な静物画は,ごまかしがききづらいが,練習にはうってつけである.(風景画は,いくらでもごまかせるので,それっぽく仕上げるだけなら,とても楽である.)
材質がはっきりと見える無着色の積み木にしたは,素材感も表現する練習にと思ってのこと…素材感は,一番絵を書いていた頃にもうまく表現ができなかったものなので,これはうまくいかなくても良しとする.

まぁとにかく,それっぽいデッサンができたわけで,本来ならこれから着色…といきたいのだが,デッサンに色鉛筆で着色する方法がさっぱり分からない.
選択美術では,絵画に関してはデッサン→水彩/油彩しか学んでないからな…
鉛筆に重ねても,色が出そうにない.
webで調べれば水彩色鉛筆の描き方講座は発見したので,普通の色鉛筆の講座もあるんだろうと信じたい.
水彩色鉛筆(水を落とせば水彩画になる)の講座によれば,下絵は塗り絵みたく輪郭だけ描いたものになっていた.
色鉛筆でいきなり陰影をつけるなんて,私にできるのだろうか…

-- 以下,選択美術の記憶.

油彩
デッサンからスタートする油彩の場合,デッサンをキャンバス上に書いた後,ブラウンや青の絵の具で下塗りをする.
下塗りでは,影のみを絵の具で表現し,色彩はとりあえずあまり考えない.
下塗りが乾いた後,その上から実際に表現したい色をのせていく…油彩は絵の具が固く,あまり塗っている感がないので,私は「のせる」と言う方がしっくりくるが,ようは色をつけることである.
色彩の表現については美術史の基本程度にいくつか学んだものの,一番好きだったのは印象派の光を表現する技法である.
ちなみに,課題で2つほど模写した.2作目がクロード・モネの「夕日の国会議事堂」なのは,そして失敗作を提出したことも覚えているのだが,1作目の高評価であった作品がどうも思い出せない.
たしか作者は大好きだったセザンヌで,森の中に小さな家あるいは小屋があって,その手前に小さな橋か船つき場があった,晩年の綺麗な絵だったような記憶があるものの…セザンヌを取り上げているwebサイトを見ても出てこない.
水彩
水彩の場合…選択美術では,水彩画を1作品しか仕上げた記憶がないので,ちょっとうろ覚え.
画用紙にデッサンした後,鉛筆の粉が浮かないようフィキサチーフという溶剤をスプレーでかける.
その上を水彩の絵の具で塗っていくと,下書きの線が残った絵になる.
水彩は準備が油彩と比較して楽で,片付けも水で洗うだけと簡易な上,この描き方の場合デッサンの時点で水彩画向けに陰影をつけておけば,着色の時点であまり陰影に気をかけなくても絵になる.
とはいえ,筆を洗う水は必要だし,絵の具も多少は値が張るのでちょっとはハードルがある.
ところで小中学校では水彩ばっかり描いてたハズなのんだが…色をつけると残念な出来になるのが嫌で仕方なかった記憶しかない.
マトモに水彩をやったのは高校の選択美術が初めて.

私の高校では美術は2年生の3学期までで,最後の一枚は高校の傍の桜並木を油彩で描いた記憶がある.
最後に好きなものを好きに描け,というお題だった.
この2年間で学んだ内容は,覚えている範囲では,
静物画デッサン--その1,静物画クロッキー,静物画デッサン--その2,静物画油彩,油彩の模写(画集から)--その1,石膏+FRP による立体造形(友人の顔),油彩の模写(画集から)--その2,木炭画,水彩,自由題の油彩
といったところか.
立体造形は,なんか妙に先生ウケして,どっかの展覧会で展示されたのだが,いかんせん立体造形に全く興味がなかったので,どこでいつ展示されたのかも知らないまま,卒業直前に引き取って実家の倉庫に放置した.
現在は行方不明である.

うーむ,印象派の絵を探したり,用語に間違えがないか調べたりしていたら,記事投稿するだけでデッサンにかけた時間の3倍もかかってしまった.

Android 2.2から1.6へ

軽いと噂のCM6.1を使っていたが,やっぱHT-03aでは重いので,Android1.6を導入することにした.

今回は,Super D 1.11 non ram hack
こいつの導入にあたっては,いくつか注意がある.

Super D は1.5くらいから,SDカードのswapパーティションに対応しており,
ちゃんとパーティションを切ってやらないと動かないため,
まず,リカバリーイメージをアップデートしてSDカードにパーティションを切れるようにすること.
DRC83_base_defanged.zipから導入すること.
更に,b-mobileのSIMを挿す場合は,libhtc_ril.soを差し替えること.

導入にあたって参考にしたページはここ→HT-03a カスタムROM導入ログ-vol.1「初期設定とGoldcard作成」 « Midnightjapan
b-mobile対応にあたって参考はこちら→Android 1.6でbmobileが動いた « コムギドットネット

  • ここから,recovery-RA-sapphire-v1.7.0G.imgを落として,SDカードへコピー
  • Android SDK を導入して,
    > adb shell
    $ su
    # flash_image recovery /sdcard/recovery-RA-sapphire-v1.7.0G.img
    

    として導入.

  • 一旦電源を落とし,Homeを押しながら起動してリカバリーモードから
    「Partition sdcard」を選択し,[swap:32MB/EXT2-size:512MB/FAT:Remainder] でフォーマット
    「SD:ext2 to ext3」を実行してext3フォーマットに変換.
  • 再起動後,別のSDカードにDRC83_base_defanged.zip,SuperD v1.11 をコピーし,この順番で導入
  • パーティションを切ったSDカードを差して起動

Yahoo Messenger のメッセージウィンドウにメッセージが表示されない

-- 追記
やっぱし直らなかったので,Yahoo Messenger 9.5 を入れたら直った.
9.5はこちら→ Windows版メッセンジャー ヘルプ - お試し版Yahoo!メッセンジャー バージョン9.5について

--

最近,メッセージウィンドウに表示されるはずの文字が再描画されず,発言があったことを示す窓の点滅と音がすれど,窓は真っ白なままという現象があった.
窓サイズを変更すると,描画コマンドが走るためか,その時点で発言されている文字が表示される.

で,見付けた解決方法はこれ.
Windows版メッセンジャー ヘルプ - メッセージが表示されない

どうやら,IE9にした際に設定が変更されたらしい.

WPtouch

今日,wireless japan 2011の講演で紹介されていたタブレット端末向けプラグイン「WPtouch」を入れてみたら,
案の定,またパースエラーが出た.
時間と元気がないので,バグ取りはまたこんど.

タグを好意的に解釈してくれるブラウザはユーザの味方だが,
開発者はそれに頼ってはならん気がする…
といいつつ,俺自身のミスでないことを祈る.

オンラインにメモっておかないと忘れてしまうので,前職の職場に遊びに行った時に教えてもらったお菓子をメモっておく.
「あべのポテト」と「呼吸チョコ」
一人,天王寺あたりに住んでる友人がいるので,前者については聞いてみるか.