読者です 読者をやめる 読者になる 読者になる

Log.i53

Themidaのアンパックを目指すブログ改め使い物になるえんじにゃを目指すブログ

ふくもく会というイベントに参加してきました

ふくもく会その3~もくもくしなイカ?~

先週末は就活のため実家は福井に帰省中、高専時代の同期からもくもく会に参加してみないか?とのお誘い。モクモク会?タバコなら遠慮しておくぞい…と思ったら違う違う、黙々と作業する会→もくもく会ということでしたw

ふくもく会(福井で黙々と作業する会)は福井でエンジニアやらデザイナーやらで集まって、何かしら勉強したり、作ったりする会…とのことです。土曜は特に用事がなかったためせっかくなので参加することに。場所は福井県産業情報センター7階コワーキングスペースで、景色良し無料wifiも提供されており、さらに私的優良施設基準指標である「トイレに温便座とウォシュレット」を満たしており、良環境でした:)

以下、会場で黙々と作業したことレポートです。

Pythonで Webスクレイピングのお勉強

今大学で行っている研究において、特定のパーミッションを持つオープンソースAndroidアプリケーションを収集したいという目的がありました。そこで見つけたのがF-DroidというWebサイトです。F-DroidはAndroidプラットフォームにおけるFOSS (Free and Open Source Software)の情報が収集されているWebサイトで、FOSSアプリのリポジトリやそのアプリが持つパーミッションを参照することが可能です。

F-DroidはAndroidに対応したソフトウェアリポジトリおよびアプリケーションストアである。Google Playと機能は類似するが、扱っているのはフリーオープンソースソフトウェアのみである。(中略)ウェブサイトでは全配信アプリケーションのソースコードがダウンロードできるようになっている。
F-Droid - Wikipediaより

F-Droidには1500のFOSSアプリが登録されているため、1アプリずつ参照して手動でアプリとそのパーミッションの対応付けを行っていたのではタイムコンシューミングであり、見落としが起こる可能性だってあります。そこでPythonでWebスクレイピングを行い1500のFOSSアプリのパーミッションCSV形式で出力するスクリプトを作成することにしました。CSV化してしまえば、あとは煮るなり焼くなり好きにできます。

requestsライブラリでWebページを取得する

Requestsは、人が使いやすいように設計されていて、Pythonで書かれている Apache2 Licensed ベースのHTTPライブラリです。

Requestsは、ウェブサービスとシームレスに統合されたPythonのHTTP/1.1の処理の全てを受け持ちます。 URLに手動でクエリを入力したり、POSTデータをエンコードしたりする必要はありません。 Keep-aliveやHTTP接続のプーリングは、Requestsに urllib3 が組み込まれているので、100%自動で行われます。

Requests: 人間のためのHTTP — requests-docs-ja 1.0.4 documentationより

requestsでF-DroidのBrowseページをGETしてそのレスポンスを表示するだけの非常にシンプルなスクリプトがこちら。

import requests

r = requests.get('https://f-droid.org/repository/browse/')
print r.text

requests.getの引数 (URL)を動的に設定するだけで Webクローリングが可能になります。他にもシンプルかつ便利な機能がいくつかありますが今回使うのは基本的にこれだけです。詳細についてはドキュメントを参照してください。

lxml.htmlでWebページから必要なデータのみを抽出する

バージョン2.0からlxmlにはHTMLを扱うための専用のPythonパッケージが付属しています。その機能はlxmlのHTMLパーサに基づいていますが、特別なHTML要素のためのElement APIを提供するだけでなく、一般的なHTMLの処理タスクを行うためのいくつかのユーティリティも提供されています。
 
http://lxml.de/lxmlhtml.htmlより

lxml.htmlでF-Droidのアプリのページからパーミッション情報を抜き出そうと考えます。パーミッションを持つアプリのページでパーミッションを選択してChromeであれば右クリックで要素を検証(またはCTRL+SHIFT+I)を選択してパーミッション情報を構成するHTMLエレメントを確認します。
f:id:i53:20150421121630p:plain

F-Droidではアプリの最新のバージョンのパーミッションは、divタグのid属性が"permissions0"のコンテナに内包されています。これはおそらくJavaScriptパーミッションの表示/非表示を切り替えるために設けられたコンテナでしょう。また、古いバージョンのパーミッションはpermissions1, permissions2...でそれぞれ管理されています。さらに、パーミッションはこのコンテナ内のcodeというタグで囲われています。したがって、divタグでid属性が"permissions0"である要素の子要素となるcodeタグを全て抽出すればアプリの最新バージョンのパーミッションを抽出することができます。

lxmlで上記の要素を指定して抽出する方法はいくつか考えられますが、今回はXPath(XML Path Language)を利用してパーミッションのリストを取得することにしました。XPathXML文書の特定の部分を指定する言語構文で、XML文書に対する簡単な問い合わせ言語として利用されています。lxmlでは完全なXPath構文式を評価するXPathメソッドが提供されています。

import requests
import lxml.html

# Adblock Plusのパーミッションを取得するサンプルスクリプト
html = requests.get('https://f-droid.org/repository/browse/?fdid=org.adblockplus.android').text
root = lxml.html.fromstring(html)
permissions = root.xpath('//div[@id="permissions0"]/code')

for p in permissions:
    print p.text_content()

上記の例では「//div[@id="permissions0"]/code」は、ページ内の全てのdiv要素(//div)でid属性が"permissons0"([@id="permissions0"])の子要素がcode(/code)であるもの全てを返します。Adblock Plusは5つのパーミッションを保持しているため、このXPathで問い合わせると5つのElement (code)オブジェクトのリストが返されます。Elementオブジェクトのコンテンツを取得するにはtext_content()メソッドを使用すればよいので、上記の簡単なスクリプトでアプリのパーミッションを標準出力することができるはずです。

あとは、Browseページにある全てのアプリリンクを同様にXpath構文で取得してrequestsでGETして各自パーミッションを抽出し、CSV化することで当初の目的を完遂することができます。以下がふくもく会の時に出力したCSVファイルの中身となります。
f:id:i53:20150421154525p:plain

感想

Pythonは簡単!便利!ライブラリも豊富!Webクローリング・スクレイピングだけではなくてこれから様々な場面で使いこなせるようになっていきたいです:)

また、もくもく会についてですが、自分一人で黙々作業していても途中でダレて(気持ちが緩んで)動画やネットサーフィンに浮気してしまうことが多いですが、こう多人数で集まって黙々と作業することでノルマ達成までのモチベーションの維持につながって良いなと思いました!

注意

F-Droidの利用規約でWebクローリング・スクレイピングを禁止している文面は見当たりませんでしたが、Webサイトによってはサーバへの負荷を考慮してこれらが禁止されていることがあります。岡崎市立中央図書館事件 - Wikipediaなどの事例もありますから、ご利用の際にはWebサイトごとに利用規約で禁止されていないかを確認して、利用する場合には負荷をかけすぎないようにするなど十分注意してください。