JavaScriptレンダリングサーバーSplashでスクレイピング
これはクローラー/Webスクレイピング Advent Calendar 2015の9日目の記事です。
本記事では、Scrapinghub社*1が開発しているSplashというオープンソースソフトウェアを紹介します。
JavaScriptを使ったページからスクレイピングする方法としては、PhantomJSとSelenium/CasperJSなどの組み合わせが一般的ですが、これらとは少し違う手段として使えるかもしれないソフトウェアです。 私自身Splashを最近知ったばかりで、軽く探した限りでは日本語の情報もないので、調査しつつSplashの使いドコロを探ってみたいと思います。
Splashとは
READMEには以下のように書かれています。
Splash is a javascript rendering service with an HTTP API. It's a lightweight browser with an HTTP API, implemented in Python using Twisted and QT.
It's fast, lightweight and state-less which makes it easy to distribute.
(訳)SplashはHTTP APIを持つJavaScriptレンダリングサービスです。HTTP APIを持つ軽量ブラウザで、TwistedとQTを使ってPythonで実装されています。 高速、軽量かつステートレスで、容易に分散できます。
ドキュメントにはもう少し詳しく機能が書かれています。
- process multiple webpages in parallel;
- get HTML results and/or take screenshots;
- turn OFF images or use Adblock Plus rules to make rendering faster;
- execute custom JavaScript in page context;
- write Lua browsing scripts;
- develop Splash Lua scripts in Splash-Jupyter Notebooks.
- get detailed rendering info in HAR format.
(訳)
- 複数のWebページを並列処理できる。
- HTMLやスクリーンショットを取得できる。
- 画像の読み込みを無効化したり、Adblock Plusのルールを使用してレンダリングを高速化できる。
- カスタムJavaScriptをページのコンテキストで実行できる。
- Luaでブラウジングスクリプトを書ける。
- Splash LuaスクリプトをSplash-Jupyter Notebooksで開発できる。
- 詳細なレンダリング情報をHARフォーマットで取得できる。
要するに、以下のように動くということでしょう。なかなか面白そうです。
Splashを使ってみる
とりあえず使ってみましょう。 今どきのソフトウェアらしく、Dockerを使って簡単にサーバーを起動できます。
$ docker pull scrapinghub/splash $ docker run -p 5023:5023 -p 8050:8050 -p 8051:8051 scrapinghub/splash
ポートの意味はそれぞれ以下のとおりです。
以下のようにログが表示されたら起動完了です。この記事ではSplash 1.8を使います。
2015-12-08 13:20:59+0000 [-] Log opened. 2015-12-08 13:20:59.239310 [-] Splash version: 1.8 2015-12-08 13:20:59.240288 [-] Qt 4.8.1, PyQt 4.9.1, WebKit 534.34, sip 4.13.2, Twisted 15.4.0, Lua 5.2 2015-12-08 13:20:59.242303 [-] Python 2.7.3 (default, Jun 22 2015, 19:33:41) [GCC 4.6.3] 2015-12-08 13:20:59.242396 [-] Open files limit: 1048576 2015-12-08 13:20:59.242472 [-] Can't bump open files limit 2015-12-08 13:20:59.447814 [-] Xvfb is started: ['Xvfb', ':1069', '-screen', '0', '1024x768x24'] 2015-12-08 13:20:59.507558 [-] proxy profiles support is enabled, proxy profiles path: /etc/splash/proxy-profiles 2015-12-08 13:20:59.547976 [-] verbosity=1 2015-12-08 13:20:59.548159 [-] slots=50 2015-12-08 13:20:59.548618 [-] Web UI: enabled, Lua: enabled (sandbox: enabled), Proxy Server: enabled 2015-12-08 13:20:59.549491 [-] Site starting on 8050 2015-12-08 13:20:59.549761 [-] Starting factory <twisted.web.server.Site instance at 0x1b87a70> 2015-12-08 13:20:59.551205 [-] SplashProxyServerFactory starting on 8051 2015-12-08 13:20:59.551413 [-] Starting factory <splash.proxy_server.SplashProxyServerFactory instance at 0x1b8a3b0>
起動したら、ブラウザでhttp://<Dockerのホスト>:8050/
にアクセスします。私の環境ではhttp://192.168.59.103:8050/
でした。
このURLを開くと、以下のようなデモ用の画面が表示されます。
「Render me!」という緑のボタンをクリックすると、以下のようにGoogleのページがレンダリングされた画像が表示されます。 さらに、スクロールするとネットワークに関する情報とHTMLが表示されます。
「Render me!」ボタンを押すと、入力したURLにアクセスし、黒いテキストボックス内のLuaスクリプトが実行される、ということのようです。
SplashのAPIを使う
デモはこれぐらいにしてHTTP APIを使ってみましょう。
/render.html
というエンドポイントにurl
パラメータを渡すことで、指定したURLのHTMLを取得できます。
$ curl 'http://192.168.59.103:8050/render.html?url=http://google.com' <!DOCTYPE html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> ...
ここで重要なのは、このAPIで取得できるHTMLは、サーバーから取得したHTMLではなく、JavaScriptのonloadイベントが発生した時点でのDOMツリーをHTMLにしたものであるという点です。
このことがわかりやすい例として、PythonでさくっとWebスクレイピングする (JavaScript読み込みにも対応しつつ) - Qiita という記事でサンプルとして使われていた、テレ朝ニュースからスクレイピングしてみます。
このページでは、ページ下部の「関連ニュース」のリストがAjaxで読み込まれます。このため、以下のように普通にcurlで取得すると空の<div>
要素が存在するだけです。
$ curl http://news.tv-asahi.co.jp/news_international/articles/000064029.html | iconv -f shift_jis ... <!-- 関連ニュース --> <div id="relatedNews"></div> ...
以下のようにSplashを経由させると、<div>
要素の中にコンテンツが含まれた状態のHTMLを取得できます。onloadのタイミングまで待つので少しだけ時間がかかります。
$ curl -v 'http://192.168.59.103:8050/render.html?url=http://news.tv-asahi.co.jp/news_international/articles/000064029.html' ... <!-- 関連ニュース --> <div id="relatedNews"> <div class="kanrennews"> <h3>関連ニュース</h3> <ul class="newslist clearfix"> <li> <div class="text"><a href="http://news.tv-asahi.co.jp/news_international/articles/000063920.html">「若い皆さん研究頑張って」 物理学賞・梶田さん</a><br><span>(2015/12/07 17:53)</span></div> </li> <li> <div class="text"><a href="http://news.tv-asahi.co.jp/news_international/articles/000063849.html">ノーベル賞大村さん現地に 梶田さん燕尾服を採寸</a><br><span>(2015/12/06 11:52)</span></div> </li> <li> <div class="text"><a href="http://news.tv-asahi.co.jp/news_international/articles/000063837.html">“ノーベルウィーク”大村さん、梶田さん現地到着</a><br><span>(2015/12/06 05:50)</span></div> </li> <li> <div class="text"><a href="http://news.tv-asahi.co.jp/news_international/articles/000063826.html">大村さんも現地到着 いよいよ「ノーベルウィーク」</a><br><span>(2015/12/05 17:31)</span></div> </li> <li> <div class="text"><a href="http://news.tv-asahi.co.jp/news_international/articles/000063810.html">ノーベル賞梶田さん到着 これからイベント目白押し</a><br><span>(2015/12/05 11:51)</span></div> </li> </ul> </div> </div> ...
あとはお好きなスクレイピングライブラリでHTMLからスクレイピングすればOKです。
細かい話ですが、このページはShift_JISでエンコードされているので、最初の例ではiconvを使って文字コードを変換しています。Splashを通すと、UTF-8でエンコードされた状態で取得できるので、iconvは不要です。metaタグは<meta charset="Shift_JIS">
のまま取得できるので、ちょっと紛らわしいですね。
render.htmlエンドポイントにはurl
以外にも様々なパラメータを渡せます。例えばonloadからさらに指定した時間待つwait
や、ページ内でJavaScriptを実行するjs_source
などがあります。
また、他にも以下のようなエンドポイントがあります。
- render.png: PNGでスクリーンショットを取得する。
- render.jpeg: JPEGでスクリーンショットを取得する。
- render.har: HARファイルを取得する。
- render.json: 複数の形式を一度に取得する。
- execute: サーバーでLuaスクリプトを実行してもっと複雑な処理を行う。
詳しくはAPIドキュメントを参照してください。
Splash HTTP API — Splash 1.8 documentation
Splashの使いドコロ
推測ですが、Splash開発のモチベーションは以下のようなものでしょう。
- JavaScriptを使ったページが増えており、JavaScriptへの対応は不可欠。
- しかしあらゆるページでPhantomJSを使うと遅くなってしまう。
- かといって、JavaScriptを使わないページはlxmlで、使うページはSelenium+PhantomJSなどと使い分けると、APIが違って面倒。
- Splashを使って、JavaScriptを実行したあとのHTMLをlxmlなどでスクレイピングすれば、JavaScriptに対応しつつAPIの一貫性を維持できる。
このため、lxmlなどを使って昔ながらのスクレイピングをしている人が、あまりコードを変更せずにJavaScriptに対応したいという目的で使えるのではないでしょうか。
一方でステートレス性を重視しているので、JavaScriptで対話的な操作をしてスクレイピングするという用途には向いていないように思います。サーバーでLuaスクリプトを実行できますが、それであれば正直SeleniumとかCasperJSとかでやっても同じように思います。
また、サーバーを立てる必要があるので、使い捨てのスクリプトにはあまり向かないでしょう。Scrapinghub社はクローラーのSaaSを提供する会社であり、Splashもサービスの一つとして提供されています。このため、スケーラビリティが重視されており、ある程度大規模に使用しないと他の手段に比べてメリットを感じにくいかもしれません。
まとめ
SplashはJavaScriptレンダリングサーバーで、JavaScriptを使ったページからスクレイピングするための手段の一つとして使える可能性を持ったソフトウェアです。
ここで紹介したのは一番基本的な機能だけで、ドキュメントを読んでいると冒頭で紹介した機能以外にもさまざまな機能があります。 例えば、HTTPプロキシとして振る舞うことができたり、Scrapyと連携したりもできるなど、色々と面白い使い方ができそうです。
良ければ使ってみてください。
参考
Scrapy 1.0が公開されました
Pythonの有名なWebスクレイピングフレームワークのScrapyがバージョン1.0になりました。*1
0.24からの主要な変更点は下記のとおりです。
- SpiderでItemの代わりにdictを返せるようになった
- Spiderごとにsettingsを設定できるようになった
- Twistedのloggingの代わりにPythonのloggingを使うようになった
- CrawlerのコアAPIがリファクタリングされた
- いくつかのモジュール配置場所が変更された
他にも数多くの変更点がリリースノートに記載されています。
Scrapy 1.0の感想
大きな機能の追加よりも、APIの整理と安定性の向上がメインのようです。これまではバージョンを重ねるごとに便利になっていくものの、あまりAPIが安定していない印象でしたが、APIを安定させた区切りのリリースと言えるでしょう。1.0というメジャーバージョンに到達したことで、安心して使えるようになったと思います。
Item
の代わりにdict
が使えるようになったのはありがたいです。Item
の存在意義は正直謎でしたので。
個人的に気になっていた、単一の要素を取得したい場合でもlist
を返すextract()
しかなくて使いにくい問題も、extract_first()
メソッドが追加されたことで解決したので嬉しいです。
1.0では依然としてPython 2.7のみの対応ですが、1.1のマイルストーンにはPython 3のサポートが含まれています。実際、Google Summer of Code 2015のテーマとして採択されており、この夏の成果が楽しみです。
それでは早速Scrapy 1.0を使ってクローラーを書いてみましょう。
例1:1ファイルのシンプルなクローラー
Scrapyは大規模なクローリングを得意とするフレームワークですが、1ファイルから構成されるシンプルなクローラーも書けます。
ScrapyのWebサイトのトップに表示されている、Scrapinghubのブログをクロールするクローラーを動かしてみます。ちなみにScrapinghubはScrapyの開発者が立ちあげた会社です。
表示されているコードをそのままターミナルに貼り付けて実行してもよいのですが、ちょっと手を加えて解説も加えておきます。
1. Scrapyをインストールする
Python 2.7が必要です。
--upgrade
をつけることでインストール済みの場合はアップグレードします。
$ pip install --upgrade scrapy
2. service_identityもインストールしておく
service_identityはMITMを防ぐモジュールであり、これがインストールされていないと警告が出ます。
$ pip install service_identity
3. Spiderを作成する
myspider.py
という名前で以下の内容のファイルを作成します。
日本語のコメントを付けたので、1行目にエンコーディングを指定しています。ファイルはUTF-8で保存してください。
# coding: utf-8 import scrapy # scrapy.Spiderを継承してBlogSpiderを定義する class BlogSpider(scrapy.Spider): name = 'blogspider' start_urls = ['http://blog.scrapinghub.com'] def parse(self, response): # トップページをパースするメソッド。 # URLに /yyyy/mm/ を含むアーカイブページへのリンクを抽出してクロールする。 # それらのページはparse_titles()メソッドでパースする。 for url in response.css('ul li a::attr("href")').re(r'.*/\d\d\d\d/\d\d/$'): yield scrapy.Request(response.urljoin(url), self.parse_titles) def parse_titles(self, response): # アーカイブページからエントリーのタイトルを取得する for post_title in response.css('div.entries > ul > li a::text').extract(): yield {'title': post_title}
4. クローラーを実行する
以下のコマンドで実行できます。
$ scrapy runspider myspider.py 2015-06-20 22:14:05 [scrapy] INFO: Scrapy 1.0.0 started (bot: scrapybot) 2015-06-20 22:14:05 [scrapy] INFO: Optional features available: ssl, http11 2015-06-20 22:14:05 [scrapy] INFO: Overridden settings: {} 2015-06-20 22:14:05 [scrapy] INFO: Enabled extensions: CloseSpider, TelnetConsole, LogStats, CoreStats, SpiderState 2015-06-20 22:14:05 [scrapy] INFO: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats 2015-06-20 22:14:05 [scrapy] INFO: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2015-06-20 22:14:05 [scrapy] INFO: Enabled item pipelines: 2015-06-20 22:14:05 [scrapy] INFO: Spider opened 2015-06-20 22:14:05 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2015-06-20 22:14:05 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023 2015-06-20 22:14:06 [scrapy] DEBUG: Crawled (200) <GET http://blog.scrapinghub.com> (referer: None) 2015-06-20 22:14:07 [scrapy] DEBUG: Crawled (200) <GET http://blog.scrapinghub.com/2012/07/> (referer: http://blog.scrapinghub.com) 2015-06-20 22:14:07 [scrapy] DEBUG: Crawled (200) <GET http://blog.scrapinghub.com/2011/11/> (referer: http://blog.scrapinghub.com) ...
実行するとアーカイブページを30ページほどクロールして、タイトルを取得できます。
-o titles.jl
という引数をつけると、取得したタイトルがtitles.jl
という名前のファイルにJSONlines形式で書き込まれます。
複雑なクローラーの作成
続いて、1年半前の記事と同様にBBCとCNET Newsを対象として、もう少し複雑なクローラーを書いてみます。
以前の記事に書いたクローラーは、Webサイト側の変更によって既に2つとも動かなくなっています。Webスクレイピングの無常さを感じますが、めげずに書き直します。 当時のバージョンは0.20.2でしたが、1.0の機能を使うとよりシンプルに書けます。
スクレイピングした後にデータベースに保存するなどの処理を行ったり、設定を共有した複数のSpiderを動かしたりするなど、1ファイルでは収まらないクローラーを作成するときには、プロジェクトを作るのがScrapyの流儀です。
以下のコマンドで、helloscrapy
という名前のプロジェクトを作成します。
$ scrapy startproject helloscrapy
以下のファイルが生成されます。
$ tree helloscrapy helloscrapy ├── helloscrapy │ ├── __init__.py │ ├── items.py │ ├── pipelines.py │ ├── settings.py │ └── spiders │ └── __init__.py └── scrapy.cfg
プロジェクトのディレクトリにcd
しておきます。
$ cd helloscrapy/helloscrapy
以降では、このディレクトリ(settings.py
が存在するディレクトリ)を基準とします。
とりあえず、settings.py
に以下の設定を追加しておきます。Webページのダウンロード間隔として3秒空け、Webサイトのrobots.txtに従うようになります。
DOWNLOAD_DELAY = 3 ROBOTSTXT_OBEY = True
例2:XML Sitemapを持つサイトのクローリング
XML Sitemapを持つWebサイトをクロールするにはSitemapSpiderが便利です。
例として、CNET Newsを取り上げます。以前の記事ではXML Sitemapを持たないサイトとして紹介しましたが、リニューアルしてXML Sitemapが提供されていました。
spiders/cnet.py
を以下の内容で作成します。scrapy genspider cnet www.cnet.com
を実行するとSpiderの雛形が生成されるので、これを変更しても構いません。
# coding: utf-8 from datetime import datetime import scrapy # SitemapSpiderを継承する class CNETSpider(scrapy.spiders.SitemapSpider): name = "cnet" allowed_domains = ["www.cnet.com"] sitemap_urls = ( # ここにはrobots.txtのURLを指定してもよいが、 # 無関係なサイトマップが多くあるので、今回はサイトマップのURLを直接指定する。 'http://www.cnet.com/sitemaps/news.xml', ) sitemap_rules = ( # 正規表現 '/news/' にマッチするページをparse_news()メソッドでパースする (r'/news/', 'parse_news'), ) def parse_news(self, response): yield { # h1要素の文字列を取得する 'title': response.css('h1::text').extract_first(), # div[itemprop="articleBody"]の直下のp要素以下にある全要素から文字列を取得して結合する 'body': ''.join(response.css('div[itemprop="articleBody"] > p ::text').extract()), # time[itemprop="datePublished"]のclass属性にUTCの時刻が格納されているので、パースする 'time': datetime.strptime( response.css('time[itemprop="datePublished"]::attr(class)').extract_first(), '%Y-%m-%d %H:%M:%S' ), }
以下のコマンドでクローラーを実行します。しばらくするとitems-cnet.jl
にスクレイピング結果が出力されていきます。
$ scrapy crawl cnet -o items-cnet.jl
例3:XML Sitemapを持たないサイトのクローリング
XML Sitemapを持たないサイトのクローリングにはCrawlSpiderが便利です。
例として、BBCを取り上げます。以前の記事ではXML Sitemapを持つサイトとして紹介しましたが、ニュース用のXML Sitemapが404になっていて使用できなかったので、XML Sitemapを使わずにクロールします。
spiders/bbc.py
を以下の内容で作成します。scrapy genspider -t crawl bbc www.bbc.com
を実行するとCrawlSpiderを使ったSpiderの雛形が生成されるので、これを変更しても構いません。
# coding: utf-8 from datetime import datetime from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule # CrawlSpiderを継承する class BBCSpider(CrawlSpider): name = "bbc" allowed_domains = ["www.bbc.com"] start_urls = ( 'http://www.bbc.com/news', ) rules = ( # /news/world/*** というカテゴリページを辿る Rule(LinkExtractor(allow=r'/news/world/'), follow=True), # /news/world-*** というニュースページはparse_news()メソッドでパースする Rule(LinkExtractor(allow=r'/news/world-'), callback='parse_news'), ) def parse_news(self, response): yield { # h1要素の文字列を取得する 'title': response.css('h1::text').extract_first(), # .story-body__innerの直下のp要素文字列を取得して改行で結合する 'body': '\n'.join(response.css('.story-body__inner > p::text').extract()), # .story-body .dateのdata-seconds属性にタイムスタンプが格納されているので時刻に変換する 'time': datetime.fromtimestamp(int( response.css('.story-body .date::attr("data-seconds")').extract_first())), }
以下のコマンドでクローラーを実行します。しばらくするとitems-bbc.jl
にスクレイピング結果が出力されていきます。たまにパースに失敗するページもありますが、無視してください。
$ scrapy crawl cnet -o items-bbc.jl
まとめ
Scrapy 1.0になり、すっきりと書けるようになったことがわかるかと思います。 使いやすくなり安定したScrapyでクローリングしていきましょう。 今後のPython 3対応も楽しみです。
LinuxディストリビューションにおけるPython 3デフォルト化の流れ
2015年6月2日修正:henrichさんのコメントを受け、Debianの記述を修正しました。
最近のLinuxディストリビューションにおいてPython 3がデフォルトになってきているという話をチラホラ聞くので、状況を調べてみました。
結論
- PEP 394にディストリビューション向けのガイドラインが公開されている。
- Arch Linuxは既にPython 3がデフォルトになっている。
- Fedora 23(2015-10-27リリース予定)でPython 3がデフォルトになる予定。
-
/usr/bin/python
は削除されるかpython3
にシンボリックリンクされるか議論されている。
-
- Ubuntu 16.04(2016-04リリース予定)でPython 3がデフォルトになる予定。
- Debian 9 (Stretch) または10 (Buster) でPython 3をデフォルトにするべく作業が始まっている。
PEP 394
PEP 394では、Arch Linuxが(アグレッシブにも)Python 3をデフォルトにしたことを受け、Unix-likeなディストリビューション向けに推奨されるpython
コマンドの振る舞いが記述されています。
PEP 394 -- The "python" Command on Unix-Like Systems
Recommendationを簡単に訳してみました。
推奨事項
- Unix-likeなディストリビューションはPython 2を
python2
コマンドとして、Python 3をpython3
コマンドとしてPATHにインストールするべきである。 python2
コマンドを実行するとPython 2が起動し、python3
コマンドを実行するとPython 3が起動するべきである。- Python 2がインストールされている場合は、
python
コマンドをインストールし、python
コマンドが実行された場合はpython2
コマンドが実行されたときと同じバージョンのPythonが起動すべきである。(ただしPython 3が起動する場合もある) - Python 2.xの
idle
,pydoc
,python-config
などのコマンドも同様に、idle2
,pydoc2
,python2-config
として実行でき、バージョンがついていないコマンドが実行された時は、これらのバージョンを実行すべきである。(ただしシステム管理者の設定によってPython 3.xのものが起動してもよい) - プラットフォームごとの差異に対応するため、Pythonインタプリタを起動する必要のあるコードでは
python
を指定すべきではなく、代わりにpython2
かpython3
(またはさらに特定のpython2.x
やpython3.x
)を指定すべきである。Shebangに書くときも同様である。 - 一点例外として、Python 2.xとPython 3.xの両方で動くスクリプトでは
python
を指定したりShebangに書いても良い。 - Pythonスクリプトから実行する場合は、
sys.executable
を使うのが望ましい。
Arch Linux
Arch Linuxはローリング・リリースを採用しており、明確なバージョンはありません。
2010-10-18に/usr/bin/python
がPython 3を指すようになったとアナウンスされています。
python
パッケージをインストールすると、Python 2ではなくPython 3が使えます。
Arch Linux - News: Python is now Python 3
参考:
実際に使ってみる
というわけで使ってみました。baseとbase-develグループをインストールしただけではPythonはインストールされなかったので、pythonパッケージをインストールしました。
python
コマンドで確かにPython 3が起動しました。
[root@archiso /]# python -V Python 3.4.3 [root@archiso /]# which python /usr/bin/python [root@archiso /]# ls /usr/bin/python* -l lrwxrwxrwx 1 root root 7 Mar 25 17:30 /usr/bin/python -> python3 lrwxrwxrwx 1 root root 14 Mar 25 17:30 /usr/bin/python-config -> python3-config lrwxrwxrwx 1 root root 9 Mar 25 17:30 /usr/bin/python3 -> python3.4 lrwxrwxrwx 1 root root 16 Mar 25 17:30 /usr/bin/python3-config -> python3.4-config -rwxr-xr-x 2 root root 10440 Mar 25 17:30 /usr/bin/python3.4 lrwxrwxrwx 1 root root 17 Mar 25 17:30 /usr/bin/python3.4-config -> python3.4m-config -rwxr-xr-x 2 root root 10440 Mar 25 17:30 /usr/bin/python3.4m -rwxr-xr-x 1 root root 3107 Mar 25 17:30 /usr/bin/python3.4m-config
なお、python2パッケージをインストールすれば、Python 2を使うことも可能です。
Fedora
次期メジャーリリースのFedora 23でPython 3をデフォルトにすることが提案されています。
Changes/Python 3 as Default - FedoraProject
ここでのデフォルトとは、以下のことを意味します。
- Python 2のみに対応していたYumに替わってDNFがデフォルトパッケージマネージャになる。(明記されていないがFedora 22で実施済みのはず)
- Python 3がminimal buildrootにおける唯一のPython実装になる。(Fedora 22で実施済み)
- Python 3がWorkstation LiveDVDにおける唯一のPython実装になる。
- Python 3がminimal cloud imageにおける唯一のPython実装になる。
- Python 3がAtomic hostにおける唯一のPython実装になる。
- Server LiveDVDでもPython 3が唯一のPython実装になると良いが、可能性は低い。
以下の点は議論されているようです。
参考:
- [Python-Dev] Python 3 as a Default in Linux Distros
- Python 3 Is Close To Becoming The Default In Fedora 22 - Phoronix
ちなみに最近のFedoraのリリース日*1は以下の感じです。
- Fedora 20 (Heisenbug): 2013-12-17
- Fedora 21: 2014-12-09
- Fedora 22: 2015-05-26
- Fedora 23: 2015-10-27(予定)
Ubuntu
Ubuntu 16.04でPython 3をデフォルトにすることが提案されています。
ここでのデフォルトとは、以下の意味です。
- Python 3がデフォルトでインストールされる唯一のPython実装になる。
- Python 3がインストールメディア(ISOなど)に含まれる唯一のPython実装になる。
- Ubuntu touchのイメージではPython 3のみが使用できる。
- Python 3をサポートするアップストリームのすべてのライブラリは、Python 3のバージョンがアーカイブに含まれる。
- Python 3上で実行できるすべてのアプリケーションはデフォルトでPython 3を使う。
- アーカイブに含まれるすべてのシステムスクリプトはPython 3を使う。
一方で、デフォルトが意味しないこととして、以下の点が挙げられています。
参考:
- Python - Ubuntu Wiki
- 2015年5月15日号 Ubuntu 15.10 “Wily Werewolf”の開発開始・ホワイトボックススイッチ版Ubuntu・Ubuntu版インターネット対応冷蔵庫 “ChillHub”:Ubuntu Weekly Topics|gihyo.jp … 技術評論社
- Python plans for LTS - | The Summit Scheduler
- Ubuntu Plans For Python 3 By Default For Ubuntu 16.04 LTS - Phoronix
ちなみに最近のUbuntuのリリース日*2は以下の感じです。
- 14.04 LTS (Trusty Tahr): 2014-04-17
- 14.10 (Utopic Unicorn): 2014-10-23
- 15.04 (Vivid Vervet): 2015-04-23
- 15.10 (Wily Werewolf): 2015-10(予定)
- 16.04 LTS: 2016-04(予定)
Debian
2015年4月8〜14日に開催されたPyCon 2015において、DebianのPythonメンテナ陣によるミーティングがあり、その後Python 3への移行がアナウンスされました。
移行の具体的な日付やタイミングは見つかりませんでしたが、2020年にPython 2のメンテナンスが終了することもあり、次期メジャーリリースのDebian 9 (Stretch) またはDebian 10 (Buster) でPython 3をデフォルトにするべく取り組みが始まっているようです。
参考:
- PyCon BoF: Stretch goals for cPython, PyPy & CFFI
- Python/StretchRoadmap - Debian Wiki
- py3porters-devel Info Page
- Python - Debian Wiki
- Debian Python Policy - Python Packaging
- Geoffrey Thomas (geofft)
- /usr/bin/python in Python 2 and 3
ちなみに最近のDebianのリリース日*3は以下の感じです。
- Debian 6.0 (Squeeze): 2011-02-06
- Debian 7 (Wheezy): 2013-05-04
- Debian 8 (Jessie): 2015-04-25
- Debian 9 (Stretch):
20182017? - Debian 10 (Buster):
20212019?
結論
最初に書いたものと同じです。
- PEP 394にディストリビューション向けのガイドラインが公開されている。
- Arch Linuxは既にPython 3がデフォルトになっている。
- Fedora 23(2015-10-27リリース予定)でPython 3がデフォルトになる予定。
-
/usr/bin/python
は削除されるかpython3
にシンボリックリンクされるか議論されている。
-
- Ubuntu 16.04(2016-04リリース予定)でPython 3がデフォルトになる予定。
- Debian 9 (Stretch) または10 (Buster) でPython 3をデフォルトにするべく作業が始まっている。
Python 3を明示的にインストールしなくても普通に使える環境が広がると嬉しいですね。 ディストリビューションのコミッターには本当に頭が下がります。
内容の正確さにあまり自信がないので、間違っていたりもっと良い情報がありましたらお知らせください。 他のディストリビューションの情報も歓迎です。
Joel on Softwareを読んだ
元MicrosoftのJoel氏が書いたエッセイ集です。 自分の中で感じていてもうまく言語化できなかったことが明確に言語化されていて素晴らしかったです。
- 作者: Joel Spolsky,青木靖
- 出版社/メーカー: オーム社
- 発売日: 2005/12
- メディア: 単行本
- 購入: 18人 クリック: 371回
- この商品を含むブログ (446件) を見る
特に印象的だったのは以下の2つの章です。
第12章 5つの世界
5つの世界とは以下の5つを指し、それぞれの世界でそれぞれの苦労があるという話です。
- パッケージ
- インターナル
- 組み込み
- ゲーム
- 使い捨て
インターナルソフトウェア(社内システム)とパッケージソフトウェア(オープンソース、Webベース、コンサルティングウェア)の違いが非常に頷けました。
実際、インターナルソフトウェアとパッケージソフトウェアの主要な違いの1つは、インターナルソフトウェアでは、ある時点以降、それをより頑健にしたり、使いやすくしたりするのにコストをかけることへのリターンは急速に少なくなる一方、パッケージソフトの方は、最後の1%の安定性や使いやすさが競争優位の鍵となり得る点だ。
第18章 二文化主義
UnixとWindowsの違いの話です。自分はUnixの方が便利だと思って常用していますが、自分が使いやすいものと一般的に受け入れられているものとのズレが的確に表現されていました。
Unixは他のプログラマにとって有用なコードに価値を置く文化であり、一方Windowsはプログラマでない人たちにとって有用なコードに価値を置く文化である。
その他
これら2つの章以外にも、商用パッケージソフトウェアの開発に携わってきた作者のOSSやアジャイル開発に対する懐疑的な見方も新鮮でした。
UNIXの考え方やハッカーと画家を読んだときは頷いてばかりでしたが、本書を読んだときは、そういう考え方もあるのかと視野が広がる思いでした。
ハッカーと画家を読んだ
Y Combinator創業者のポール・グレアム氏が書いたエッセイ集です。
- 作者: ポールグレアム,Paul Graham,川合史朗
- 出版社/メーカー: オーム社
- 発売日: 2005/01
- メディア: 単行本
- 購入: 109人 クリック: 4,884回
- この商品を含むブログ (581件) を見る
本書も読み進めていく中で頷いてばかりでしたが、特に表題作の「ハッカーと画家」が印象的でした。
「計算機科学」という言葉のしっくりこなさが明文化されていて、自分だけじゃなかったのだと救われた気がします。
私は「計算機科学」という用語がどうにも好きになれない。一番大きな理由は、そもそもそんなものは存在しないからだ。計算機科学とは、ほとんど関連のない分野が歴史的な偶然からいっしょくたに袋に放り込まれたもので、言ってみればユーゴスラビアみたいなものだ。
また、「昼間の仕事(day job)」という概念が明文化されていて、そういう割り切り方もありなんだと気付かされました。
ソフトウェアに関してのこの問題への解答は、 実は他のもの創りの人々には既に知られている。昼間の仕事(day job)というやつだ。 この言葉はミュージシャンの間で発生した。彼らは夜に演奏するからだ。 より一般的に言えば、生活費のためにひとつの仕事を、愛のためにもうひとつの仕事をするということだ。
これまで自分が目指していく先にハッカーがあるとは思ってなかったのですが、本書を読んで自分が目指す先はハッカーなのかもしれないと思うようになりました。
そしてやはりLispを使いたくなるのでした。
UNIXという考え方を読んだ
もともとUNIXの考え方は理解しているつもりでしたが、ちゃんと言語化されているものを読んだことがなかったので読んでみました。新しい発見があった箇所や非常に頷ける箇所をピックアップします。
- 作者: Mike Gancarz,芳尾桂
- 出版社/メーカー: オーム社
- 発売日: 2001/02
- メディア: 単行本
- 購入: 40人 クリック: 498回
- この商品を含むブログ (140件) を見る
定理3:できるだけ早く試作を作成する
あらゆる試作の目的は、「第三のシステム」に早く到達することだ。
- 第一のシステム:数人で作られ、尖っていて小さく軽い
- 第二のシステム:委員会方式で作られ、多機能で大きくて重い
- 第三のシステム:専門家に作られ、コンセプトは常識となり、正しく作られる
早く第三のシステムに到達するために、素早く試作して素早く失敗することが大事という話。
定理4:効率より移植性
効率が良くても移植性のないソフトウェアの価値は、新しいハードウェアが出た途端に大暴落するので、シェルスクリプトを書くべきという話。
定理6:ソフトウェアの梃子(てこ)を有効に活用する
1時間働いたら、5時間分、100時間分、いや1000時間分の結果を生み出すようにしなさい
既存のアプリケーションをゼロから設計し直すことは模倣ではあっても創造とは言わない
独自技術症候群(Not Invented Here Syndrome)を避け、他人の成果を利用し、他人に成果を利用されるのを認めることで個人の力を増幅できるという話。
定理8:過度の対話的インタフェースを避ける
UNIXは、人間とマシンのどちらがボトルネックなのかを分かっている
最も重要なことに、拘束的ユーザーインタフェースはソフトウェアの梃子の効果を利用できない
対話的インタフェースを使うプログラムは、大きく醜くく他のコマンドと連携しづらいものになるので、避けたほうが良いという話。
定理9:全てのプログラムをフィルタにする
入出力をハードワイアするという裏には、プログラムの使い道が完全に分かっているという思い上がりがある。
ユーザーがソフトウェアをどう使うかは、決して予測できない。設計者である自分の意図に全員が従ってくれるはずだ、などとは絶対に考えてはならない。
プログラムをフィルタとして使えるようにしておくことで、開発者の想定を超える使い方にも対応できるという話。
まとめ
全体的に頷けるところが非常に多い書籍でした。書かれた年代が古いため、事例はピンと来ないものも多いですが、それほど気にならずに読めました。
プログラミングしながら運動できるエアロバイク FitDesk X-2.0を買った
2016-01-16追記: 購入した当初は高いと思っていたサドルですが、座り方で多少改善されるようです。身長160cmの妻でも漕げています。
平日の家に帰ってご飯を食べてから寝るまでの時間はコードを書いていることが多いのですが、まったく運動しないことが気にかかっていました。 運動するためにジムに行くのは面倒だし、コードを書く時間を減らしたくはないので、運動しながらコードを書ける方法がないか考えていました。
そんなときに以下の記事を見て、運動しないとなぁと思っていると、「サイクリングデスク」という言葉が目に入りました。
「The Healthy Programmer」を読んで自宅を快適なプログラミング環境にする - 八発白中
オフィスでは1種類以上のイスを使うこと -- 普通のオフィスチェア、バランスボール、可動式のイス、さらに言えばサイクリングデスク
サイクリングデスクってなんだ?と思ってググって先頭に出てきたもの*1は家庭用ではなかったですが、要するにエアロバイクにPCを置ける机がついていれば良いことに気付きました。
というわけでFitDesk X-2.0という製品を買いました。
FitDesk X-2.0 ジャパンモデル(フィットデスクX-2.0 ジャパンモデル )エアロバイク、パソコン
- 出版社/メーカー: FitDesk
- メディア: スポーツ用品
- この商品を含むブログを見る
以下のページのように普通のエアロバイクに机を足すのでも良いかもしれませんが、安定性やスペースを考えると、多少高くても最初から一体となっている製品を買うのが良いと判断しました。
組み立て
組み立てには大人の男性1人で2時間弱かかりました。 必要な工具は一緒に入っているので問題ありません。
組み立てマニュアルは中国の方が英語から日本語に訳したようで、若干元の英語を想像しながら読解する必要がありますが、なんとかなります。
地味に大変だったのはサドルに棒をくっつけるところです。角度が急な箇所のナットを閉める必要があり、ちょっとずつしか進まないため時間がかかりました。
サイズ的には、アメリカンサイズでかなり大きめです。私は身長170cmですが、サドルを一番下げて、机を一番手前に引いてちょうどいいぐらいです。 小柄な人は注意したほうがいいかもしれません。
また、Amazonのページには以下のように書かれていますが、この横と長さは床に接する部分のサイズです。
サイズ 横41cmx長さ71cmx高さ114cm
実際に組み立てると机の部分が本体より前にせり出すため、空間としては横53cmx長さ110cmぐらい必要です。
サポート
いざ組み立ててしばらく漕いでみるとカタカタと異音がしました。 代理店のWebサイトからサポートに問い合わせてみると、迅速に本体を交換して頂けました。
Amazon.comでは$300以下で販売されている一方、日本では5万円を超えているのも気になっていましたが、サポートを考えると日本の代理店で買って良かったです。
感想
漕ぎながら作業できるのかは若干疑問もありましたが、慣れれば集中して作業できます。この記事も半分ぐらいは漕ぎながら書きました。 逆に疲れたことに気づかずに漕ぎ続けてしまう危険もあると思っていて、最初のうちは意識的に30分ぐらいで辞めるよう気をつけています。
何にせよ、日常生活に運動を取り入れられるのは嬉しいです。 エアロバイクは低めの負荷でスルスルと漕ぐのが良いらしいので、10段階中の下から3段目で漕いでいます。
肝心の机の使い心地は上々です。流石にエアロバイクと一体になっているだけあって安定しています。アームレストがついているので腕がつかれることもありません。机にはMacbook Pro 13 inch がちょうど良く収まります。
ノートPCを置くとメーターは見えなくなるので全く使ってません。アームバンドも置いてあるだけです。机の下の引き出しも使ってないですが、滑りが悪く、使いやすくはなさそうです。
音はほとんど気になりませんが、床を保護するために以前Kinect用に買ったマットを敷いています。
ALINCO(アルインコ) エクササイズ フロアマット 厚さ 9mm EXP150
- 出版社/メーカー: ALINCO(アルインコ)
- 発売日: 2012/04/05
- メディア: スポーツ用品
- 購入: 17人 クリック: 35回
- この商品を含むブログ (2件) を見る