スポンサーサイト

Tags :
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

FC2Blogに画像をアップロードするAppleScriptが動作するかをチェックするスクリプト書いた

ちょっと前に
ドラッグ&ドロップでFC2ブログに複数の画像をまとめてアップロードするAppleScript その4
てのを書きましたが、先週あたりにFC2Blogの管理画面がアップデートされて、アップロードする画像を選択するフォームが複数表示されるように変更された為(どうせなら、はてなfotolifeみたいにダイアログ中で複数選択出来る様にすれば良いのに)、スクレイピングに頼っている部分が動作しなくなっていたので元エントリのスクリプトを更新しておきました。

で、今回も使ってる方からの報告で動作しなくなってるのを知ったんですが、そちらに頼ってばっかりなのも何なので、上記のAppleScriptが動作するかどうかをチェックして、もし動作しなくなる様なFC2Blogの仕様変更があった場合にはメールで知らせるようなスクリプトをPythonで書いてcronで回す事にしました。AppleScriptで書いても良かったんですけど、cronで動かすのでほぼ常時電源の入ってるLinux PCで使える様に。

やってる事は、上記のAppleScriptと同じ方法でアップロードを試みて、失敗するとSubjectにどの処理で失敗したのか、本文はその時サーバから返って来たHTMLを入れて自分宛にメールを送ります。始めはサーバとやり取りするのにurllib2を使って書いてたんですが、画像等の『multipart/form-data』をすんなりPOST出来ない感じだったので、手っ取り早くcurlコマンドをpopen2モジュールで呼び出して処理しています。
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, re
import smtplib
from popen2 import popen3
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate
from BeautifulSoup import BeautifulSoup

#SMTPでメールを送信
def send_mail(subject, body):
    from_addr = 'sender@example.com'
    to_addr = 'receiver@example.com'
    encoding = 'ISO-2022-JP'

    #メッセージを生成
    msg = MIMEText(body.encode(encoding), 'plain', encoding)
    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_addr
    msg['To'] = to_addr
    msg['Date'] = formatdate()

    #送信
    s = smtplib.SMTP("localhost")
    s.sendmail(from_addr, [to_addr], msg.as_string())
    s.close()


#コマンドを実行し処理結果を返す
def popen(cmd):
    stdout, stdin, stderr = popen3(cmd)    
    rep = []
    for line in stdout: rep.append(line)
    return ''.join(rep)


def main():
    blogurl = 'http://MY_ACCOUNT.blog80.fc2.com/admin.php'
    uploadurl = 'http://blog80.fc2.com/control.php'
    passwd = 'MY_PASSWORD'
    id = 'MY_ACCOUNT'
    testfile = 'fc2blog_uploadtest.jpg'
    cookiefile = 'fc2uploader_cookie.txt'
    title = 'FC2Blog_uploadchaecker'
    
    #ログイン処理
    cmd  = 'curl -d "id=%s&pass=%s&mode=admin&mode=logging&process=in" -c "%s" -L "%s" | tail -n 300' % (id, passwd, cookiefile, blogurl)
    rep = popen(cmd)
    for line in rep.splitlines():
        if  'input type="password"' in line:
            send_mail(u'%s : ログインに失敗' % title, unicode(rep, 'EUC-JP'))
            sys.exit(0)

    #アップロード時にPOSTするcrcの値を取得
    cmd = 'curl -b %s -d "mode=control&process=upload" -L "%s" | grep \'name="crc"\' | sed \'s/\t*<input.*value=\"//\' | sed \'s/".*\'//' % (cookiefile, blogurl)
    rep = popen(cmd)
    crc =  rep.splitlines()[1]
    if crc == '':
        send_mail(u'%s : crc値の取得に失敗' % title, stdout.read())
        sys.exit()

    #テスト用画像をアップロード
    cmd  = 'curl -b %s -F "upfile[0]=@%s" -F mode=control -F process=upload -F width=200 -F height=200 -F overwrite=force -F type=upload -F crc=%s -F insert="" -L "%s"' % (cookiefile, testfile, crc, uploadurl)
    rep = popen(cmd)
    result = False
    for line in rep.splitlines():
        if testfile in line:
            result = True
    if result == True:
        #アップロード成功の場合
        soup = BeautifulSoup(rep)
        td = soup.find('td', 'manage')
        try:
            #ファイル削除用のcrc値、ファイルIDを取得
            m = re.search('fileno=([0-9]+)&crc=([0-9a-z]+)', str(td))
            fileno = m.group(1)
            crc = m.group(2)
            print fileno, crc
            #テスト用ファイルを削除
            cmd = 'curl -b %s -F mode=control -F process=upload -F type=delete -F no=%s -F crc=%s -F page=1 -F tail= -F sort=dd -L "%s"' % (cookiefile, fileno, crc, uploadurl)
            popen(cmd)
        except AttributeError:
            #ファイル削除用のcrc値、ファイルIDを取得出来ない場合
            send_mail(u'%s : 削除用ファイルID,crcの取得に失敗' % title, unicode(rep, 'EUC-JP'))
            sys.exit()
        #テスト用画像が削除出来ているかをチェック
        cmd = 'curl -b %s -d "mode=control&process=upload" -L "%s"' % (cookiefile, blogurl)
        rep = popen(cmd)
        for line in rep.splitlines():
            if testfile in line:
                send_mail(u'%s : ファイルの削除に失敗' % title, unicode(rep, 'EUC-JP'))
                sys.exit()
        send_mail(u'%s : 正常終了' % title, unicode(rep, 'EUC-JP'))
    else:
        #アップロード失敗
        send_mail(u'%s : ファイルのアップロードに失敗' % title, unicode(rep, 'EUC-JP'))
                
