<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>週刊（月刊？）プレカリアート &#187; コンピュータ</title>
	<atom:link href="http://blog.neoneet.jp/category/%e3%82%b3%e3%83%b3%e3%83%94%e3%83%a5%e3%83%bc%e3%82%bf/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.neoneet.jp</link>
	<description>ニートになりそうな私が好き勝手書きます</description>
	<lastBuildDate>Sat, 24 Dec 2011 06:19:08 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>PayPalのSandboxで&#8221;Please login to use the PayPal Sandbox features.&#8221;になる問題</title>
		<link>http://blog.neoneet.jp/2011/12/24/paypal%e3%81%aesandbox%e3%81%a7please-login-to-use-the-paypal-sandbox-features-%e3%81%ab%e3%81%aa%e3%82%8b%e5%95%8f%e9%a1%8c/</link>
		<comments>http://blog.neoneet.jp/2011/12/24/paypal%e3%81%aesandbox%e3%81%a7please-login-to-use-the-paypal-sandbox-features-%e3%81%ab%e3%81%aa%e3%82%8b%e5%95%8f%e9%a1%8c/#comments</comments>
		<pubDate>Sat, 24 Dec 2011 06:19:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=277</guid>
		<description><![CDATA[クリスマスイブだというのに寂しくコードを書いています（；；） さて、本題ですがPayPalの支払いのリダイレクトページについて、あちこちにサンプルコードがあります。たとえば $fp = fsockopen (&#8216;www.sandbox.paypal.com&#8217;, 80, $errno, $errstr, 30); のようになっているサンプルがあるのですが、このままでは動作しません（少なくともこちらでは動作しませんでした）。&#8221;Please login to use the PayPal Sandbox features.&#8221;が出てきます。これについての日本語ページは探したところ1ページしかなく、期待する解決策はなかったためメモ書きを残すことにしました。英語だと7,500件出てきますが、そのうち何件が役に立つかは定かではありません。 ともあれ、実行するとこのような画面になってしまいログインを促されます。 この原因は https://developer.paypal.com/にログインしないと使えない クッキーにsequre属性が付いているからhttpsにしないとクッキーが無効になる ことなので、解決策はsandboxにはhttpsでアクセスすることです。 いま、Google App EngineをPayPalから通知を受けるサーバとしてプログラムを書いています。Pythonは不慣れだから色々と大変です。]]></description>
			<content:encoded><![CDATA[				<p>クリスマスイブだというのに寂しくコードを書いています（；；）</p>
				<p>さて、本題ですがPayPalの支払いのリダイレクトページについて、あちこちにサンプルコードがあります。たとえば</p>
				<blockquote><p>
				$fp = fsockopen (&#8216;www.sandbox.paypal.com&#8217;, 80, $errno, $errstr, 30);
				</p></blockquote>
				<p>のようになっているサンプルがあるのですが、このままでは動作しません（少なくともこちらでは動作しませんでした）。&#8221;Please login to use the PayPal Sandbox features.&#8221;が出てきます。これについての日本語ページは探したところ1ページしかなく、期待する解決策はなかったためメモ書きを残すことにしました。英語だと7,500件出てきますが、そのうち何件が役に立つかは定かではありません。</p>
				<p>ともあれ、実行するとこのような画面になってしまいログインを促されます。</p>
				<p><img src="http://blog.neoneet.jp/wp-content/uploads/2011/12/sandbox.png" alt="Sandbox" title="sandbox.png" border="0" width="500" height="81" /></p>
				<p>この原因は</p>
				<ul>
				<li>https://developer.paypal.com/にログインしないと使えない</li>
				<li>クッキーにsequre属性が付いているからhttpsにしないとクッキーが無効になる</li>
				</ul>
				<p>ことなので、解決策はsandboxにはhttpsでアクセスすることです。</p>
				<p>いま、Google App EngineをPayPalから通知を受けるサーバとしてプログラムを書いています。Pythonは不慣れだから色々と大変です。</p>
				<p><div class="tmkm-amazon-view">
					<p><a href="http://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Google-App-Engine-Sanderson/dp/4873114756%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873114756"><img src="http://ecx.images-amazon.com/images/I/51DUsWCEfWL._SL160_.jpg" border="0" alt="" /></a></p>
					<p><a href="http://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Google-App-Engine-Sanderson/dp/4873114756%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873114756">プログラミング Google App Engine</a></p>
					<p><em>著者／訳者：</em>Array</p>
					<p><em>出版社：</em>オライリージャパン( 2011-01-24 )</p>
					<p><em>定価：</em>￥ 3,570</p>
					<p>大型本 ( 392 ページ )</p>
					<p>ISBN-10 : 4873114756</p>
					<p>ISBN-13 : 9784873114750</p>
				<hr class="tmkm-amazon-clear" /></div><br />
				<div class="tmkm-amazon-view">
					<p><a href="http://www.amazon.co.jp/%E3%81%99%E3%81%A3%E3%81%8D%E3%82%8A%E3%82%8F%E3%81%8B%E3%82%8BGoogle-App-Engine-Java%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E4%B8%AD%E7%94%B0/dp/4797357606%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4797357606"><img src="http://ecx.images-amazon.com/images/I/512pNjQz%2BKL._SL160_.jpg" border="0" alt="" /></a></p>
					<p><a href="http://www.amazon.co.jp/%E3%81%99%E3%81%A3%E3%81%8D%E3%82%8A%E3%82%8F%E3%81%8B%E3%82%8BGoogle-App-Engine-Java%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E4%B8%AD%E7%94%B0/dp/4797357606%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4797357606">すっきりわかるGoogle App Engine for Javaクラウドプログラミング</a></p>
					<p><em>著者／訳者：</em>Array</p>
					<p><em>出版社：</em>ソフトバンククリエイティブ( 2010-07-02 )</p>
					<p><em>定価：</em>￥ 3,360</p>
					<p>単行本 ( 480 ページ )</p>
					<p>ISBN-10 : 4797357606</p>
					<p>ISBN-13 : 9784797357608</p>
				<hr class="tmkm-amazon-clear" /></div></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2011/12/24/paypal%e3%81%aesandbox%e3%81%a7please-login-to-use-the-paypal-sandbox-features-%e3%81%ab%e3%81%aa%e3%82%8b%e5%95%8f%e9%a1%8c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ウェブサイトごとに別々の強力なパスワードを作ることは難しいのか</title>
		<link>http://blog.neoneet.jp/2011/08/30/%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%94%e3%81%a8%e3%81%ab%e5%88%a5%e3%80%85%e3%81%ae%e5%bc%b7%e5%8a%9b%e3%81%aa%e3%83%91%e3%82%b9%e3%83%af%e3%83%bc%e3%83%89%e3%82%92%e4%bd%9c/</link>
		<comments>http://blog.neoneet.jp/2011/08/30/%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%94%e3%81%a8%e3%81%ab%e5%88%a5%e3%80%85%e3%81%ae%e5%bc%b7%e5%8a%9b%e3%81%aa%e3%83%91%e3%82%b9%e3%83%af%e3%83%bc%e3%83%89%e3%82%92%e4%bd%9c/#comments</comments>
		<pubDate>Mon, 29 Aug 2011 21:41:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コンピュータ]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=274</guid>
		<description><![CDATA[「紙だけでサイトごとに異なるパスワードを生成する暗号、米研究者が考案」に関連して。 前から感じているのだけど、パスワードを使い回す人が多く、その理由はパスワードを覚えきれないからという。しかし、実のところ強力でサイトごとにバラバラなパスワードを生成し、それを忘れない方法はあると思う。簡単にいうとパスワードを覚えるのではなく、パスワードを生成するルールを覚えておくのだ。 仮に http://www.example.comというサイトがあるとしよう。ここで仮にパスワード生成のルールに「ドメイン名にsaltを加えてMD5する」と決めておく。saltはNEETにしようか。そうすればあとは必要なときにコンソールを叩くだけだ。 md5 -s "NEETwww.example.com" MD5 ("NEETwww.example.com") = 3bf864e8b76269f05cb5aa0405f02d5b こうして得られたパスワード3bf864e8b76269f05cb5aa0405f02d5bは十分に強いし、これをブルートフォース攻撃でクラックしようとしてもまず無理だろう。生年月日や電話番号ではないので想像も難しい。その割にMD5を計算できるパソコンがあればいつでもすぐにパスワードを復元できる。 この方法を使うときはsaltの内容とMD5を使ってパスワードを作っていることを他人に悟られないこと。別にMD5でなくてもいいんだけど。SHA1して先頭の24文字を採用するとかなんでもいい。]]></description>
			<content:encoded><![CDATA[				<p>「<a href="http://internet.watch.impress.co.jp/docs/news/20110829_473716.html">紙だけでサイトごとに異なるパスワードを生成する暗号、米研究者が考案</a>」に関連して。</p>
				<p>前から感じているのだけど、パスワードを使い回す人が多く、その理由はパスワードを覚えきれないからという。しかし、実のところ強力でサイトごとにバラバラなパスワードを生成し、それを忘れない方法はあると思う。簡単にいうとパスワードを覚えるのではなく、パスワードを生成するルールを覚えておくのだ。</p>
				<p>仮に http://www.example.comというサイトがあるとしよう。ここで仮にパスワード生成のルールに「ドメイン名にsaltを加えてMD5する」と決めておく。saltはNEETにしようか。そうすればあとは必要なときにコンソールを叩くだけだ。</p>
				<pre>
md5 -s "NEETwww.example.com"
MD5 ("NEETwww.example.com") = 3bf864e8b76269f05cb5aa0405f02d5b
</pre>
				<p>こうして得られたパスワード3bf864e8b76269f05cb5aa0405f02d5bは十分に強いし、これをブルートフォース攻撃でクラックしようとしてもまず無理だろう。生年月日や電話番号ではないので想像も難しい。その割にMD5を計算できるパソコンがあればいつでもすぐにパスワードを復元できる。</p>
				<p>この方法を使うときはsaltの内容とMD5を使ってパスワードを作っていることを他人に悟られないこと。別にMD5でなくてもいいんだけど。SHA1して先頭の24文字を採用するとかなんでもいい。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2011/08/30/%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%94%e3%81%a8%e3%81%ab%e5%88%a5%e3%80%85%e3%81%ae%e5%bc%b7%e5%8a%9b%e3%81%aa%e3%83%91%e3%82%b9%e3%83%af%e3%83%bc%e3%83%89%e3%82%92%e4%bd%9c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>BBEdit 10.0</title>
		<link>http://blog.neoneet.jp/2011/08/04/bbedit-10-0/</link>
		<comments>http://blog.neoneet.jp/2011/08/04/bbedit-10-0/#comments</comments>
		<pubDate>Wed, 03 Aug 2011 23:39:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[コンピュータ]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=265</guid>
		<description><![CDATA[最近他のブログばかり更新しているけど、こういう話題はあまり読む人がいないだろうからこっちに書く。 BBEditが39.9ドル＝3,192円（1ドル80円換算） BBEdit 10.0が出ている。BBEditは昔からMacの定番エディタとして有名だがあまりにも高いのでレジストしようとは思わなかった。いま主に使っているエディタはCotEditorとmiである。フリーだし十分高機能だからこれでいいと思っていた。しかし、いまBBEditはそう高いとは言えない。 unidic-mecabのソースコードを見てみるとVerb.csvが90.8MBもある。これをmiとかCotEditorとかで開くと非常に重くて作業が困難である。ところがBBEditはいともあっさり開いて編集ができた。やはりフリーのエディタと定番のエディタは違う、高いだけのことはある。 ただ、いまのところBBEditを買おうと思う動機は巨大ファイルの編集も楽々くらいしかない。Lionのフルスクリーンにもいち早く対応しているし、フリーのエディタよりも開発は精力的なのも魅力だけど、これはそのうちフリーのエディタも対応するだろう。 SubversionやCVS対応は最近のgitより古い感じもする。Lionにバージョン機能があるし個人でバージョン管理をする用途ならサーバは要りそうもない。チーム開発ではCVSってどうなのか。 FTP/SFTP機能だけどscpには対応していないのだろうか。miもFTP機能はあるけど最近はあまり使っていない。FTPを使う機会が減っている。 エディタにいま求める物はソースコードを書く機能が優れているかではないかなと分析している。そのときメニューを見渡してみるとHTML関連は豊富なのだけど、RubyとかC++はそれほど魅力を感じない。HTMLを書くエディタならCodaを買うべきだろう。C++のコードを書いてみたけど、Xcodeのほうがよさそうな感じ。ソースコード関連だとVicoとかSublime Text 2のほうが期待できそう。ただし、こいつらは巨大ファイルの取り扱いでBBEditに劣る感じがする。TextMateも放置されて久しいし、これが定番というテキストエディタがないのが残念。]]></description>
			<content:encoded><![CDATA[				<p>最近他のブログばかり更新しているけど、こういう話題はあまり読む人がいないだろうからこっちに書く。</p>
				<h2>BBEditが39.9ドル＝3,192円（1ドル80円換算）</h2>
				<p><a href="http://www.barebones.com/products/bbedit/">BBEdit 10.0</a>が出ている。BBEditは昔からMacの定番エディタとして有名だがあまりにも高いのでレジストしようとは思わなかった。いま主に使っているエディタはCotEditorとmiである。フリーだし十分高機能だからこれでいいと思っていた。しかし、いまBBEditはそう高いとは言えない。</p>
				<p>unidic-mecabのソースコードを見てみるとVerb.csvが90.8MBもある。これをmiとかCotEditorとかで開くと非常に重くて作業が困難である。ところがBBEditはいともあっさり開いて編集ができた。やはりフリーのエディタと定番のエディタは違う、高いだけのことはある。</p>
				<p>ただ、いまのところBBEditを買おうと思う動機は巨大ファイルの編集も楽々くらいしかない。Lionのフルスクリーンにもいち早く対応しているし、フリーのエディタよりも開発は精力的なのも魅力だけど、これはそのうちフリーのエディタも対応するだろう。</p>
				<p>SubversionやCVS対応は最近のgitより古い感じもする。Lionにバージョン機能があるし個人でバージョン管理をする用途ならサーバは要りそうもない。チーム開発ではCVSってどうなのか。</p>
				<p>FTP/SFTP機能だけどscpには対応していないのだろうか。miもFTP機能はあるけど最近はあまり使っていない。FTPを使う機会が減っている。</p>
				<p>エディタにいま求める物はソースコードを書く機能が優れているかではないかなと分析している。そのときメニューを見渡してみるとHTML関連は豊富なのだけど、RubyとかC++はそれほど魅力を感じない。HTMLを書くエディタなら<a href="http://www.panic.com/jp/coda/">Coda</a>を買うべきだろう。C++のコードを書いてみたけど、Xcodeのほうがよさそうな感じ。ソースコード関連だと<a href="http://www.vicoapp.com/">Vico</a>とか<a href="http://www.sublimetext.com/2">Sublime Text 2</a>のほうが期待できそう。ただし、こいつらは巨大ファイルの取り扱いでBBEditに劣る感じがする。TextMateも放置されて久しいし、これが定番というテキストエディタがないのが残念。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2011/08/04/bbedit-10-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ミルカさんボット</title>
		<link>http://blog.neoneet.jp/2010/05/18/%e3%83%9f%e3%83%ab%e3%82%ab%e3%81%95%e3%82%93%e3%83%9c%e3%83%83%e3%83%88/</link>
		<comments>http://blog.neoneet.jp/2010/05/18/%e3%83%9f%e3%83%ab%e3%82%ab%e3%81%95%e3%82%93%e3%83%9c%e3%83%83%e3%83%88/#comments</comments>
		<pubDate>Mon, 17 May 2010 16:28:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=260</guid>
		<description><![CDATA[ベクトルってつぶやきに反応してこっそり「&#8230;ヴェクタ」とつぶやくbotとかいないかな という要望があったので作ってみた。 基本 ほとんどの手順は株ニュースと同じ。今回はTwitter::Searchを使う。結果をHashie::Meshで受け取るので、必要なものだけ取り出す。一度RTしたものには反応しないことにする。 以下ソース。 #!/opt/local/bin/ruby -Ku require 'rubygems' require 'mechanize' require 'nokogiri' require 'kconv' require 'logger' require 'oauth' require 'twitter' #--------------------------------------------------------------------------- # 定数 #--------------------------------------------------------------------------- CONSUMER_KEY = "きー" CONSUMER_SECRET = "しーくれっと" ACCESS_TOKEN = "とーくん" ACCESS_TOKEN_SECRET = "とーくんしーくれっと" #--------------------------------------------------------------------------- # Retweet #--------------------------------------------------------------------------- def retweet( r ) user = r["from_user"] text = r["text"] id = r["id"].to_s # [...]]]></description>
			<content:encoded><![CDATA[				<blockquote><p>
				ベクトルってつぶやきに反応してこっそり「&#8230;ヴェクタ」とつぶやくbotとかいないかな
				</p></blockquote>
				<p>という要望があったので作ってみた。</p>
				<h2>基本</h2>
				<p>ほとんどの手順は株ニュースと同じ。今回はTwitter::Searchを使う。結果をHashie::Meshで受け取るので、必要なものだけ取り出す。一度RTしたものには反応しないことにする。</p>
				<p>以下ソース。</p>
				<pre class="prettyprint">
#!/opt/local/bin/ruby -Ku
require 'rubygems'
require 'mechanize'
require 'nokogiri'
require 'kconv'
require 'logger'

require 'oauth'
require 'twitter'

#---------------------------------------------------------------------------
# 定数
#---------------------------------------------------------------------------

CONSUMER_KEY = "きー"
CONSUMER_SECRET = "しーくれっと"
ACCESS_TOKEN = "とーくん"
ACCESS_TOKEN_SECRET = "とーくんしーくれっと"

#---------------------------------------------------------------------------
# Retweet
#---------------------------------------------------------------------------
def retweet( r )

	user = r["from_user"]
	text = r["text"]
	id = r["id"].to_s

	# もともと「ヴェクタ」を喋るものには反応しない
	return if text.include?("ヴェクタ")

	# 手抜き
	f = open("recent_tweet.txt", "a")
	f.close

	# 過去にRTしているか調べる
	f = open("recent_tweet.txt", "r")
	while recent_id = f.gets
		if recent_id.include?(id) then
			f.close
			return
		end
	end

	# RTする
	f = open("recent_tweet.txt", "a")
	f.puts(id)
	consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => "http://twitter.com")
	oauth = Twitter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
	oauth.authorize_from_access(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
	twitter_client = Twitter::Base.new(oauth)

	tweet = "...ヴェクタ QT @#{user} #{text}"
	twitter_client.update(tweet, {:in_reply_to_status_id => id})
#	twitter_client.update(tweet)
	$log.info("Twitterに投稿しました：" + tweet)
	f.close

end

#---------------------------------------------------------------------------
# main
#---------------------------------------------------------------------------
def main

	Twitter::Search.new('ベクトル').each do |r|

		if r.class == Hashie::Mash then
			retweet(r)
		end
	end
end

#---------------------------------------------------------------------------
# エントリポイント
#---------------------------------------------------------------------------

#$log = Logger.new("log.txt")
$log = Logger.new(STDOUT)
$log.level = Logger::INFO

main
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/18/%e3%83%9f%e3%83%ab%e3%82%ab%e3%81%95%e3%82%93%e3%83%9c%e3%83%83%e3%83%88/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rubyでmixiの日記をバックアップする</title>
		<link>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7mixi%e3%81%ae%e6%97%a5%e8%a8%98%e3%82%92%e3%83%90%e3%83%83%e3%82%af%e3%82%a2%e3%83%83%e3%83%97%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7mixi%e3%81%ae%e6%97%a5%e8%a8%98%e3%82%92%e3%83%90%e3%83%83%e3%82%af%e3%82%a2%e3%83%83%e3%83%97%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Wed, 05 May 2010 09:50:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=253</guid>
		<description><![CDATA[mixiを退会すると日記は消えてしまいます。その日記を手っ取り早く手元に残しておきたいとき、1つずつ手作業でやっていると大変です。ここではそれを自動化します。 準備 まず普通にWebブラウザでmixiにログインして日記を見ます。FirefoxだとFirebugが便利です。 FirebugでDOMツリーを見ていくと該当の部分が青く反転するので、必要な場所を絞り込んでいきます。最後に、右クリックをして「XPathをコピー」を選んでやると、XPathを入手できます。 xpathを入手したら、これを利用して解析していきます。ただし、Firefoxではtbodyタグを勝手に挟むため、これを除去します。 コード #!/usr/local/bin/ruby -Ku require 'rubygems' require 'mechanize' require 'nokogiri' require 'kconv' # 簡易待ち付きget def get(url) sleep(10) $agent.get(url); $agent.page.encoding = "UTF-8" end #変数 owner_id = mixiのID diary_url = "http://mixi.jp/list_diary.pl?id=#{owner_id}" # mixiのトップページにアクセス $agent = Mechanize.new $agent.get("http://mixi.jp/") $agent.page.encoding = "UTF-8" # ログイン $agent.page.form_with(:name => "login_form" ) do &#124;f&#124; f.field_with(:name => 'email').value = "めーるあどれす" [...]]]></description>
			<content:encoded><![CDATA[				<p>mixiを退会すると日記は消えてしまいます。その日記を手っ取り早く手元に残しておきたいとき、1つずつ手作業でやっていると大変です。ここではそれを自動化します。</p>
				<h2>準備</h2>
				<p>まず普通にWebブラウザでmixiにログインして日記を見ます。FirefoxだとFirebugが便利です。</p>
				<p><img src="http://www.onaneet.org/blog/wp-content/uploads/2009/04/firebug.png" /></p>
				<p>FirebugでDOMツリーを見ていくと該当の部分が青く反転するので、必要な場所を絞り込んでいきます。最後に、右クリックをして「XPathをコピー」を選んでやると、XPathを入手できます。</p>
				<p><img src="http://www.onaneet.org/blog/wp-content/uploads/2009/04/xpath.png"/></p>
				<p>xpathを入手したら、これを利用して解析していきます。ただし、Firefoxではtbodyタグを勝手に挟むため、これを除去します。</p>
				<h3>コード</h3>
				<pre class="prettyprint">
#!/usr/local/bin/ruby -Ku
require 'rubygems'
require 'mechanize'
require 'nokogiri'
require 'kconv'

# 簡易待ち付きget
def get(url)
	sleep(10)
	$agent.get(url);
	$agent.page.encoding = "UTF-8"
end

#変数
owner_id = mixiのID
diary_url = "http://mixi.jp/list_diary.pl?id=#{owner_id}"

# mixiのトップページにアクセス
$agent = Mechanize.new
$agent.get("http://mixi.jp/")
$agent.page.encoding = "UTF-8"

# ログイン
$agent.page.form_with(:name => "login_form" ) do |f|
	f.field_with(:name => 'email').value = "めーるあどれす"
	f.field_with(:name => 'password').value = "ぱすわーど"
	f.click_button
end

puts "ログインしました"

# 日記トップを取得
get(diary_url)
parser = Nokogiri::HTML.parse($agent.page.body, nil)
diary = parser.xpath("/html/body/div/div[2]/div/div[3]/div[2]/div[2]").to_html.toutf8
diaries = diary.scan(/
<li>.*?\"(.*?)\".*?\"(.*?)\".*?li>/)

diaries.each do |d|
	each_diary = "http://mixi.jp/#{d[0]}"
	puts "#{d[1]}を処理"
	Dir::mkdir(d[1])
	Dir::chdir(d[1])

	get(each_diary)

	parser = Nokogiri::HTML.parse($agent.page.body, nil)
	diary_list = parser.xpath('//*[@id="bodyMainAreaMain"]').to_html.toutf8
	entrirs = diary_list.scan(/
<dt>.*?\"(view_diary.*?)\">(.*?)</)

	entrirs.each do |e|
		entry_url = "http://mixi.jp/#{e[0]}"
		get(entry_url)
		parser = Nokogiri::HTML.parse($agent.page.body, nil)
		contents = parser.xpath('//*[@id="bodyMainAreaMain"]').to_html.toutf8
		name = e[1].gsub("/", "／")
		f = open(name + ".html",'w')
		f.puts "<html>"
		f.puts "<head>"
		f.puts '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'
		f.puts "</head>"
		f.puts "<body>"
		f.puts contents
		f.puts "</body>"
		f.puts "</html>"
		f.close
	end

	Dir::chdir("../")
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7mixi%e3%81%ae%e6%97%a5%e8%a8%98%e3%82%92%e3%83%90%e3%83%83%e3%82%af%e3%82%a2%e3%83%83%e3%83%97%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RubyでSBIランキングの売り越し額を調べる</title>
		<link>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7sbi%e3%83%a9%e3%83%b3%e3%82%ad%e3%83%b3%e3%82%b0%e3%81%ae%e5%a3%b2%e3%82%8a%e8%b6%8a%e3%81%97%e9%a1%8d%e3%82%92%e8%aa%bf%e3%81%b9%e3%82%8b/</link>
		<comments>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7sbi%e3%83%a9%e3%83%b3%e3%82%ad%e3%83%b3%e3%82%b0%e3%81%ae%e5%a3%b2%e3%82%8a%e8%b6%8a%e3%81%97%e9%a1%8d%e3%82%92%e8%aa%bf%e3%81%b9%e3%82%8b/#comments</comments>
		<pubDate>Wed, 05 May 2010 09:35:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=250</guid>
		<description><![CDATA[SBI証券は個人投資家が多く使っている証券会社です。通常は個人投資家は機関投資家に搾取されるようにできています。株価が暴落すると個人投資家は飛びつき、下げ止まらないとどんどんナンピン買いをして損を膨らませていきます。投資のスタイルは人それぞれですが、個人が買い越している間は手を出さずに売り越しに転じた辺りで買うというのもよいと思っています。 これを毎日、前場と後場にランキングを見て、買い代金と売り代金を比較してソートするのは面倒ですので、これを自動でやらせます。 方針 いつものようにMechanizeで該当のページを読み、xpathで必要な部分だけ取り出して解析します。 売りと買いを配列に入れて1つずつ照合、同じコードを持つもので買い代金と売り代金の差を取って新しい配列に入れます。これをソートして出力すればOK。 実装例 #!/usr/bin/ruby -Ku require 'rubygems' require 'nokogiri' require 'mechanize' require 'logger' require 'kconv' SBI_RANKING = "https://trading1.sbisec.co.jp/ETGate/?_ControlID=WPLETmgR001Control&#38;_DataStoreID=DSWPLETmgR001Control&#38;burl=search_market&#38;dir=ranking%2F&#38;file=et_trading_value.html&#38;cat1=market&#38;cat2=ranking&#38;getFlg=on" BUY_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr/td[2]/table[4]/tr/td[1]/table" SELL_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[4]/tr/td[3]/table" DATE_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[3]/tr/td[1]/b" TIME_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[3]/tr/td[2]" #--------------------------------------------------------------------------- # main #--------------------------------------------------------------------------- def main agent = Mechanize.new log = Logger.new(STDOUT) # log = Logger.new("sbi_ranking.log") log.level = Logger::INFO agent.get(SBI_RANKING) agent.page.encoding = [...]]]></description>
			<content:encoded><![CDATA[				<p>SBI証券は個人投資家が多く使っている証券会社です。通常は個人投資家は機関投資家に搾取されるようにできています。株価が暴落すると個人投資家は飛びつき、下げ止まらないとどんどんナンピン買いをして損を膨らませていきます。投資のスタイルは人それぞれですが、個人が買い越している間は手を出さずに売り越しに転じた辺りで買うというのもよいと思っています。</p>
				<p>これを毎日、前場と後場にランキングを見て、買い代金と売り代金を比較してソートするのは面倒ですので、これを自動でやらせます。</p>
				<h2>方針</h2>
				<p>いつものようにMechanizeで該当のページを読み、xpathで必要な部分だけ取り出して解析します。</p>
				<p>売りと買いを配列に入れて1つずつ照合、同じコードを持つもので買い代金と売り代金の差を取って新しい配列に入れます。これをソートして出力すればOK。</p>
				<h3>実装例</h3>
				<pre class="prettyprint">
#!/usr/bin/ruby -Ku
require 'rubygems'
require 'nokogiri'
require 'mechanize'
require 'logger'
require 'kconv'

SBI_RANKING = "https://trading1.sbisec.co.jp/ETGate/?_ControlID=WPLETmgR001Control&amp;_DataStoreID=DSWPLETmgR001Control&amp;burl=search_market&amp;dir=ranking%2F&amp;file=et_trading_value.html&amp;cat1=market&amp;cat2=ranking&amp;getFlg=on"

BUY_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr/td[2]/table[4]/tr/td[1]/table"
SELL_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[4]/tr/td[3]/table"
DATE_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[3]/tr/td[1]/b"
TIME_XPATH = "/html/body/div[@id='middleArea']/div[@id='middleAreaM']/table/tr/td[1]/div[@id='main']/table[2]/tr[1]/td[2]/table[3]/tr/td[2]"

#---------------------------------------------------------------------------
# main
#---------------------------------------------------------------------------
def main

	agent = Mechanize.new
	log = Logger.new(STDOUT)
#	log = Logger.new("sbi_ranking.log")
	log.level = Logger::INFO
	agent.get(SBI_RANKING)
	agent.page.encoding = "Shift_JIS"

	html = agent.page.body
	parser = Nokogiri::HTML.parse(html, nil)

	# 時刻
	ranking_time = parser.xpath(TIME_XPATH)
	/(\d{2,2}):(\d{2,2})<\/td>$/ =~ ranking_time.to_html.toutf8
	sbi_hour = $1
	sbi_min = $2

	# 日付
	ranking_date = parser.xpath(DATE_XPATH)
	/.*?(\d{1,2})\/(\d{1,2})/ =~ ranking_date.to_html.toutf8
	sbi_month = $1
	sbi_day = $2

	buy_code = []
	buy_name = []
	buy_trading_value = []

	sell_code = []
	sell_name = []
	sell_trading_value = []

	for i in 3..22 do
		buy = parser.xpath(BUY_XPATH + "/tr[#{i}]")
		e = buy.to_html.toutf8.gsub("\n", "")
		/stock_sec_code_mul=(\d{4,4}).*?exchange_code.*?>(.*?)<.*?([\d,]+?)<\/div>/ =~ e
		buy_code << $1
		buy_name << $2
		buy_trading_value << $3.gsub(",", "")
	end

	for i in 3..22 do
		sell = parser.xpath(SELL_XPATH + "/tr[#{i}]")
		e = sell.to_html.toutf8.gsub("\n", "")
		/stock_sec_code_mul=(\d{4,4}).*?exchange_code.*?>(.*?)<.*?([\d,]+?)<\/div>/ =~ e
		sell_code << $1
		sell_name << $2
		sell_trading_value << $3.gsub(",", "")
	end

	result = []
	for i in 0..buy_code.size - 1 do
		for j in 0..sell_code.size - 1 do
			if buy_code[i] == sell_code[j] then
				result.push( [buy_code[i], buy_name[i], ( buy_trading_value[i].to_i - sell_trading_value[j].to_i )] )
			end
		end
	end

	result = result.sort{ |a, b| a[2] <=> b[2] }

	for i in 0..result.size - 1 do
		puts "#{result[i][0]}, #{result[i][1]}, #{result[i][2]}"
	end
end

#---------------------------------------------------------------------------
# エントリポイント
# 単にmainを呼ぶだけ
#---------------------------------------------------------------------------
main
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7sbi%e3%83%a9%e3%83%b3%e3%82%ad%e3%83%b3%e3%82%b0%e3%81%ae%e5%a3%b2%e3%82%8a%e8%b6%8a%e3%81%97%e9%a1%8d%e3%82%92%e8%aa%bf%e3%81%b9%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RubyでNHKラジオ講座のストリーミングを保存する</title>
		<link>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7nhk%e3%83%a9%e3%82%b8%e3%82%aa%e8%ac%9b%e5%ba%a7%e3%81%ae%e3%82%b9%e3%83%88%e3%83%aa%e3%83%bc%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7nhk%e3%83%a9%e3%82%b8%e3%82%aa%e8%ac%9b%e5%ba%a7%e3%81%ae%e3%82%b9%e3%83%88%e3%83%aa%e3%83%bc%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Wed, 05 May 2010 06:58:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=245</guid>
		<description><![CDATA[NHKのラジオ講座は安価に語学を学ぶことができる。ラジオを持っていない人でもストリーミングで聴くことができる。ただしロシア語などいくつかの講座は提供されていない。 ストリーミングは電車の中でiPodに入れて聴きたいと思ったときには不便である。ここではストリーミングファイルを自動的にダウンロードしてmp3に変換する。 ツールを手に入れる ストリーミングファイルをダウンロードするにはRTMPDumpを使う。ビルド版もあるし、portやyumなどでインストールしてもいい。 flvをmp3に変換するにはFFmpegを使う。これは多種のコーデックをサポートするツールだが、そのぶんビルドが面倒臭い。既にビルドされているものを使うか、やはりportやyumを使って入手するとよい。 準備 まず語学講座のURLを連想配列に入れる。また、flvの情報が記録されているXMLファイルlistdataflv.xmlやストリーミングファイル置き場のURLも定数に入れておく。 #!/usr/local/bin/ruby -Ku require 'rubygems' require 'mechanize' require 'nokogiri' require 'kconv' require 'logger' require "fileutils" RTMPDUMP = "rtmpdump " FFMPEG = "ffmpeg " STREAMING_BASE = "rtmp://flv9.nhk.or.jp/flv9/_definst_/gogaku/streaming/flv/" COURSE_XML = "listdataflv.xml" COURSE = { "基礎英語1" => "http://www.nhk.or.jp/gogaku/english/basic1/", "基礎英語2" => "http://www.nhk.or.jp/gogaku/english/basic2/", "基礎英語3" => "http://www.nhk.or.jp/gogaku/english/basic3/", "英語5分間トレーニング" => "http://www.nhk.or.jp/gogaku/english/training/", "ラジオ英会話" => "http://www.nhk.or.jp/gogaku/english/kaiwa/", "入門ビジネス英語" => [...]]]></description>
			<content:encoded><![CDATA[				<p>NHKのラジオ講座は安価に語学を学ぶことができる。ラジオを持っていない人でもストリーミングで聴くことができる。ただしロシア語などいくつかの講座は提供されていない。</p>
				<p>ストリーミングは電車の中でiPodに入れて聴きたいと思ったときには不便である。ここではストリーミングファイルを自動的にダウンロードしてmp3に変換する。</p>
				<h2>ツールを手に入れる</h2>
				<p>ストリーミングファイルをダウンロードするには<a href="http://rtmpdump.mplayerhq.hu/">RTMPDump</a>を使う。ビルド版もあるし、portやyumなどでインストールしてもいい。</p>
				<p>flvをmp3に変換するには<a href="http://www.ffmpeg.org/">FFmpeg</a>を使う。これは多種のコーデックをサポートするツールだが、そのぶんビルドが面倒臭い。既にビルドされているものを使うか、やはりportやyumを使って入手するとよい。</p>
				<h2>準備</h2>
				<p>まず語学講座のURLを連想配列に入れる。また、flvの情報が記録されているXMLファイルlistdataflv.xmlやストリーミングファイル置き場のURLも定数に入れておく。</p>
				<pre class="prettyprint">
#!/usr/local/bin/ruby -Ku
require 'rubygems'
require 'mechanize'
require 'nokogiri'
require 'kconv'
require 'logger'
require "fileutils"

RTMPDUMP = "rtmpdump "
FFMPEG   = "ffmpeg "
STREAMING_BASE = "rtmp://flv9.nhk.or.jp/flv9/_definst_/gogaku/streaming/flv/"
COURSE_XML = "listdataflv.xml"

COURSE = {
	"基礎英語1" => "http://www.nhk.or.jp/gogaku/english/basic1/",
	"基礎英語2" => "http://www.nhk.or.jp/gogaku/english/basic2/",
	"基礎英語3" => "http://www.nhk.or.jp/gogaku/english/basic3/",
	"英語5分間トレーニング" => "http://www.nhk.or.jp/gogaku/english/training/",
	"ラジオ英会話"  => "http://www.nhk.or.jp/gogaku/english/kaiwa/",
	"入門ビジネス英語" => "http://www.nhk.or.jp/gogaku/english/business1/",
	"実践ビジネス英語" => "http://www.nhk.or.jp/gogaku/english/business2/",
	"まいにち中国語" => "http://www.nhk.or.jp/gogaku/chinese/kouza/",
	"まいにちフランス語" => "http://www.nhk.or.jp/gogaku/french/kouza/",
	"まいにちイタリア語" => "http://www.nhk.or.jp/gogaku/italian/kouza/",
	"まいにちハングル講座" => "http://www.nhk.or.jp/gogaku/hangeul/kouza/",
	"まいにちドイツ語" => "http://www.nhk.or.jp/gogaku/german/kouza/",
	"まいにちスペイン語" => "http://www.nhk.or.jp/gogaku/spanish/kouza/"
}</pre>
				<h2>ダウンロードメソッドを作る</h2>
				<p>まず連想配列の名前を与えてdownloadメソッドを呼ぶ。存在しない講座ならreturnしておく。</p>
				<p>ファイルが乱雑に置かれると面倒なので講座ごとにフォルダを作る。まだフォルダがなければ作成しておく。</p>
				<p>MechanizeでXMLファイルをgetして、NokogiriのXMLパーサで解析する。解析にはxpathを使う。ファイル名はfile属性にある。講座名や日付もあるので利用する。</p>
				<p>まだファイルがないときには、RTMPDumpを用いてflvファイルをダウンロードする。mp3ファイルがまだないときは続けてFFmpegを使って変換する。</p>
				<p>最後に連続してアクセスしないように待ちを入れる。</p>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# ラジオ講座のダウンロード
#---------------------------------------------------------------------------

def download(course)

	if COURSE[course] == nil then
		return
	end

	unless( FileTest.exist?(course) ) then
		FileUtils.mkdir_p course
	end

	agent = Mechanize.new
	url = COURSE[course] + COURSE_XML
	agent.get(url)
	parser = Nokogiri::XML.parse(agent.page.body, nil)
	parser.xpath("musicdata/music").each do |element|
		flvname = element.attr("file")
		filename = course + "/" + element.attr("kouza") + "_" + element.attr("hdate")

		unless( FileTest.exist?("#{filename}.flv") ) then
			command = RTMPDUMP + "-o #{filename}.flv -r #{STREAMING_BASE+flvname}"
			system(command)
		end

		unless( FileTest.exist?("#{filename}.mp3") ) then
			command = FFMPEG + "-i #{filename}.flv #{filename}.mp3"
			system(command)
		end
	end
	sleep(1)
end
</pre>
				<h2>聴きたい講座をダウンロードする</h2>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# エントリポイント
#---------------------------------------------------------------------------

download("基礎英語1")
</pre>
				<p>聴きたい講座を指定してdownloadメソッドを呼ぶ。</p>
				<h3>実行結果</h3>
				<pre>
RTMPDump&nbsp;v2.2
(c)&nbsp;2010&nbsp;Andrej&nbsp;Stepanchuk,&nbsp;Howard&nbsp;Chu,&nbsp;The&nbsp;Flvstreamer&nbsp;Team;&nbsp;license:&nbsp;GPL
Connecting&nbsp;...
Starting&nbsp;download&nbsp;at:&nbsp;0.000&nbsp;kB
Metadata:
&nbsp;&nbsp;duration&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;900.76
&nbsp;&nbsp;audiodatarate&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;64.00
&nbsp;&nbsp;audiodelay&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.04
&nbsp;&nbsp;audiocodecid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.00
&nbsp;&nbsp;canSeekToEnd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRUE
7577.419&nbsp;kB&nbsp;/&nbsp;900.81&nbsp;sec&nbsp;(100.0%)
Download&nbsp;complete
FFmpeg&nbsp;version&nbsp;0.5.1,&nbsp;Copyright&nbsp;(c)&nbsp;2000-2009&nbsp;Fabrice&nbsp;Bellard,&nbsp;et&nbsp;al.
&nbsp;&nbsp;configuration:&nbsp;--prefix=/opt/local&nbsp;--disable-vhook&nbsp;--enable-gpl&nbsp;--enable-postproc&nbsp;--enable-swscale&nbsp;--enable-avfilter&nbsp;--enable-avfilter-lavf&nbsp;--enable-libmp3lame&nbsp;--enable-libvorbis&nbsp;--enable-libtheora&nbsp;--enable-libdirac&nbsp;--enable-libschroedinger&nbsp;--enable-libfaac&nbsp;--enable-libfaad&nbsp;--enable-libxvid&nbsp;--enable-libx264&nbsp;--enable-nonfree&nbsp;--mandir=/opt/local/share/man&nbsp;--enable-shared&nbsp;--enable-pthreads&nbsp;--cc=/usr/bin/gcc-4.2&nbsp;--arch=x86_64
&nbsp;&nbsp;libavutil&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;49.15.&nbsp;0&nbsp;/&nbsp;49.15.&nbsp;0
&nbsp;&nbsp;libavcodec&nbsp;&nbsp;&nbsp;&nbsp;52.20.&nbsp;1&nbsp;/&nbsp;52.20.&nbsp;1
&nbsp;&nbsp;libavformat&nbsp;&nbsp;&nbsp;52.31.&nbsp;0&nbsp;/&nbsp;52.31.&nbsp;0
&nbsp;&nbsp;libavdevice&nbsp;&nbsp;&nbsp;52.&nbsp;1.&nbsp;0&nbsp;/&nbsp;52.&nbsp;1.&nbsp;0
&nbsp;&nbsp;libavfilter&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;4.&nbsp;0&nbsp;/&nbsp;&nbsp;1.&nbsp;4.&nbsp;0
&nbsp;&nbsp;libswscale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;7.&nbsp;1&nbsp;/&nbsp;&nbsp;1.&nbsp;7.&nbsp;1
&nbsp;&nbsp;libpostproc&nbsp;&nbsp;&nbsp;51.&nbsp;2.&nbsp;0&nbsp;/&nbsp;51.&nbsp;2.&nbsp;0
&nbsp;&nbsp;built&nbsp;on&nbsp;Apr&nbsp;11&nbsp;2010&nbsp;12:49:33,&nbsp;gcc:&nbsp;4.2.1&nbsp;(Apple&nbsp;Inc.&nbsp;build&nbsp;5646)&nbsp;(dot&nbsp;1)
Input&nbsp;#0,&nbsp;flv,&nbsp;from&nbsp;'基礎英語1/基礎英語14月30日放送分.flv':
&nbsp;&nbsp;Duration:&nbsp;00:15:00.75,&nbsp;start:&nbsp;0.000000,&nbsp;bitrate:&nbsp;64&nbsp;kb/s
&nbsp;&nbsp;&nbsp;&nbsp;Stream&nbsp;#0.0:&nbsp;Audio:&nbsp;mp3,&nbsp;44100&nbsp;Hz,&nbsp;mono,&nbsp;s16,&nbsp;64&nbsp;kb/s
Output&nbsp;#0,&nbsp;mp3,&nbsp;to&nbsp;'基礎英語1/基礎英語14月30日放送分.mp3':
&nbsp;&nbsp;&nbsp;&nbsp;Stream&nbsp;#0.0:&nbsp;Audio:&nbsp;libmp3lame,&nbsp;44100&nbsp;Hz,&nbsp;mono,&nbsp;s16,&nbsp;64&nbsp;kb/s
Stream&nbsp;mapping:
&nbsp;&nbsp;Stream&nbsp;#0.0&nbsp;-&gt;&nbsp;#0.0
Press&nbsp;[q]&nbsp;to&nbsp;stop&nbsp;encoding
[libmp3lame&nbsp;@&nbsp;0x101812800]lame:&nbsp;output&nbsp;buffer&nbsp;too&nbsp;small&nbsp;(buffer&nbsp;index:&nbsp;9404,&nbsp;free&nbsp;bytes:&nbsp;388)
Audio&nbsp;encoding&nbsp;failed
</pre>
				<p>FFmpegのバージョンによってはAudio encoding failedになる。解決策が<a href="http://wiki.crav-ing.com/index.php?%E5%90%8C%E6%A2%B1ffmpeg%E3%81%AElame%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E4%B8%8D%E5%85%B7%E5%90%88">ここ</a>にある。</p>
				<pre>
[libmp3lame&nbsp;@&nbsp;0x101812800]lame:&nbsp;output&nbsp;buffer&nbsp;too&nbsp;small&nbsp;(buffer&nbsp;index:&nbsp;9404,&nbsp;free&nbsp;bytes:&nbsp;388)
Audio&nbsp;encoding&nbsp;failed
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a7nhk%e3%83%a9%e3%82%b8%e3%82%aa%e8%ac%9b%e5%ba%a7%e3%81%ae%e3%82%b9%e3%83%88%e3%83%aa%e3%83%bc%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%92%e4%bf%9d%e5%ad%98%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rubyで2chの市況1板のニュースを集めTweetする</title>
		<link>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a72ch%e3%81%ae%e5%b8%82%e6%b3%811%e6%9d%bf%e3%81%ae%e3%83%8b%e3%83%a5%e3%83%bc%e3%82%b9%e3%82%92%e9%9b%86%e3%82%81tweet%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a72ch%e3%81%ae%e5%b8%82%e6%b3%811%e6%9d%bf%e3%81%ae%e3%83%8b%e3%83%a5%e3%83%bc%e3%82%b9%e3%82%92%e9%9b%86%e3%82%81tweet%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Tue, 04 May 2010 19:15:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=235</guid>
		<description><![CDATA[2chの市況1板には多くの人（個人投資家）が集まって、株価に一喜一憂している。そのため、何かよい材料がないか常に探し求めている状況にある。もしよいニュースを見つけたら「キタ━━━━━━(゜∀゜)━━━━━━」とすぐに書き込んでくれる。これは場合によると自分の見ているニュースサイトに掲載されるより早く情報を手に入れられるかも知れない。 しかし、スレッドは多く全部見ているのは大変である。雑談も多いし、必要な情報だけいち早く報告したらトレードに有利なのではないかと考えた。信頼性の高い情報はソースを載せることが多いので、ニュースサイトのURL付きの書き込みを有用度が高いと判断することにする。 スレッド一覧を取得する スレッドの一覧は前回書いたようにsubject.txtを見れば手に入る。これをmechanizeでgetする。 BOARD = "http://anchorage.2ch.net/livemarket1/" DAT = "dat/" SUBJECT = "subject.txt" このように定数を用意しておく。 株価コードで絞り込む 市況1板では慣例である銘柄についてのスレッドに株価コードを入れることになっている。自分にとって関心のある銘柄のコードで探せば上手く見つけられる。これを事前に用意して配列に入れておく。 STOCK_CODE = [ "2497", "5401", "5405", "5411", "5713", "6301", "6752", "6758", "7203", "7974", "8002", "8031", "8058", "8306", "8316", "8411", "8802", "9132", "9433", "9984", "日経" ] ここでは出来高の大きそうな銘柄と「日経」に関するスレッドを読むことにする。1行ずつSTOCK_CODEの配列にある文字列を含むか見ていき、該当するものだけをdatsという配列に格納する。 #--------------------------------------------------------------------------- # getThreads #--------------------------------------------------------------------------- def getThreads(list) # 読むべきdatリスト dats = [] # 1行ずつ判定 [...]]]></description>
			<content:encoded><![CDATA[				<p>2chの市況1板には多くの人（個人投資家）が集まって、株価に一喜一憂している。そのため、何かよい材料がないか常に探し求めている状況にある。もしよいニュースを見つけたら「キタ━━━━━━(゜∀゜)━━━━━━」とすぐに書き込んでくれる。これは場合によると自分の見ているニュースサイトに掲載されるより早く情報を手に入れられるかも知れない。</p>
				<p>しかし、スレッドは多く全部見ているのは大変である。雑談も多いし、必要な情報だけいち早く報告したらトレードに有利なのではないかと考えた。信頼性の高い情報はソースを載せることが多いので、ニュースサイトのURL付きの書き込みを有用度が高いと判断することにする。</p>
				<h2>スレッド一覧を取得する</h2>
				<p>スレッドの一覧は前回書いたようにsubject.txtを見れば手に入る。これをmechanizeでgetする。</p>
				<pre class="prettyprint">
BOARD = "http://anchorage.2ch.net/livemarket1/"
DAT = "dat/"
SUBJECT = "subject.txt"
</pre>
				<p>このように定数を用意しておく。</p>
				<h3>株価コードで絞り込む</h3>
				<p>市況1板では慣例である銘柄についてのスレッドに株価コードを入れることになっている。自分にとって関心のある銘柄のコードで探せば上手く見つけられる。これを事前に用意して配列に入れておく。</p>
				<pre class="prettyprint">
STOCK_CODE = [
"2497",
"5401",
"5405",
"5411",
"5713",
"6301",
"6752",
"6758",
"7203",
"7974",
"8002",
"8031",
"8058",
"8306",
"8316",
"8411",
"8802",
"9132",
"9433",
"9984",
"日経"
]
</pre>
				<p>ここでは出来高の大きそうな銘柄と「日経」に関するスレッドを読むことにする。1行ずつSTOCK_CODEの配列にある文字列を含むか見ていき、該当するものだけをdatsという配列に格納する。</p>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# getThreads
#---------------------------------------------------------------------------
def getThreads(list)

	# 読むべきdatリスト
	dats = []

	# 1行ずつ判定
	list.each_line do |line|
		d = line.split( /<>/ )
		STOCK_CODE.each do |code|
			if d[1].include?(code) then
				dats << d[0]
			end
		end
	end

	#重複があれば除去
	dats.uniq!

	return dats

end
</pre>
				<h3>不要なDATファイルを削除する</h3>
				<p>過去に取得したものの、既に板から消えてしまったDATファイルは不要だから削除する。</p>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# deleteThreads
#---------------------------------------------------------------------------
def deleteThreads(dats)

	# カレントディレクトリのファイル一覧を消去候補リストに入れる
	fileList = Dir::entries(Dir::pwd)

	# datファイル以外は消去リストから取り除く
	fileList.delete_if do |x|
		/\.dat$/ !~ x
	end

	# カレントディレクトリの.datファイルでdatsにないものを消す
	fileList.each do |name|

		# flagがtrueのものは消す
		flag = true

		dats.each do |dat|
			if name == dat then
				# 取得したいdatファイルは消さないでおく
				flag = false
			end
		end

		# datファイルで不要なものは削除する
		if flag == true then
			File.delete(name)
			$log.info(name + "を消去しました")
		end

	end
end
</pre>
				<h2>必要なスレッドを読む</h2>
				<p>dats配列に格納されたスレッドを読む。ただし、丸ごと読むとサーバに負担をかけるので差分ダウンロードをする。差分ダウンロードはwgetでもできるが、差分だけ解析する処理が面倒臭いので自力でやることにする。</p>
				<p>差分ダウンロードはHTTPのリクエストヘッダにRangeヘッダを追加してリクエストすればよい。まずローカルに保存されたDATファイルがあるなら容量を計算して、それをRangeにセットすればよい。転送量を減らすためにaccept-encodingにgzipを入れておく。</p>
				<p>これでリクエストしたものは差分になる。簡易あぼーん対策として、最初に改行コードが来ていなければ、あぼーんによってスレッドの構成が変わっていると判断する。市況1板ではそれほど個人情報さらしなどの悪質な書き込みがないので、簡易対策だけに留めるが、必要なら丸ごと再取得する。</p>
				<p>連続してリクエストするとサーバに負荷をかけて迷惑になるのでsleepを適当に入れる。</p>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# 必要なスレッドをクロールする
#---------------------------------------------------------------------------
def crawl( name )

	daturl = BOARD + DAT + name
	$log.info( daturl + "を取得中")

	header = {}
	header['User-Agent']= 'Monazilla/1.00 (super-hikky/1.0)'

	length = 0
	if File.exist?( name )
		length = File.stat( name ).size
		datfile = open( name, 'a' )
	else
		datfile = open(  name, 'w' )
	end

	if length > 0
		header['Range'] = "bytes=#{length-1}-"
		header['accept-encoding'] = "gzip"
	end

	url = URI.parse(daturl)
	res = Net::HTTP.start(url.host, url.port) do |http|
		http.get(url.path,header)
	end

	#簡易あぼーん対策
	if res.body[0] != '\n' then
		datfile.print res.body
   		analyze(res.body)
	end

	datfile.close
	sleep(10)
end
</pre>
				<h2>ニュースを取り出す</h2>
				<p>書き込まれたURLが全てニュースとは限らない。そこで、ニュースサイトのドメインを用意しておく。</p>
				<pre class="prettyprint">
NEWS_SITE =
[
"www.bloomberg.co.jp",
"jp.reuters.com/article",
"www.nikkei.co.jp/news",
"www3.nhk.or.jp/news",
"www.yomiuri.co.jp",
"www.asahi.com",
"www.business-i.jp",
"sankei.jp.msn.com",
"news.livedoor.com/article",
"headlines.yahoo.co.jp",
"www.tokyo-np.co.jp/article",
"news.searchina.ne.jp",
"www.jiji.com",
"www.worldtimes.co.jp",
]
</pre>
				<p>これに該当するものだけをニュースサイトであると判断する。過不足があればこの配列に足してもよい。2chではhttpをttpと書くこともあるので、ドメイン名のみにしておく。これを用いて判断する。</p>
				<p>重複したニュースを読むのはコストの無駄なので、recent_news.txtに既に読んだニュースのURLを記録しておく。</p>
				<p>新しく取得した差分から1行ずつURLが含まれているかscanする。URLが含まれるときはrecent_news.txtに含まれていないのを確認して、news配列に入れていく。また、recent_news.txtにも記録する。もしかするとrecent_news.txtに記録するタイミングはTwitterにつぶやいた後の方がいいかもしれない。</p>
				<pre class="prettyprint">
#------------------------------------------------------------------------------------------
# ニュースサイトを抽出
#------------------------------------------------------------------------------------------
def analyze( body )
	body.each_line do |each_res|

		# URLのみ取り出す
		r = each_res.scan(/ttp\:\/\/([\w\+\$\;\?\.\%\,\!\#\~\*\/\:\@\&amp;\\\=\_\-]+)/)

		# URLが入っている場合
		if r.size > 0 then

			# 全てのURLを精査
			r.each do |url|

				NEWS_SITE.each do |news|

					if url[0].include?( news ) then

						# 過去に読んでいるならtrue
						flag = false
						news_url = "http://" + url[0]

						recent_news = open("recent_news.txt", "a+")
						recent_news.each do |line|
							if line.include?(news_url) then
								flag = true
								break
							end
						end

						if flag == false then
							$news << news_url
							recent_news.puts(news_url)
						end

						recent_news.close

					end
				end # each
			end # each
		end # if
	end #each
end
</pre>
				<h2>ニュースを読む</h2>
				<p>ニュースを読み、Twitterにつぶやく。まず、前回取得したOAuthのキー類を用意する。</p>
				<pre class="prettyprint">
CONSUMER_KEY = "GDzTag（略）"
CONSUMER_SECRET = "7TbeOj9waUkqVCOiP（略）"
ACCESS_TOKEN = "91938679-（略）"
ACCESS_TOKEN_SECRET = "hvwhVudtK8QOD（略）"
</pre>
				<p>これを用いて</p>
				<pre class="prettyprint">
#------------------------------------------------------------------------------------------
# ニュースサイトを抽出
#------------------------------------------------------------------------------------------
def readNews

	$news.each do |url|

		begin
			$agent.get(url)
			puts "getting " + url

			title = $agent.page.title.toutf8.chomp
			$log.info(title)

			text = title + " " + url

			#OAuth
			# http://d.hatena.ne.jp/shibason/20090802/1249204953を参考にしました
			consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => "http://twitter.com")
			oauth = Twitter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
			oauth.authorize_from_access(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
			twitter_client = Twitter::Base.new(oauth)
			twitter_client.update(text)

		rescue
		rescue Timeout::Error
		ensure
		end

	end
end
</pre>
				<h2>実行する</h2>
				<pre class="prettyprint">
#---------------------------------------------------------------------------
# main
#---------------------------------------------------------------------------
def main

	# 板一覧を取得
	$agent.get(BOARD + SUBJECT)
	board = $agent.page.body.toutf8

	puts board

	# 読むべきスレッド名を取得
	dats = getThreads(board)

	# 不要なDATファイルを消去する
	deleteThreads(dats)

	# 必要なスレッドを読む
	dats.each do |name|
		crawl(name)
	end

	# ニュースをげっと
	if $news.size > 0 then
		$log.info("ニュースあり")
		readNews
	else
		$log.info("ニュースがありません＞＜")
	end
end

#---------------------------------------------------------------------------
# エントリポイント
#---------------------------------------------------------------------------

#$log = Logger.new("log.txt")
$log = Logger.new(STDOUT)
$log.level = Logger::INFO
$agent = Mechanize.new

#かき集めたニュースURLが入る配列
$news = []

#mainを呼ぶ
main
</pre>
				<h2>実行結果</h2>
				<pre>
1272986450.dat&lt;&gt;■■■明日の日経平均を予想するスレ14685■■■&nbsp;(54)
1272984242.dat&lt;&gt;日経225先物オプション実況スレ6264&nbsp;(907)
9241004012.dat&lt;&gt;【２ちゃんねる十周年】携帯からお試し●を使ってみよう！&nbsp;【規制?】&nbsp;(30)
（中略）
I,&nbsp;[2010-05-05T03:10:00.196231&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;1272744747.datを消去しました
（中略）
I,&nbsp;[2010-05-05T03:10:00.198558&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;1272876392.datを消去しました
I,&nbsp;[2010-05-05T03:10:00.198603&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;http://anchorage.2ch.net/livemarket1/dat/1272986450.datを取得中
I,&nbsp;[2010-05-05T03:10:01.709770&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;http://anchorage.2ch.net/livemarket1/dat/1272984242.datを取得中
（中略）
I,&nbsp;[2010-05-05T03:11:03.133612&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;http://anchorage.2ch.net/livemarket1/dat/1266856385.datを取得中
I,&nbsp;[2010-05-05T03:11:04.344469&nbsp;#858]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;http://anchorage.2ch.net/livemarket1/dat/1270186921.datを取得中
I,&nbsp;[2010-05-05T03:33:28.767688&nbsp;#1070]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;ニュースあり
getting&nbsp;http://www.asahi.com/photonews/images/TKY201004290227.jpg
getting&nbsp;http://jp.reuters.com/article/topNews/idJPJAPAN-15081720100430
I,&nbsp;[2010-05-05T03:33:30.066649&nbsp;#1070]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;ギリシャは厳しい緊縮財政措置の構え、市場は安心感で回復
|&nbsp;Reuters

getting&nbsp;http://www.bloomberg.co.jp/apps/news?pid=90920008&amp;sid=au._wm7SnJDQ
I,&nbsp;[2010-05-05T03:33:33.845826&nbsp;#1070]&nbsp;&nbsp;INFO&nbsp;--&nbsp;:&nbsp;&nbsp;&nbsp;
		&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ギリシャでデモ活動が激化、遺跡アクロポリス占拠も−緊縮財政に抗議&nbsp;&nbsp;-&nbsp;Bloomberg.co.jp
</pre>
				<p>なお、ここでつぶやいたニュースは<a href="http://twitter.com/kabu_news">ボット</a>をフォローすれば読むことができる。</p>
				<h2>参考になる本</h2>
				<div class="tmkm-amazon-view">
					<p><a href="http://www.amazon.co.jp/%E9%9B%86%E5%90%88%E7%9F%A5%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Toby-Segaran/dp/4873113644%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873113644"><img src="http://ecx.images-amazon.com/images/I/51FgSThMzVL._SL160_.jpg" border="0" alt="" /></a></p>
					<p><a href="http://www.amazon.co.jp/%E9%9B%86%E5%90%88%E7%9F%A5%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Toby-Segaran/dp/4873113644%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873113644">集合知プログラミング</a></p>
					<p><em>著者／訳者：</em>Array</p>
					<p><em>出版社：</em>オライリージャパン( 2008-07-25 )</p>
					<p><em>定価：</em>￥ 3,570</p>
					<p>大型本 ( 392 ページ )</p>
					<p>ISBN-10 : 4873113644</p>
					<p>ISBN-13 : 9784873113647</p>
				<hr class="tmkm-amazon-clear" /></div>
				<p>どちらかというと機械学習の本で、サポートベクターマシン(SVM)とか面白い話題にも踏み込んである。</p>
				<div class="tmkm-amazon-view">
					<p><a href="http://www.amazon.co.jp/Java%E3%82%B9%E3%83%91%E3%82%A4%E3%83%80%E3%83%BC%E3%83%84%E3%83%BC%E3%83%AB%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB-%E3%82%AF%E3%83%83%E3%82%AF%E3%83%96%E3%83%83%E3%82%AF%E2%80%95%E8%87%AA%E5%8B%95%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9-%E5%8F%8E%E9%9B%86%E3%83%BB%E5%8A%A0%E5%B7%A5%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0-%E5%B7%9D%E5%B4%8E-%E5%85%8B%E5%B7%B3/dp/4798010618%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4798010618"><img src="http://ecx.images-amazon.com/images/I/51BBV7Q87RL._SL160_.jpg" border="0" alt="" /></a></p>
					<p><a href="http://www.amazon.co.jp/Java%E3%82%B9%E3%83%91%E3%82%A4%E3%83%80%E3%83%BC%E3%83%84%E3%83%BC%E3%83%AB%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB-%E3%82%AF%E3%83%83%E3%82%AF%E3%83%96%E3%83%83%E3%82%AF%E2%80%95%E8%87%AA%E5%8B%95%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9-%E5%8F%8E%E9%9B%86%E3%83%BB%E5%8A%A0%E5%B7%A5%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0-%E5%B7%9D%E5%B4%8E-%E5%85%8B%E5%B7%B3/dp/4798010618%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4798010618">Javaスパイダーツールサンプル&クックブック―自動アクセス&収集・加工プログラム</a></p>
					<p><em>著者／訳者：</em>Array</p>
					<p><em>出版社：</em>秀和システム( 2005-05 )</p>
					<p><em>定価：</em>￥ 2,730</p>
					<p>単行本 ( 377 ページ )</p>
					<p>ISBN-10 : 4798010618</p>
					<p>ISBN-13 : 9784798010618</p>
				<hr class="tmkm-amazon-clear" /></div>
				<p>好きな本だけど新品で手に入れることは難しいようだ。</p>
				<div class="tmkm-amazon-view">
					<p><a href="http://www.amazon.co.jp/Spidering-hacks%E2%80%95%E3%82%A6%E3%82%A7%E3%83%96%E6%83%85%E5%A0%B1%E3%83%A9%E3%82%AF%E3%83%A9%E3%82%AF%E5%8F%96%E5%BE%97%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF101%E9%81%B8-Kevin-Hemenway/dp/4873111870%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873111870"><img src="http://ecx.images-amazon.com/images/I/41AT4JG2KQL._SL160_.jpg" border="0" alt="" /></a></p>
					<p><a href="http://www.amazon.co.jp/Spidering-hacks%E2%80%95%E3%82%A6%E3%82%A7%E3%83%96%E6%83%85%E5%A0%B1%E3%83%A9%E3%82%AF%E3%83%A9%E3%82%AF%E5%8F%96%E5%BE%97%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF101%E9%81%B8-Kevin-Hemenway/dp/4873111870%3FSubscriptionId%3DAKIAJUJFHUMWVQBGDBFQ%26tag%3Donaneet-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873111870">Spidering hacks―ウェブ情報ラクラク取得テクニック101選</a></p>
					<p><em>著者／訳者：</em>Kevin Hemenway Tara Calishain </p>
					<p><em>出版社：</em>オライリー・ジャパン( 2004-05 )</p>
					<p><em>定価：</em>￥ 3,675</p>
					<p>単行本 ( 516 ページ )</p>
					<p>ISBN-10 : 4873111870</p>
					<p>ISBN-13 : 9784873111872</p>
				<hr class="tmkm-amazon-clear" /></div>
				<p>やや古いけどいい本。Perlで書いてあるけど内容は問題ない。マナーについてなど単に技術的な話だけに留まらないので是非読むべき。オライリーなので<a href="http://books.google.co.jp/books?id=vlf1qnRWSCYC&#038;lpg=PA2&#038;ots=Z9kAox0qAS&#038;dq=%E3%82%B9%E3%83%91%E3%82%A4%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%20Hacks&#038;pg=PR3#v=onepage&#038;q&#038;f=false">Google Books</a>で読むことができる。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/05/ruby%e3%81%a72ch%e3%81%ae%e5%b8%82%e6%b3%811%e6%9d%bf%e3%81%ae%e3%83%8b%e3%83%a5%e3%83%bc%e3%82%b9%e3%82%92%e9%9b%86%e3%82%81tweet%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RubyでTwitter</title>
		<link>http://blog.neoneet.jp/2010/05/03/ruby%e3%81%a7twitter/</link>
		<comments>http://blog.neoneet.jp/2010/05/03/ruby%e3%81%a7twitter/#comments</comments>
		<pubDate>Mon, 03 May 2010 10:41:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=226</guid>
		<description><![CDATA[最初に書いたoauth.rbでトラブルに遭って困った。 #!/usr/local/bin/ruby -Ku require 'rubygems' require 'oauth' require 'twitter' すると ./oauth.rb:13:&#160;uninitialized&#160;constant&#160;OAuth&#160;(NameError) from&#160;/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in&#160;`gem_original_require' from&#160;/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in&#160;`require' from&#160;oauth.rb:3 となってしまう。原因は簡単で、ファイル名がoauth.rbだったからである。requireはカレントディレクトリを優先して読みに行くので、自分自身をrequireしていた。解決策もシンプルで別の名前にすればいい。 OAuth認証でTwitterを使う まず [root@PC&#160;twitter]#&#160;gem&#160;install&#160;twitter When&#160;you&#160;HTTParty,&#160;you&#160;must&#160;party&#160;hard! Building&#160;native&#160;extensions.&#160;&#160;This&#160;could&#160;take&#160;a&#160;while... Successfully&#160;installed&#160;oauth-0.4.0 Successfully&#160;installed&#160;hashie-0.2.0 Successfully&#160;installed&#160;crack-0.1.6 Successfully&#160;installed&#160;httparty-0.5.2 Successfully&#160;installed&#160;yajl-ruby-0.7.6 Successfully&#160;installed&#160;twitter-0.9.5 6&#160;gems&#160;installed Installing&#160;ri&#160;documentation&#160;for&#160;oauth-0.4.0... Installing&#160;ri&#160;documentation&#160;for&#160;hashie-0.2.0... Installing&#160;ri&#160;documentation&#160;for&#160;crack-0.1.6... Installing&#160;ri&#160;documentation&#160;for&#160;httparty-0.5.2... Installing&#160;ri&#160;documentation&#160;for&#160;yajl-ruby-0.7.6... Installing&#160;ri&#160;documentation&#160;for&#160;twitter-0.9.5... Installing&#160;RDoc&#160;documentation&#160;for&#160;oauth-0.4.0... Installing&#160;RDoc&#160;documentation&#160;for&#160;hashie-0.2.0... Installing&#160;RDoc&#160;documentation&#160;for&#160;crack-0.1.6... Installing&#160;RDoc&#160;documentation&#160;for&#160;httparty-0.5.2... Installing&#160;RDoc&#160;documentation&#160;for&#160;yajl-ruby-0.7.6... Installing&#160;RDoc&#160;documentation&#160;for&#160;twitter-0.9.5... 一緒にoauth-0.4.0もインストールされる。 アプリケーションを登録する Twitterのアカウントがなければ取得する Twitterにログインする ログインした状態でWebブラウザで「Twitter / アプリケーション」にアクセスする 「新しいアプリケーションを追加」をする 必要事項を記入する アプリ名などは自由に記入すればいい。わかりにくいのは「あなたの招待状」は「送信」を選ぶとよい。そうすると出てくる「Default Access type」は「Read &#038; Write」にしておいた方がいいだろう。 必要事項を記入するとConsumer keyとConsumer [...]]]></description>
			<content:encoded><![CDATA[				<p>最初に書いたoauth.rbでトラブルに遭って困った。</p>
				<pre class="prettyprint">
#!/usr/local/bin/ruby -Ku
require 'rubygems'
require 'oauth'
require 'twitter'
</pre>
				<p>すると</p>
				<pre>
./oauth.rb:13:&nbsp;uninitialized&nbsp;constant&nbsp;OAuth&nbsp;(NameError)
	from&nbsp;/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in&nbsp;`gem_original_require'
	from&nbsp;/opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in&nbsp;`require'
	from&nbsp;oauth.rb:3
</pre>
				<p>となってしまう。原因は簡単で、ファイル名がoauth.rbだったからである。requireはカレントディレクトリを優先して読みに行くので、自分自身をrequireしていた。解決策もシンプルで別の名前にすればいい。</p>
				<h2>OAuth認証でTwitterを使う</h2>
				<p>まず</p>
				<pre>
[root@PC&nbsp;twitter]#&nbsp;gem&nbsp;install&nbsp;twitter
When&nbsp;you&nbsp;HTTParty,&nbsp;you&nbsp;must&nbsp;party&nbsp;hard!
Building&nbsp;native&nbsp;extensions.&nbsp;&nbsp;This&nbsp;could&nbsp;take&nbsp;a&nbsp;while...
Successfully&nbsp;installed&nbsp;oauth-0.4.0
Successfully&nbsp;installed&nbsp;hashie-0.2.0
Successfully&nbsp;installed&nbsp;crack-0.1.6
Successfully&nbsp;installed&nbsp;httparty-0.5.2
Successfully&nbsp;installed&nbsp;yajl-ruby-0.7.6
Successfully&nbsp;installed&nbsp;twitter-0.9.5
6&nbsp;gems&nbsp;installed
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;oauth-0.4.0...
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;hashie-0.2.0...
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;crack-0.1.6...
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;httparty-0.5.2...
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;yajl-ruby-0.7.6...
Installing&nbsp;ri&nbsp;documentation&nbsp;for&nbsp;twitter-0.9.5...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;oauth-0.4.0...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;hashie-0.2.0...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;crack-0.1.6...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;httparty-0.5.2...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;yajl-ruby-0.7.6...
Installing&nbsp;RDoc&nbsp;documentation&nbsp;for&nbsp;twitter-0.9.5...
</pre>
				<p>一緒にoauth-0.4.0もインストールされる。</p>
				<h3>アプリケーションを登録する</h3>
				<ol>
				<li>Twitterのアカウントがなければ取得する</li>
				<li>Twitterにログインする</li>
				<li>ログインした状態でWebブラウザで「<a href="http://twitter.com/oauth_clients">Twitter / アプリケーション</a>」にアクセスする</li>
				<li>「新しいアプリケーションを追加」をする</li>
				<li>必要事項を記入する</li>
				</ol>
				<p>アプリ名などは自由に記入すればいい。わかりにくいのは「あなたの招待状」は「送信」を選ぶとよい。そうすると出てくる「Default Access type」は「Read &#038; Write」にしておいた方がいいだろう。</p>
				<p>必要事項を記入するとConsumer keyとConsumer secretなどが表示されるので記録しておく。</p>
				<h3>Access token, Access token secretを取得する</h3>
				<pre class="prettyprint">
#!/usr/local/bin/ruby -Ku
require 'rubygems'
require 'oauth'

# http://d.hatena.ne.jp/shibason/20090802/1249204953を参考にしました

#OAuth
CONSUMER_KEY = "きー"
CONSUMER_SECRET = "しーくれっと"

consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => "http://twitter.com")
request_token = consumer.get_request_token

puts "Access this URL and approve => #{request_token.authorize_url}"
print "Input OAuth Verifier: "
oauth_verifier = gets.chomp.strip

access_token = request_token.get_access_token(:oauth_verifier => oauth_verifier)

puts "Access token: #{access_token.token}"
puts "Access token secret: #{access_token.secret}"
</pre>
				<p>これを適切な名前を付けて保存する。oauth.rbにしたらひどいトラブルで苦労したので気をつける。実行すると</p>
				<pre>
Access&nbsp;this&nbsp;URL&nbsp;and&nbsp;approve&nbsp;=&gt;&nbsp;http://twitter.com/oauth/authorize?oauth_token=とーくん
Input&nbsp;OAuth&nbsp;Verifier:&nbsp;
</pre>
				<p>と出てくるので、URLにアクセスして出てきた数値を入力すると、Access tokenとAccess token secretが得られる。これを記録しておく。</p>
				<h3>Twitterに何か書いてみる</h3>
				<pre class="prettyprint">
#!/usr/local/bin/ruby -Ku
require 'rubygems'
require 'oauth'
require 'twitter'

CONSUMER_KEY = "きー"
CONSUMER_SECRET = "しーくれっと"
ACCESS_TOKEN = "とーくん"
ACCESS_TOKEN_SECRET = "とーくんしーくれっと"

consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => "http://twitter.com")
oauth = Twitter::OAuth.new(CONSUMER_KEY, CONSUMER_SECRET)
oauth.authorize_from_access(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
twitter_client = Twitter::Base.new(oauth)
twitter_client.update("こけこっこ")
</pre>
				<p>実行すると「こけこっこ」とつぶやきが投稿される。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/03/ruby%e3%81%a7twitter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rubyスクレーピング本を出したい</title>
		<link>http://blog.neoneet.jp/2010/05/03/ruby%e3%82%b9%e3%82%af%e3%83%ac%e3%83%bc%e3%83%94%e3%83%b3%e3%82%b0%e6%9c%ac%e3%82%92%e5%87%ba%e3%81%97%e3%81%9f%e3%81%84/</link>
		<comments>http://blog.neoneet.jp/2010/05/03/ruby%e3%82%b9%e3%82%af%e3%83%ac%e3%83%bc%e3%83%94%e3%83%b3%e3%82%b0%e6%9c%ac%e3%82%92%e5%87%ba%e3%81%97%e3%81%9f%e3%81%84/#comments</comments>
		<pubDate>Sun, 02 May 2010 17:18:57 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.neoneet.jp/?p=218</guid>
		<description><![CDATA[というわけで、原稿を書きためることにする。手元に原稿を置いてもいいけど、ブログにまとめた方がモチベーションが上がりそう。あまり細かいことに拘らず、とにかく色々書く。 2chの板をスクレーピングする 2chのスレッドから情報を得たいとする。スレッドは板と呼ばれるグループに所属している。ここでは例として「台湾」板から情報を得る。各々の板にはsubject.txtというファイルがある。内容は 1141905139.dat韓国より台湾だと思う人→ (718) 1236575332.dat麻煩ね～青木由香　堂々と不法就労で警察沙汰 (753) 1268142329.dat■中山北路２段９３巷１７号ビル名「小室哲哉」■ (32) 1249183264.dat牛肉麺 (200) のようなデータがたくさん入っている。subject.txtから、スレッドのタイトルと、スレッドが格納されているファイル名、レス数がわかる。&#60;&#62;が区切り文字になっている。 次にスレッドを取得する。スレッドはdatというディレクトリの中にある。スレッドを取得するときは、http://academy6.2ch.net/taiwan/dat/1141905139.datのようにリクエストすればいい。ダウンロードをするときにはmechanizeでもよいが、差分ダウンロードなどの機能を考えるとwgetが便利である。 wgetの-Nオプションはファイルのタイムスタンプを比較して、差分ダウンロードを試みる。2chのスレッドのように少しずつ新しい内容が付け足されていくタイプのファイルをダウンロードする場合には差分でダウンロードする方がよい。 datファイルの中身は 美麗島の名無桑sage2006/03/09(木) 20:52:19 台湾わ日本を尊敬してるから偉いな 韓国より台湾だと思う人→ 美麗島の名無桑sage2006/03/09(木) 21:03:28 それよりもまずナガノ 美麗島の名無桑2006/03/11(土) 23:19:10 観光・グルメ・安全性の面で台湾が上だな。 漢字だから日本と違和感無いし。 美麗島の名無桑2006/03/12(日) 03:05:12 台湾ﾏﾝｾｰヽ(&#8216;Д&#8217;)人(&#8216;Д&#8217;)人(&#8216;Д&#8217;)人(&#8216;Д&#8217;)/ このようになっている。1行が1レスになる。subject.txtと同様に区切りは&#60;&#62;である。 コード #!/usr/bin/ruby -Ku require 'rubygems' require 'nokogiri' require 'mechanize' require 'kconv' HOST = "http://academy6.2ch.net/taiwan/" SUBJECT = "/subject.txt" DAT = "/dat/" agent = Mechanize.new agent.get(HOST + [...]]]></description>
			<content:encoded><![CDATA[				<p>というわけで、原稿を書きためることにする。手元に原稿を置いてもいいけど、ブログにまとめた方がモチベーションが上がりそう。あまり細かいことに拘らず、とにかく色々書く。</p>
				<h2>2chの板をスクレーピングする</h2>
				<p>2chのスレッドから情報を得たいとする。スレッドは板と呼ばれるグループに所属している。ここでは例として「台湾」板から情報を得る。各々の板にはsubject.txtというファイルがある。内容は</p>
				<blockquote><p>
				1141905139.dat<>韓国より台湾だと思う人→ (718)<br />
				1236575332.dat<>麻煩ね～青木由香　堂々と不法就労で警察沙汰 (753)<br />
				1268142329.dat<>■中山北路２段９３巷１７号ビル名「小室哲哉」■ (32)<br />
				1249183264.dat<>牛肉麺 (200)
				</p></blockquote>
				<p>のようなデータがたくさん入っている。subject.txtから、スレッドのタイトルと、スレッドが格納されているファイル名、レス数がわかる。&lt;&gt;が区切り文字になっている。</p>
				<p>次にスレッドを取得する。スレッドはdatというディレクトリの中にある。スレッドを取得するときは、http://academy6.2ch.net/taiwan/dat/1141905139.datのようにリクエストすればいい。ダウンロードをするときにはmechanizeでもよいが、差分ダウンロードなどの機能を考えるとwgetが便利である。</p>
				<p>wgetの-Nオプションはファイルのタイムスタンプを比較して、差分ダウンロードを試みる。2chのスレッドのように少しずつ新しい内容が付け足されていくタイプのファイルをダウンロードする場合には差分でダウンロードする方がよい。</p>
				<p>datファイルの中身は</p>
				<blockquote><p>
				美麗島の名無桑<>sage<>2006/03/09(木) 20:52:19 <> 台湾わ日本を尊敬してるから偉いな <>韓国より台湾だと思う人→<br />
				美麗島の名無桑<>sage<>2006/03/09(木) 21:03:28 <> それよりもまずナガノ <><br />
				美麗島の名無桑<><>2006/03/11(土) 23:19:10 <> 観光・グルメ・安全性の面で台湾が上だな。 <br /> 漢字だから日本と違和感無いし。 <><br />
				美麗島の名無桑<><>2006/03/12(日) 03:05:12 <> 台湾ﾏﾝｾｰヽ(&#8216;Д&#8217;)人(&#8216;Д&#8217;)人(&#8216;Д&#8217;)人(&#8216;Д&#8217;)/ <>
				</p></blockquote>
				<p>このようになっている。1行が1レスになる。subject.txtと同様に区切りは&lt;&gt;である。</p>
				<h3>コード</h3>
				<pre class="prettyprint">
#!/usr/bin/ruby -Ku
require 'rubygems'
require 'nokogiri'
require 'mechanize'
require 'kconv'

HOST = "http://academy6.2ch.net/taiwan/"
SUBJECT = "/subject.txt"
DAT = "/dat/"

agent = Mechanize.new
agent.get(HOST + SUBJECT)
agent.page.body.toutf8.each do |line|
	array = line.split(/<>/)
	command = "wget -N " + HOST + DAT + array[0]
	puts array[1].chomp + "をダウンロードします"
	system(command)
	sleep(10)
	exit
end
</pre>
				<h3>コードの説明</h3>
				<p>取得したsubject.txtを1行ずつeachで見ていく。区切り文字が&lt;&gt;なので、それでsplitする。全てのスレッドを取得することもできるが、サンプルなので1回ダウンロードしたらexitで抜けるようにしてある。あまり連続してアクセスするのはサーバに負担をかけるので1回につき10秒の待ちを入れてある。</p>
				<h3>実行例</h3>
				<pre>
[onaneet@PC ~/Desktop/Ruby本]# ruby 2ch.rb
韓国より台湾だと思う人→ (718)をダウンロードします
--2010-05-03 02:02:10--  http://academy6.2ch.net/taiwan//dat/1141905139.dat
Resolving academy6.2ch.net (academy6.2ch.net)... 206.223.152.60
Connecting to academy6.2ch.net (academy6.2ch.net)|206.223.152.60|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 226448 (221K) [text/plain]
Saving to: `1141905139.dat'
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.neoneet.jp/2010/05/03/ruby%e3%82%b9%e3%82%af%e3%83%ac%e3%83%bc%e3%83%94%e3%83%b3%e3%82%b0%e6%9c%ac%e3%82%92%e5%87%ba%e3%81%97%e3%81%9f%e3%81%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

