2012-05-27 良い天気
■[python] python-twitterを使う 
Twitterで、気になった つぶやき を、ポコポコ お気に入りに登録しています。
後で、がーっとwebで見なおしてやろうと思っての事なんですが、Twitterクライアントって、お気に入りを一気に開きまくるという使い方には、対応していません。
という訳で、Twitter APIを使って、何とかしてやろうと思いました。
その際、幾つか躓いた点をメモします。
最初
Python版のライブラリは、python-twitterというのがあるようで、先達の方々が色々と調べてらっしゃっています。
- 公式サイト:python-twitter - A python wrapper around the Twitter API - Google Project Hosting
http://code.google.com/p/python-twitter/
まずは、ここの情報を見るのは必須ですね。
後は、先達の皆さんのブログなメモを見ながら、Pythonのhelpコマンドの表示内容と見比べつつ やっていけばOKです。
注意:APIを使用するには、Twitter Developersの登録が必須です
古い情報だと、例えば以下の呼び出しで、幾つかAPIが呼び出せるよ。と、書いていますが、現在は
oAuth 認証が全ての機能の呼び出しで必須の模様です。
import twitter api = twitter.Api(username='ユーザー名', password='パスワード') ary = api.GetFriendsTimeline()
つまり、Twitter Developersサイトでの登録が必須だという事です。
- Twitter Developers
https://dev.twitter.com/
作業の流れとしては、以下の感じです。
- Twitter Developersにアクセス。
- 右側のメニュー「Create an app」をクリック。
すると、「Sign in with your Twitter account」と出て、ユーザー名とパスワードを求められるので、自分のTwitterアカウントを入力する。 - Sign inできると、表示が切り替わるので、「Create a new application」を選ぶ。
- アプリケーションの情報を入力する。
(自分、何かアプリな情報を入れないといけないのか?と、思ってたんですが、かなりテキトーでもOKでした)
入力内容は、↓を参考にすると良いでしょう。
TwitterでOAuth認証を行う(1:Twitterへのアプリケーション登録) | Tech Booster
http://techbooster.org/android/mashup/4525/ - すると、Consumer key, secretの情報がゲットできます。
更に続けて、ページ下部にある「Create my access token」を選んで、Access token/secretをゲットしましょう。
削除機能を使うならば、Access levelを変更すべきです
参照するだけなら良いですが、削除とかを行うAPIを呼び出したいならば、先ほどのページで、Access levelを変更しましょう。
自分は、Api.DestroyFavoriteメソッドを使おうとして、この問題にぶち当たりました。
TwitterError: Read-only application cannot POST
既にAccess tokenをゲットしている場合は、Access levelを変更後、再度Access tokenを取得しなおして下さい。
サンプルコード
という訳で、お気に入りを一覧取得するサンプルコードです。
# -*- coding: utf-8 -*- # テスト:お気に入り情報の取得 import twitter CONSUMER_KEY = '入れて' CONSUMER_SECRET = '入れて' ACCESS_KEY = '入れて' ACCESS_SECRET = '入れて' def T(s): return s.encode('cp932', 'ignore') def print_status(ary): for i in ary: print "------" print "[%s][%s][%s]" % (T(i.created_at), T(i.relative_created_at), T(i.user.name)) print " %s" % (T(i.source)) print " %s" % (T(i.text)) api = twitter.Api( consumer_key = CONSUMER_KEY, consumer_secret = CONSUMER_SECRET, access_token_key = ACCESS_KEY, access_token_secret = ACCESS_SECRET) stat = api.GetFavorites() print_status(stat)
twitterライブラリが、utf-8専用だと書いてあったので、エンコードをutf-8にしてみました。
ただ これだと、コンソール出力する時に、encode失敗するようなので、適当に encode メソッドを呼び出して逃げています。
ちなみに、登録したお気に入りを削除するには、例えば、以下のように変更すればOKです。
... def print_status(ary): for i in ary: api.DestroyFavorite(i) ...
これらの挙動を調べる際、pdbモジュールとhelpコマンドを総動員しました。
便利ですよね。
2012-05-02 ごーるでんうぃーく
■[tips] バッチファイルで、あるプロセスが起動してなかったらば…を実現する 
自分的なメモ。
バッチファイルで、あるプロセスが起動していなければ、実行する。
というのを指示する方法です。
tasklist | find /C "procexp" if ERRORLEVEL 1 start C:\ほげほげ\ProcessExplorer\procexp.exe /t
これで、ProcessExplorerが起動していなければ、起動させる。という事が実現できます。
(まぁ、ProcessExplorerは、「Allow Only One Instance」って指定が出来るんですけどね)
tasklist単体では、返値が常に「0」っぽいので、findと組み合わせてみました。
■[memo] corega CG-WLNUP04N を買った 
嫁さんがプリンタ(非無線対応)をUSBケーブルで接続していたんだけど、取り回しが大変そうだったんですね。
他にも、非無線対応なUSBデバイスがあったので、無線対応なプリンターサーバーを買って、机の周りをすっきりさせる事にしました。
当初考えていたのは、PLANEXのFFP-PKP03って奴。このタイプでは一番安いタイプじゃないかなと思います?
ただ、これUSBが1ポートしかないんですね。
USBハブで複数分けて使えるのか、非常に微妙。
他のメーカさんで、複数のUSBポートが使えるタイプは無いか調べてみたんですが、大体以下の状況っぽい。
ほとんど1ポートのみなんですが、無線対応のプリンタが出てきている状況で、何の意味があるんだろうなぁ?(USBハブ対応とはっきり書いてある訳でも無し)
| メーカ | 型式 | URL |
|---|---|---|
| corega | CG-WLNUP04N/-W | http://www.corega.co.jp/prod/wlnup04n/ |
| I/Oデータ | WN-DS/US | http://www.iodata.jp/product/network/option/wn-dsus/ |
で、いつものAmazonでチェックしていたら、CG-WLNUP04Nがある瞬間 結構安かったので、思わず購入してみました。
コレガ(アライドテレシス) IEEE802.11n/g/b規格対応 デバイスサーバ(USB機器4台用) プリントサーバ機能搭載 CG-WLNUP04N
- 出版社/メーカー: コレガ
- 発売日: 2011/07/20
- メディア: Personal Computers
- 購入: 1人 クリック: 5回
- この商品を含むブログを見る
接続の手順ですが、大体以下の感じでした。
- 無線化したいプリンタを、まずUSB接続でドライバを入れる。
ちゃんとスキャナとか使える事を確認した方が良いでしょう。 - USB共有センターのドライバを入れる。
CD-ROMのものより、Web siteの方が新しかったので、こっちを入れました。 - CG-WLNUP04Nと無線ルーターを接続。
USB共有センターで開くと、デバイスを認識するので、IPアドレスを自分の所属するドメインに設定し直して、ping確認しましょう。 - CG-WLNUP04Nにプリンタを接続。
USBポートのLEDランプが点灯します。 - USB共有センターで、接続したいプリンタを選んで、「接続」します。
- 無線上で「接続」したプリンタを使います。
当初、WPSボタンで簡単接続は出来なかったので、無線ルーターのフィルタ外しを、ちこっと行なっていたら、共有センターがデバイスを認識していました。(多分、パケットを監視してんだろうなぁ)
で、「サーバーをダブルクリックして、IPアドレスを変更してください」とあったので、自分の所属ドメインに適当に振ってやると、後は簡単に接続できました。
他の製品で、無線化したプリンタは、応答速度が遅いというコメントも見られましたが、そんなに遅いかな?という感じです。
(あぁ、一度だけ妙にスキャナの応答速度が遅い時がありましたが、その後、特に発生していません)
今回、無線化したプリンタは、EPSON PM-A890という奴ですが、Win7 x64環境で、スキャナがばっちり使えています。(というか、先日からスキャナばっかり使っている)
2012-02-12 ひさしぶりー
■[tips][android] RMapsを使う為に、Windows7(x64)環境で Mobile Atlas Creator を使う 
Androidタブレットを買ったんですが、Wi-Fi環境なので、基本外に持ち出す事が出来ないんですね。
(Wi-Fiルーターを持ち歩く必要がある)
Google Mapsは便利なので、これを外で電子地図代わりに使いたい。
けど、Wi-Fiルーターで接続しないと、地図表示できない。…うーん。という訳で、悩んでいたんですが、どうやらローカル地図ソフトなるものがある事を知った次第。
- 人々柱の備忘録| RMaps Android ローカルMAP
http://hitobitobashira.blog64.fc2.com/blog-entry-132.html - 人々柱の備忘録| Maps (-) Android オフライン地図をいつでも簡単キャッシュ
http://hitobitobashira.blog64.fc2.com/blog-entry-162.html - 人々柱の備忘録| Androidのオフライン地図アプリまとめ iPhoneとの比較
http://hitobitobashira.blog64.fc2.com/blog-entry-157.html
という訳で、RMapsというソフトを入れてみる事に。
動かしてみた感じ、良さげだったので、パソコンからオフライン地図データを取得して、RMapsに入れ込む事にしました。
オフラインな地図データ作成ソフトの存在
RMapsをWi-Fiが届かない環境でも使えるようにする為には、オフライン地図データが必要な訳ですね。
描画速度の速さで、↓このページからダウンロードできる Mobile Atlas Creator か TrekBuddy Atlas Creatorが良いように感じました。
- android-map - Solutions to Offline Google Maps for Android-powered phones. - Google Project Hosting
http://code.google.com/p/android-map/ - 作者と思われるページ:Dr. TYT 的 Android 地圖
http://android-map.blogspot.com/
本家?か良く判らないんですが、Mobile Atlas Creatorからダウンロードできる配布物は、SQLiteのバージョン不一致か良く判りませんが、少なくとも、Windows7(x64)な環境では正しく地図データを作成してくれません。
(当初、しょうがないので、VirtualPCで動かしていた)
ソフトの経歴としては、TrekBuddy Atlas CreatorからMobile Atlas Creatorにメンテナンスが移っているようなので、現在だと Mobile Atlas Creator(の、このサイトバージョン)を使った方が良いでしょう。
自分は、Mobile_Atlas_Creator_1.8_SQLite.zipをダウンロードして動かしてみたんですが、何の設定変更も無しに、地図データを作成してくれました。
多分、正しく動く SQLiteライブラリが同梱されているお陰だと思われます。
皆さんが紹介されている、TrekBuddy Atlas Creatorも使えます。(というか、タブレットでの動作確認は、こちらばかり試していた)
この場合、Windows7(x64)環境では、そのままでは使えません。x64に対応したSQLiteのライブラリに更新する必要があるので注意して下さい。
x64なSQLiteは、↓ここで紹介されている通り、やはり同サイトの、Mobile_Atlas_Creator_1.7_SQLite.zip内の「Win x64(64bit)」フォルダにある、「sqlite_jni.dll」に上書きする必要があります。
- Updating problems [myProject]'. no sqlite_jni in java.library.path | The Log of "__ ____"
http://thelogofthewook.blogspot.com/2011/12/updating-problems-myproject-no.html#!/2011/12/updating-problems-myproject-no.html
使い方
使い方は、基本皆さんの説明ページを読んで下さい。
そちらの方が、詳細で判りやすいです。
- 人々柱の備忘録| RMaps Android ローカルMAP
http://hitobitobashira.blog64.fc2.com/blog-entry-132.html - TrekBuddy Atlas Creator & RMaps
http://wp.07ch.com/?page_id=57 - RMapsを使ってトレイルランに(XperiaにオフラインでGPS): くろすけの、まったりと過ごす日々
http://kuro277.cocolog-nifty.com/blog/2010/08/rmapsxperiagps-.html
まぁ、それだと芸が無いので、同じ説明で申し訳ありませんが、順を追って説明をば。
1.アプリを起動すると、地図がどーんと表示されます。
ここで、注意ば必要なのは、左ドラッグは領域選択。右ドラッグが地図の移動です。最初、アレ?と思って固まりました。
2.地図データを作成したい大体の場所まで移動したら、おもむろに地図データを作成したい部分を左ドラッグで選択します。
選択した後、左ペインの「Zoom Levels」の数値を選択して下さい。これは地図の詳細度を指定します。
あまり大きい値を入れると、データサイズが莫大になるので、選択した際に表示される「xxx tiles」の値を睨みながら選んで下さい。
3.次に左ペインの「Add selection」をクリックします。
領域設定した情報は、下側の「Saved profiles」の下の「Save」で保存できるようなので、テケトーに保存しましょう。
4.次に左ペインの「Create atlas」で、地図データの情報取得と作成を行います。
全ての作業が完了したら、「Open Atlas Folder」ボタンが有効になります。
ちなみに、「Atlas settings」の「Format」で作成する地図データの形式を選ぶ事ができるようです。
5.「Open Atlas Folder」ボタンをクリックすると、作成された地図データファイル(.sqlitedb)のフォルダがオープンされます。
これを、タブレット端末の、SDカードの「//rmaps/maps」フォルダにコピーします。
6.タブレット端末を起動して、RMapsを起動し、Menuを選び、「その他」→「Settings」→「User defined maps」で、作成した地図データファイルを選択→「Enable map」にチェックを入れます。
一旦画面に戻って、Menuを選び、「Maps」で選択した地図データファイル名を選択すると、オフラインな地図データを表示するようになります。
感想
人々柱の備忘録さんのページで、オフライン地図アプリのまとめが載っていて、非常に参考になります。
- 人々柱の備忘録| Androidのオフライン地図アプリまとめ iPhoneとの比較
http://hitobitobashira.blog64.fc2.com/blog-entry-157.html
つーか、iPhone版もあるんですね。知らなかった。
こうなると、手持ちのiPod touchにGPSが欲しくなるなぁ。次期バージョンで搭載してくれないかなぁ?
2011-11-06 涼しいね
■[tips] Windows7でIrvineを使用する際の気づき 
ダウンローダ Irvineは、大きめのファイルや複数のリンクに分けられている細かいファイル(ネット小説系は、やけにリンク細切れが多くて、後でゆっくり見たい時大変)をダウンロードするのに便利なんですね。
今だったら、DCさくらの方がWindows7も正式サポートしているんで、こっちの方が良いと思うんですが、何故か こっちを使い続けています。
Windows7の動作報告関係のページだと、Irvine使えるよ!って報告例が多いのですが、一部の方は使えないよ。と報告している方も居るようですね。
- Irvineフリー版|Windows 7 アプリケーション動作報告リスト
http://w7.vector.jp/softrev/detail.php?s_no=20263 - Windows 7 @ ウィキ - 対応ソフト(x64)
http://www15.atwiki.jp/win7/pages/30.html
自分のマシンは、Windows7(x64)でIE9の環境(正確にはメインブラウザはSleipnir)なんですが、Irvineは ちゃんと使えています。(Irvine 1.3.0)
ただ、ちゃんと使えるようにする為には、ちょっとしたテクニックがあるようです。現時点で、判っている事を、メモしておきます。
Tips1.Program Files フォルダ以外にインストールする
これは結構有名なようです。
- Program Filesの読み取り専用を解除できません。 - Microsoft Answers
http://answers.microsoft.com/ja-jp/windows/forum/windows_7-files/program/7333d51a-f8db-4164-b87e-ed5a2b01245f - Windows Vista & 7のUAC対策について
http://www.trycut.com/uac.htm - Windows Vista/7 のファイルの仮想化(Virtualization)について
http://pasofaq.jp/windows/vista/virtualstore.htm
自分の場合、適当なフォルダを掘って、その中にIrvineを入れて動かしています。
Tips2.実行ファイルに管理者権限を与えずに動かす
先のwikiでは、管理者権限与えて動かせば。とありますが、どうも管理者権限を与えてしまうと、IEの右クリックメニューによる Irvine連携が機能しなくなるようです。
(もしかしたら、最初の起動だけは管理者権限必要かも知れません)
これ、何で気づいたかと言うと、オレオレなスクリプトで、Irvineにダウンロードアイテムを登録しようとした際に気づいたんですね。
JavaScriptで、IrvineにアクセスするActiveXオブジェクトを起動しようと思って、簡単なJavaScriptを書いたんですよ。
o = new ActiveXObject('Irvine.Api'); WScript.Echo(o);
これを実行したら、以下のエラーが出てきたんですね。
$ cscript test.js Microsoft (R) Windows Script Host Version 5.8 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. test.js(1, 1) (null): 要求された操作には管理者特権が必要です。
これを見て、「はっ」と気づいたんですよ。IEの右クリックメニューでも、「オブジェクトが生成できない」とか言ってたな。と。
で、Irvineの実行ファイルに与えていた管理者権限を外したら、ちゃんとIEの右クリックメニューからの「Irvineへ登録」が機能し始めた次第です。
テケトーな予想ですが、以下の動きじゃないかな?と思ってます。
- 管理者権限で起動した際、自分のアカウントとは別の専用アカウントで起動。
- スクリプトからアプリのActiveXオブジェクトを得ようとする(new ActiveXObject(...))。
- スクリプトのアカウントはxxさん、アプリのアカウントは管理者権限さん。
アカウントが違うので、アプリへのアクセスを蹴られる。 - 結果、ActiveXオブジェクトの生成に失敗する。
要するにクライアントのアカウントと、Irvineのアカウントを同じにしろや。って事です。
だから、Irvineに管理者権限を与えてしまうと、クライアント 例えばスクリプトやIEやSleipnirも管理者権限で起動しないと、連携出来ないって寸法な訳ですね。
最後に
という訳で、ちょっとした気づきでした。
後、おまけですが、Irvineにダウンロードアイテムを登録するには、ぶっちゃけ以下のコードで大体OKのようです。
var Irvine = new ActiveXObject('Irvine.Api'); var IrvineItem = new ActiveXObject('Irvine.Item'); IrvineItem.Url = ダウンロードしたいURL; IrvineItem.FileName = ダウンロード時のファイル名; Irvine.Current.AddItem(IrvineItem);
APIリファレンスは、 http://hp.vector.co.jp/authors/VA024591/doc/api.txt にあります。
2011-09-19 台風かな?
■[python] Google Documents List APIを使って、Google ドキュメントにファイルを自動アップロードする 
自分は、個人的な気づきをテキストファイルにメモしたりしているんですね。
メールやはてブも使っていますが、ネット経由とローカルファイルでは、どうしても応答速度に違いが出てしまいますからね。
そうやって、書き留めたテキストファイルですが、何時までもローカルに置いておくのも嫌なんですね。
プライベートなネットストレージに突っ込んでおけば、ローカルマシンが壊れた際の復旧や、タブレットなどの別のマシンからも参照できるので、便利になる訳です。
ネットストレージに突っ込んだデータの検索性で、非常に便利なのは、今の所、Google ドキュメントかEvernote辺りかな?と感じています。
特に、Google ドキュメントは、検索がバカ早なので、結構お気に入りです。
(MicrosoftさんのSkyDriveは容量はピカイチなのですが、検索を自分のアップしたものに絞れないのがネック<何か方法があるのかなぁ?)
(ちなみに、Yahooはサービス規約をポンポン変えるので、不安で使えない)
という訳で
という訳で、テキストファイルをGoogle ドキュメントに自動アップロードしようと思いました。
要するに、タスクスケジューラ等で、ローカルに置いたテキストファイルを定期的にアップロード&更新しちゃおうって訳です。
当初は、適当なソフトを使おうか?と思っていたんですが、ぐぐると結構楽に実装できる事が判ったので、勉強がてら自作する事にしました。
- Client Libraries and Sample Code - Google Documents List API - Google Code
http://code.google.com/intl/ja/apis/documents/code.html - Python Language Guide (v1.0) - Google Documents List Data API v1.0 - Google Code
http://code.google.com/intl/ja/apis/documents/docs/1.0/developers_guide_python.html - Google Document にファイルをアップロードするバッチを作ってみた - Limitの日記
http://d.hatena.ne.jp/limitusus/20090929/1254232748 - imageryblog: Google ドキュメントにファイルをアップロード,ダウンロードする方法 #googledocs
http://blog.firefly-vj.net/2011/08/google-googledocs.html - Google Documents List Data API v3.0 を python から利用してみた。 (tonextone.com/type/)
http://tonextone.com/type/2010/06/20-0028.html
クライアントのライブラリは、Client Libraries and Sample Code - Google Documents List API - Google CodeのDownloadから取得します。
自分が取得したのは、gdata-2.0.14.zip でした。
ダウンロードして、setup.pyでinstallすればインストールされます。
I:\Wacky\src\test\google\gdata-2.0.14>python setup.py install ... byte-compiling C:\tool2\Python27\Lib\site-packages\gdata\youtube\__init__.py to __init__.pyc byte-compiling C:\tool2\Python27\Lib\site-packages\gdata\__init__.py to __init__ .pyc running install_egg_info Writing C:\tool2\Python27\Lib\site-packages\gdata-2.0.14-py2.7.egg-info
後は、上のリンクで紹介されているサンプルコードを元にAPIを叩けばOKです。
では、早速今回作ったコードを示します。
#!/bin/env python # -*- encoding: cp932 -*- """ Google Documentにテキストファイルをアップロードする なお、テキストファイルは、utf-8形式がデフォルトである。(Google Documentの場合) """ import sys import os import os.path import pdb import gdata.docs import gdata.docs.service def get_exe_dir_name(): """実行スクリプトのフォルダを取得""" return os.path.abspath(os.path.dirname(__file__)) def copy_to_utf8(src_fpath, dst_dir=None): """src_fpath(コピー元のファイルパス)からdst_dir(コピー先ディレクトリ)に、utf-8変換コピーする""" fname = os.path.split(src_fpath)[1] if dst_dir == None: dst_dir = get_exe_dir_name() dst_fpath = os.path.join(dst_dir, fname) s = "nkf32 -w8 \"%s\" > \"%s\"" % (src_fpath, dst_fpath) print "call: ", s os.system(s) return dst_fpath def list_file(cli): """Google Documentのファイル一覧を得る""" i = 0 for e in cli.GetDocumentListFeed().entry: i = i + 1 print "%02d : file [%s][%s]" % (i, e.title.text.decode('utf-8'), e.GetDocumentType()) def list_dir(cli): """Google Documentのフォルダ一覧(コレクション)を得る""" i = 0 q = gdata.docs.service.DocumentQuery(categories=['folder'], params={'showfolders': 'true'}) for e in cli.Query(q.ToUri()).entry: i = i + 1 print "%02d : dir [%s]" % (i, e.title.text.decode('utf-8').encode('cp932')) def find_file(cli, name): """Google Documentに指定した名前のファイルがあるか調べる。あればオブジェクトを、無ければNoneを返す""" for e in cli.GetDocumentListFeed().entry: if e.title.text.decode('utf-8') == unicode(name, 'cp932'): return e return None def upload_text(cli, fpath, name=None): """Google Documentに、ファイルをアップロードする。既にファイルがあれば置き換える \arg fpath アップロード元のファイルパス \arg name アップロード時の名前 """ if name == None: name = os.path.split(fpath)[1] print "アップロード中(%s, %s)..." % (name, fpath) ms = gdata.MediaSource(file_path=fpath, content_type=gdata.docs.service.SUPPORTED_FILETYPES['TXT']) exist_file = find_file(cli, name) e = None if exist_file == None: print " new upload file!!" e = cli.Upload(ms, unicode(name, 'cp932')) else: print " replace file!!" e = cli.Put(ms, exist_file.GetEditMediaLink().href) print " OK!!" print " href=%s" % (e.GetAlternateLink().href) def main(argv): print "[%s]のファイルを作業フォルダにコピー中" % argv[1] up_file = copy_to_utf8(argv[1]) print "upload file:[%s]" % up_file print "Google Documentにアクセス中...", cli = gdata.docs.service.DocsService() cli.ClientLogin("<アカウント>", "<パスワード>") print "アクセス完了!!" print "\n--- Google Document List ---" list_dir(cli) list_file(cli) print "" upload_text(cli, up_file, None) print "アップロード完了!!" if __name__ == "__main__": argv = sys.argv print "argc=%d" % len(argv) for i in range(len(argv)): print "%d-[%s]" % (i, argv[i]) main(argv)
使い方は、アップロードしたいテキストファイルのパスを第1引数に与えるだけです。
スクリプトのフォルダに、nkf32でUTF-8変換したテキストファイルを一旦配置し、それからGoogle ドキュメントにアップロードする仕掛けです。
最後に
一応余談です。
Googleドキュメントは、テキストファイルはUTF-8が前提になっているみたいです。
なので、スクリプトでは、Windows版のnkf32を使って、一旦UTF-8に変換してからアップロードするようにしています。
そうしないと、アップロードしたファイルを参照しようとして、文字化けに遭遇しちゃいます。
後、UploadとReplaceをうまく使わないと、同じファイル名で、バンバンUploadするハメに陥りますので、気をつけてください。
(最初、同じ名前のファイルが連続して表示されたので、何が起きたのだろうと考えこんでしまった)
でわでわ。
![[Amazon.co.jp限定] PLANEX 双方向通信対応 Wi-Fiシンプルプリントサーバ(LAN×2/USB 2.0ポート) FFP-PKP03 [フラストレーションフリーパッケージ(FFP)] [Amazon.co.jp限定] PLANEX 双方向通信対応 Wi-Fiシンプルプリントサーバ(LAN×2/USB 2.0ポート) FFP-PKP03 [フラストレーションフリーパッケージ(FFP)]](http://ecx.images-amazon.com/images/I/31uFG4WM1lL._SL75_.jpg)