if __name__ == '__main__':
    main()
スポンサーサイト

XML等の文字参照を通常の文字列に戻すAppleScript(その2)

■4/7追記 こちらのエントリにもっとシンプルなのがあります。
Webで利用される様々な文字列エンコードを扱うためのAppleScriptいろいろ


ちょっと前に『&amp;』や『&#12345;』といった文字参照を含む文字列を通常の文字列に戻すAppleScriptてのを書きましたが、あまりに処理が遅いので、もうちょっと速くなるよう書き直しました。

前回のはpythonでforループを一行に納める書き方がわからなかったというのもあって、文字コードを一文字ごとにdo shell scriptでpythonに渡してましたが、それだとやたら時間がかかるので、間にASCII文字が入る等して文字参照が途切れない限り出来るだけ一度にpythonの引数として渡すようにしました。

MacOSX10.5のAppleScriptならpythonを使わなくてもUnicode textのidプロパティで変換できるので、一文字ずつ処理するような書き方でもそれ程遅くならないかも知れません。なのでこのスクリプトは主に10.4以前のOSX向けです。

あと、数値文字参照の表記が10進、16進どちらでも変換できるようにしてあります。

■動作確認■
MacOSX 10.4.11
-- my_string -> 変換する文字参照を含んだ文字列
set my_string to "&#x300e;&#x26;&#x61;&#x6d;&#x70;&#x3b;&#x300f;&#x7b49;&#x306e;&#x5b9f;&#x4f53;&#x53c2;&#x7167;&#x3084;&#x300e;&#x26;&#x23;&#x31;&#x32;&#x33;&#x34;&#x35;&#x3b;&#x300f;&#x3068;&#x3044;&#x3063;&#x305f;&#x6570;&#x5024;&#x6587;&#x5b57;&#x53c2;&#x7167;&#x3092;&#x901a;&#x5e38;&#x306e;&#x6587;&#x5b57;&#x306b;&#x5909;&#x63db;&#x3057;&#x307e;&#x3059;" as Unicode text

display dialog (decodeStringsWithNCRs(my_string))

on decodeStringsWithNCRs(my_string)
    set resultStr to ""
    set ent to "" as Unicode text
    set ent_list to {}
    set flg to false
    repeat with cnt from 1 to (count of my_string)
        set chr to item cnt of my_string
        if chr is "&" and (item (cnt + 1) of my_string is not "&") then
            if flg is false then
                set flg to true
                set ent to chr
            else
                set resultStr to resultStr & ent
                set ent to "&"
            end if
        else if chr is ";" and flg is true then
            if ent starts with "&#" then
                set end of ent_list to ent & ";"
            else
                set resultStr to resultStr & decodeNCRs(ent_list) & decodeEntity(ent & ";")
                set ent_list to {}
            end if
            set flg to false
            set ent to ""
        else if flg is true then
            set ent to ent & chr
        else
            if ent_list is not {} then
                set resultStr to resultStr & decodeNCRs(ent_list) & chr
                set ent_list to {}
            else
                set resultStr to resultStr & chr
            end if
        end if        
    end repeat
    set resultStr to resultStr & decodeNCRs(ent_list)
end decodeStringsWithNCRs


on decodeNCRs(ncr_list)
    set args to "" as Unicode text
    repeat with w in ncr_list
        set w to items 3 thru -2 of w
        if w starts with "x" then set w to "0" & w
        set args to args & " " & w
    end repeat
    try
        set scpt to "python -c 'import sys;[sys.stdout.write(unichr(eval(i)).encode(\"utf-8\")) for i in sys.argv[1:]] ' " & args
        return do shell script scpt
    on error
        return false
    end try
end decodeNCRs


on decodeEntity(str)
    set html_ent to {"&amp;", "&lt;", "&gt;", "&quot;", "&apos;"}
    set decoded_ent to {"&", "<", ">", "\"", "'"}
    set cnt to 1
    repeat with he in html_ent
        if str is he as Unicode text then
            return item cnt of decoded_ent
        end if
        set cnt to cnt + 1
    end repeat
    return str
end decodeEntity

XML等の文字参照を通常の文字列に戻すAppleScript

■4/7追記 こちらのエントリにもっとシンプルなのがあります。
Webで利用される様々な文字列エンコードを扱うためのAppleScriptいろいろ


『&amp;』や『&#12345;』といった文字参照を含む文字列を通常の文字列に戻すAppleScript。

Twitterなんかの海外のWebサービスのRSSや、APIで取得出来るXMLの日本語部分が数値文字参照で返ってくるものがありますが、それを AppleScriptで扱うにはどうしたら良いか…やり方を軽く探してみたんですが見付けられなかったので自分で書きました。OSAXとかありそうですけど、とりあえず素の状態でやりたかったんで。

何が何でもAppleScriptで処理しないといけない場面はそれほど無いとは思いますが。

スクリプトの要になる、文字を変換する部分は最近かじり始めたpythonを使ってます。あと、これは以前ぴよまるさんが文字列を処理するのにpythonを使ってられたのをヒントにしました。

このスクリプトを実行すると、復元された文字列が表示されます。

1文字ずつdo shell scriptで変換して行くので処理はやや遅いです。数文字まとめてpythonに渡すようにした方が良かったですね。整形が面倒ですけど。

『&amp;』等を1つだけ引数で渡して変換した文字を返す部分だけ関数化しました。

■2/15追記■
気になった部分を若干修正

■3/3追記■
MacOSX10.5のAppleScript2.0だと、Unicode textのidプロパティ使えばもっと素直に変換できますね

■動作確認■
MacOSX10.4.11
property bslashChr : ASCII character (128)

--my_stringsに処理する文字参照を含んだ文字列を入れておく
set my_strings to "&amp;amp;&#31561;&#12398;&#23455;&#20307;&#21442;&#29031;&#12420;&amp;#12345;&#12392;&#12356;&#12387;&#12383;&#25968;&#20516;&#25991;&#23383;&#21442;&#29031;&#12434;&#36890;&#24120;&#12398;&#25991;&#23383;&#12395;&#22793;&#25563;&#12375;&#12414;&#12377;&#12290;" as Unicode text

--my_stringsの文字列を{"a","b","c","&amp;","&#12345;"}のようなリストに分解
set chr_list to {}
set chrRef to "" as Unicode text
set flg to false
repeat with cnt from 1 to (count of my_strings)
    set chr to item cnt of my_strings
    if chr is "&" and (item (cnt + 1) of my_strings is not "&") and flg is false then
        set flg to true
        set chrRef to chr
    else
        if flg is true then
            if chr is ";" then
                set end of chr_list to chrRef & ";"
                set flg to false
                set chrRef to ""
            else
                set chrRef to chrRef & chr
            end if
        else
            set end of chr_list to chr
        end if
    end if
end repeat

--リストの要素を1つずつ変換してmy_textに追加していく。変換出来ないものはそのまま文字として追加
set my_text to "" as Unicode text
repeat with chr in chr_list
    set returned_chr to my decodeCharacterReferences(chr)
    if not returned_chr is false then set chr to returned_chr
    set my_text to my_text & chr
end repeat

display dialog my_text


(*
    実体参照および数値文字参照を『1文字ずつ』変換
    &#および;を付けたまま引数として渡す
    文字コードは16bit以下 10進表記限定(&#01234;の表記)
    XMLの仕様で定義されている 「&amp;」 , 「&lt;」 , 「&gt;」 , 「&quot;」 , 「&apos;」 を変換出来る事は確認
*)
on decodeCharacterReferences(chrRef)
    if chrRef starts with "&#" and item -1 of chrRef is ";" then
        set chrRef to (items 3 thru ((count of chrRef) - 1) of chrRef)
        try
            set scpt to "python -c 'print unichr(eval(\"" & chrRef & "\")).encode(\"utf-8\")' "
            return do shell script scpt
        on error
            return false
        end try
    else if chrRef starts with "&" and item -1 of chrRef is ";" then
        if chrRef is "&apos;" then return "'" --&apos;はhtmlentitydefsモジュールのname2codepointに定義されてない?
        set chrRef to (items 2 thru ((count of chrRef) - 1) of chrRef)
        try
            set scpt to "python -c 'import htmlentitydefs; print unicode(\"" & bslashChr & bslashChr & "u%04x\" % htmlentitydefs.name2codepoint[\"" & chrRef & "\"],\"Unicode-Escape\").encode(\"utf-8\")'"
            return do shell script scpt
        on error
            return false
        end try
    end if
    return false
end decodeCharacterReferences
Profile
choco
Author : choco

印刷・製版の現場を経て、広告制作会社でPhotoshopを使ったビジュアル制作を担当。

→現在は車載機器開発ベンダにて、組み込み3Dデータ作成やUIデザインなどを行っています。

Categories
Favorites


Search
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。