2014年8月3日日曜日

AWS上でPiwikでウェブ解析

仕事でPiwikというWebアクセスログ解析ツールを使用する事になったので、AWSで構築してみます。
  • AWS EC2(Red Hat Enterprise Linux 6.5)
    • AWSは、契約済とします。
  • Piwik 2.4.1
  • MacBook Air 10.9.4 (クライアント端末)

  1. AWS EC2でのマシン作成手順。(既にある場合は読み飛ばしてください。)
    1. AWS マネジメントコンソールに接続する
      https://console.aws.amazon.com/console/home
    2. 「EC2」を選択する。
    3. 「Lunch Instance」を選択する。
    4. 「Red Hat Enterprise Linux 6.5(PV)」の「64-bit」を選択して「Select」を選択する。
    5. とりあえず、Type「t1.micro」を選択して「Next: Configure Instance Details」を選択する。
    6. Step 3: Configure Instance Details画面で「Enable termination protection」の「Protect against accidental termination」のチェックボックスをOnにして、「Next: Add Strage」を選択する。
    7. Sizeを「30」、Volume Typeを「General Purpose (SSD)」として、「Next: Tag Instance」を選択する。
    8. Tagは適当に、Name=「Name」、Value=「piwik_test」とかしておく。「Next: Configure Security Group」を選択する。
    9. Step 3: Configure Security Group画面でSSH通信の設定のSourceに「My  IP」を選択し、IPアドレスを確認して、「Review and Launch」を選択する。
    10. 「Lunch」を選択する。「Create a new key pair」を選択し、Key pair nameに「piwik_test」とでも入力し、「Download key pair」をクリックした後に、「Launch Instance」を選択する。
    11. マシンへsshで接続する。rootのパスワードを設定しておく。
      $ sudo su -
      # passwd
  2. piwikをインストールする。(主にrootで実施)
    1. 公式サイトからPiwikをダウンロードしておく。
      # wget http://builds.piwik.org/piwik.zip
      --2014-08-02 08:27:36--  http://builds.piwik.org/piwik.zip
      Resolving builds.piwik.org... 176.31.58.94
      Connecting to builds.piwik.org|176.31.58.94|:80... connected.
      HTTP request sent, awaiting response... 200 OK
      Length: 10143342 (9.7M) [application/zip]
      Saving to: “piwik.zip”
      
      100%[======================================>] 10,143,342  2.67M/s   in 4.6s
      
      2014-08-02 08:27:42 (2.10 MB/s) - “piwik.zip” saved [10143342/10143342]
    2. Apache(Webサーバ)のインストール
      # yum -y install httpd
    3. PHP関連パッケージインストール
      # yum -y install php php-mysql php-pdo php-mbstring php-xml php-gd
    4. MySQLインストール
      # yum -y install mysql mysql-server mysql-libs
    5. MySQL初期設定と起動
      # mysql_secure_installation
      NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
            SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!
      
      
      In order to log into MySQL to secure it, we'll need the current
      password for the root user.  If you've just installed MySQL, and
      you haven't set the root password yet, the password will be blank,
      so you should just press enter here.
      
      Enter current password for root (enter for none):
      OK, successfully used password, moving on...
      
      Setting the root password ensures that nobody can log into the MySQL
      root user without the proper authorisation.
      
      Set root password? [Y/n] Y
      New password:
      Re-enter new password:
      Password updated successfully!
      Reloading privilege tables..
       ... Success!
      
      
      By default, a MySQL installation has an anonymous user, allowing anyone
      to log into MySQL without having to have a user account created for
      them.  This is intended only for testing, and to make the installation
      go a bit smoother.  You should remove them before moving into a
      production environment.
      
      Remove anonymous users? [Y/n] Y
       ... Success!
      
      Normally, root should only be allowed to connect from 'localhost'.  This
      ensures that someone cannot guess at the root password from the network.
      
      Disallow root login remotely? [Y/n] Y
       ... Success!
      
      By default, MySQL comes with a database named 'test' that anyone can
      access.  This is also intended only for testing, and should be removed
      before moving into a production environment.
      
      Remove test database and access to it? [Y/n] Y
       - Dropping test database...
       ... Success!
       - Removing privileges on test database...
       ... Success!
      
      Reloading the privilege tables will ensure that all changes made so far
      will take effect immediately.
      
      Reload privilege tables now? [Y/n] Y
       ... Success!
      
      Cleaning up...
      
      
      
      All done!  If you've completed all of the above steps, your MySQL
      installation should now be secure.
      
      Thanks for using MySQL!
      # mysql -uroot -p
      <省略>
      mysql> create user piwik identified by '****';    パスワード「****」は、任意の文字列を入れる。
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> create database piwik;
      Query OK, 1 row affected (0.00 sec)
      
      mysql> show databases;
      +--------------------+
      | Database           |
      +--------------------+
      | information_schema |
      | mysql              |
      | piwik              |
      +--------------------+
      3 rows in set (0.00 sec)
      
      mysql> grant all on piwik.* to piwik;
      Query OK, 0 rows affected (0.00 sec)
      
      # mysql piwik -upiwik -p
      Enter password:
      

    1. Piwikインストール
      # mkdir /var/www/html/piwik
      # unzip piwik.zip
      # cp -rp piwik/* /var/www/html/piwik
      # rm -f How\ to\ install\ Piwik.html
      # chown -R apache:apache /var/www/html/piwik
    2. Apache起動
      # service httpd start
    3. ブラウザで「http://<Public DNS or IP adress of the instance>/piwik/」に接続する。と、以下のような画面が出る。「次へ」を選択する。
    4. システムの確認画面で、すべてチェックが入っていることを確認し、「次へ」を選択する。
    5. データベースのセットアップを以下の用に入力する。パスワードは、MySQKでpiwikユーザを作成した際に設定したものをしていする。
      「データベースサーバ」が、デフォルトで「127.0.0.1」になっているが、なぜか接続が失敗するので、「localhost」に変更するとうまくいった。が、原因は不明。。。
    6. 「次へ」を選択すると、テーブル作成が正常にできたメッセージが表示される。さらに、「次へ」を選択する。
    7. スーパーユーザ画面で、任意の名前とパスワードのユーザを作成する。「次へ」を選択すると進むウェブサイトのセットアップ画面でこのブログを登録してみる。

    8. 「次へ」を選択すると、解析対象のWebサイトに埋め込むJavaScriptのタグが表示されるので、それをコピーして対象Webサイトの「</body>」の前にペーストする。「次へ」を選択して、最後に「Piwikを続ける」を選択する。
    9. ブラウザで「http://<Public DNS or IP adress of the instance>/piwik/」に接続する。先ほど、作成したスーパユーザのアカウント情報を使ってログインする。

    10. 以下のようなダッシュボード画面がみれる。
なんかいろいろみれそうです!まさに、Google Analiticsに似ている。Piwikおもしろそうです。
また、AWSもすぐに仮想マシンが作成できて便利!

おわり

2013年3月13日水曜日

Rでトピック分析(LDA:Latent Dirichlet Allocatoion)

テキストマイニング手法のひとつであるトピック分析をR言語を使ってやってみる。

トピック分析とは、簡単に言うと、単語の出現確率の組み合わせで表現されたトピックにより与えられた文書のテーマを推定する手法である。(と思っています)
これをLDA:Latent Dirichlet Allocationというトピックモデルを用いて行う。CRANにRのLDAパッケージが存在する。

  • Mac Book Air
  • Mac OS 10.8.2
  • R 2.15.1


  1. インストール
  2. Rはインストールされているものとする。
    > install.packages("lda")
     --- このセッションで使うために、CRANのミラーサイトを選んでください --- 
            
    Tcl/Tkインターフェースのロード中   終了済 
    CRAN mirror 
    
     1: 0-Cloud                       2: Argentina (La Plata)       
     3: Argentina (Mendoza)           4: Australia (Canberra)       
     5: Australia (Melbourne)         6: Austria                    
     7: Belgium                       8: Brazil (PR)                
     9: Brazil (RJ)                  10: Brazil (SP 1)              
    11: Brazil (SP 2)                12: Canada (BC)                
    13: Canada (NS)                  14: Canada (ON)                
    15: Canada (QC 1)                16: Canada (QC 2)              
    17: Chile                        18: China (Beijing 1)          
    19: China (Beijing 2)            20: China (Guangzhou)          
    21: China (Hefei)                22: China (Xiamen)             
    23: Colombia (Bogota)            24: Colombia (Cali)            
    25: Denmark                      26: Ecuador                    
    27: France (Lyon 1)              28: France (Lyon 2)            
    29: France (Montpellier)         30: France (Paris 1)           
    31: France (Paris 2)             32: Germany (Berlin)           
    33: Germany (Bonn)               34: Germany (Falkenstein)      
    35: Germany (Goettingen)         36: Greece                     
    37: Hungary                      38: India                      
    39: Indonesia                    40: Iran                       
    41: Ireland                      42: Italy (Milano)             
    43: Italy (Padua)                44: Italy (Palermo)            
    45: Japan (Hyogo)                46: Japan (Tsukuba)            
    47: Japan (Tokyo)                48: Korea (Seoul 1)            
    49: Korea (Seoul 2)              50: Latvia                     
    51: Mexico (Mexico City)         52: Mexico (Texcoco)           
    53: Netherlands (Amsterdam)      54: Netherlands (Utrecht)      
    55: New Zealand                  56: Norway                     
    57: Philippines                  58: Poland                     
    59: Russia                       60: Singapore                  
    61: Slovakia                     62: South Africa (Cape Town)   
    63: South Africa (Johannesburg)  64: Spain (Madrid)             
    65: Sweden                       66: Switzerland                
    67: Taiwan (Taichung)            68: Taiwan (Taipei)            
    69: Thailand                     70: Turkey                     
    71: UK (Bristol)                 72: UK (London)                
    73: UK (St Andrews)              74: USA (CA 1)                 
    75: USA (CA 2)                   76: USA (IA)                   
    77: USA (IN)                     78: USA (KS)                   
    79: USA (MD)                     80: USA (MI)                   
    81: USA (MO)                     82: USA (OH)                   
    83: USA (OR)                     84: USA (PA 1)                 
    85: USA (PA 2)                   86: USA (TN)                   
    87: USA (TX 1)                   88: USA (WA 1)                 
    89: USA (WA 2)                   90: Venezuela                  
    91: Vietnam                      
    
     選択: 
     メニューから項目を入力するか、0 を入力して終了して下さい 
     選択: 46
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/lda_1.3.2.tgz' を試しています 
    Content type 'application/x-gzip' length 460292 bytes (449 Kb)
     開かれた URL 
    ==================================================
    downloaded 449 Kb
    
    
     ダウンロードされたパッケージは、以下にあります 
      /var/folders/1c/8xf1yn7x5zl37mfvqjrl31ph0000gp/T//RtmpIxno8E/downloaded_packages 
    
    さらに関連パッケージをインストールしておきます。
    > install.packages("reshape2")
    also installing the dependencies ‘plyr’, ‘stringr’
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/plyr_1.8.tgz' を試しています 
    Content type 'application/x-gzip' length 726655 bytes (709 Kb)
     開かれた URL 
    ==================================================
    downloaded 709 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/stringr_0.6.2.tgz' を試しています 
    Content type 'application/x-gzip' length 70411 bytes (68 Kb)
     開かれた URL 
    ==================================================
    downloaded 68 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/reshape2_1.2.2.tgz' を試しています 
    Content type 'application/x-gzip' length 56717 bytes (55 Kb)
     開かれた URL 
    ==================================================
    downloaded 55 Kb
    
    
     ダウンロードされたパッケージは、以下にあります 
      /var/folders/1c/8xf1yn7x5zl37mfvqjrl31ph0000gp/T//RtmpIxno8E/downloaded_packages 
    > install.packages("Matrix")
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/Matrix_1.0-11.tgz' を試しています 
    Content type 'application/x-gzip' length 4066929 bytes (3.9 Mb)
     開かれた URL 
    ==================================================
    downloaded 3.9 Mb
    
    
     ダウンロードされたパッケージは、以下にあります 
      /var/folders/1c/8xf1yn7x5zl37mfvqjrl31ph0000gp/T//RtmpIxno8E/downloaded_packages 
    > install.packages("ggplot2")
    also installing the dependencies ‘colorspace’, ‘RColorBrewer’, ‘dichromat’, ‘munsell’, ‘labeling’, ‘digest’, ‘gtable’, ‘scales’, ‘proto’
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/colorspace_1.2-1.tgz' を試しています 
    Content type 'application/x-gzip' length 404391 bytes (394 Kb)
     開かれた URL 
    ==================================================
    downloaded 394 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/RColorBrewer_1.0-5.tgz' を試しています 
    Content type 'application/x-gzip' length 22390 bytes (21 Kb)
     開かれた URL 
    ==================================================
    downloaded 21 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/dichromat_2.0-0.tgz' を試しています 
    Content type 'application/x-gzip' length 144378 bytes (140 Kb)
     開かれた URL 
    ==================================================
    downloaded 140 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/munsell_0.4.tgz' を試しています 
    Content type 'application/x-gzip' length 125546 bytes (122 Kb)
     開かれた URL 
    ==================================================
    downloaded 122 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/labeling_0.1.tgz' を試しています 
    Content type 'application/x-gzip' length 35236 bytes (34 Kb)
     開かれた URL 
    ==================================================
    downloaded 34 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/digest_0.6.3.tgz' を試しています 
    Content type 'application/x-gzip' length 161113 bytes (157 Kb)
     開かれた URL 
    ==================================================
    downloaded 157 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/gtable_0.1.2.tgz' を試しています 
    Content type 'application/x-gzip' length 60865 bytes (59 Kb)
     開かれた URL 
    ==================================================
    downloaded 59 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/scales_0.2.3.tgz' を試しています 
    Content type 'application/x-gzip' length 169299 bytes (165 Kb)
     開かれた URL 
    ==================================================
    downloaded 165 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/proto_0.3-10.tgz' を試しています 
    Content type 'application/x-gzip' length 454829 bytes (444 Kb)
     開かれた URL 
    ==================================================
    downloaded 444 Kb
    
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/ggplot2_0.9.3.1.tgz' を試しています 
    Content type 'application/x-gzip' length 2659920 bytes (2.5 Mb)
     開かれた URL 
    ==================================================
    downloaded 2.5 Mb
    
    
     ダウンロードされたパッケージは、以下にあります 
      /var/folders/1c/8xf1yn7x5zl37mfvqjrl31ph0000gp/T//RtmpIxno8E/downloaded_packages 
    > install.packages("penalized")
     URL 'http://cran.md.tsukuba.ac.jp/bin/macosx/leopard/contrib/2.15/penalized_0.9-42.tgz' を試しています 
    Content type 'application/x-gzip' length 522276 bytes (510 Kb)
     開かれた URL 
    ==================================================
    downloaded 510 Kb
    
    
     ダウンロードされたパッケージは、以下にあります 
      /var/folders/1c/8xf1yn7x5zl37mfvqjrl31ph0000gp/T//RtmpIxno8E/downloaded_packages 
    

  3. デモ実行
  4. > library("lda")
    > demo(lda)
    
    
     demo(lda)
     ---- ~~~
    
    Type    to start : 
    
    > require("ggplot2")
    Loading required package: ggplot2
    
    > require("reshape2")
    Loading required package: reshape2
    
    > data(cora.documents)
    
    > data(cora.vocab)
    
    > theme_set(theme_bw())  
    
    > set.seed(8675309)
    
    > K <- data-blogger-escaped-10="" data-blogger-escaped-clusters="" data-blogger-escaped-num=""> result <- data-blogger-escaped-0.1="" data-blogger-escaped-25="" data-blogger-escaped-clusters="" data-blogger-escaped-compute.log.likelihood="TRUE)" data-blogger-escaped-cora.documents="" data-blogger-escaped-cora.vocab="" data-blogger-escaped-iterations="" data-blogger-escaped-k="" data-blogger-escaped-lda.collapsed.gibbs.sampler="" data-blogger-escaped-num=""> ## Get the top words in the cluster
    > top.words <- data-blogger-escaped-5="" data-blogger-escaped-by.score="TRUE)" data-blogger-escaped-result="" data-blogger-escaped-top.topic.words="" data-blogger-escaped-topics=""> ## Number of documents to display
    > N <- data-blogger-escaped-10=""> topic.proportions <- data-blogger-escaped-colsums="" data-blogger-escaped-document_sums="" data-blogger-escaped-result="" data-blogger-escaped-t=""> topic.proportions <- data-blogger-escaped-dim="" data-blogger-escaped-n="" data-blogger-escaped-sample="" data-blogger-escaped-topic.proportions=""> topic.proportions[is.na(topic.proportions)] <- data-blogger-escaped-1="" data-blogger-escaped-k=""> colnames(topic.proportions) <- data-blogger-escaped-2="" data-blogger-escaped-apply="" data-blogger-escaped-collapse=" " data-blogger-escaped-paste="" data-blogger-escaped-top.words=""> topic.proportions.df <- data-blogger-escaped-cbind="" data-blogger-escaped-data.frame="" data-blogger-escaped-document="factor(1:N))," data-blogger-escaped-id.vars="document" data-blogger-escaped-melt="" data-blogger-escaped-topic.proportions="" data-blogger-escaped-variable.name="topic"> qplot(topic, value, fill=document, ylab="proportion",
    +       data=topic.proportions.df, geom="bar") +
    +   opts(axis.text.x = theme_text(angle=90, hjust=1)) +  
    +   coord_flip() +
    +   facet_wrap(~ document, ncol=5)
    'opts' is deprecated. Use 'theme' instead. (Deprecated; last used in version 0.9.1)
    theme_text is deprecated. Use 'element_text' instead. (Deprecated; last used in version 0.9.1)
     次の図を見るためにはキーを押して下さい:  
    
    キーを叩くと、下のような画面が出現する。

    四角の枠は、10個のドキュメントの分析結果それぞれを表している。
    縦軸の各項目がトピックでその内の単語はそのトピックで使われる代表的な単語である。この単語群からトピックの内容を把握する。
    横軸は、各トピックの各ドキュメントにおけるトピックの割合(最大1)である。LDAでは、ドキュメントのテーマは複数のトピックの混合で表現される。

  5. 外部データ読み込み
  6. 外部データを取り込んでこのLDAに食わせてみる。
    利用するコーパスは、NLTKのデータセット「nltk.corpus.webtext」とする。
    このファイル一つを1ドキュメントとする。各ドキュメントに対して前処理として以下を実施した。
    • 小文字に変換
    • ASCII文字コードの「SP(¥x20)」から「~(¥x7e)」以外を除去
    • 文末のコンマを除去
    • -ing, -s, -edなどを除去(nltkのLancasterStemmer()を利用)
    • 意味のないトークンを除去(アルファベット以外のみで構成された単語)
    • ストップワードを除去(and, a, the, など)
    下記のソースコード参照

    ドキュメント毎の文字列のリストと語彙のリストからLDAが食える形に変換することが可能である。
    > doclines <- data-blogger-escaped-6="" data-blogger-escaped-docr.txt="" data-blogger-escaped-earn_r="" data-blogger-escaped-items="" data-blogger-escaped-lda="" data-blogger-escaped-read="" data-blogger-escaped-scan="" data-blogger-escaped-sep="\n" data-blogger-escaped-sers="" data-blogger-escaped-shu222="" data-blogger-escaped-what="character"> vocablist <- data-blogger-escaped-11826="" data-blogger-escaped-earn_r="" data-blogger-escaped-items="" data-blogger-escaped-lda="" data-blogger-escaped-read="" data-blogger-escaped-scan="" data-blogger-escaped-sep="\n" data-blogger-escaped-sers="" data-blogger-escaped-shu222="" data-blogger-escaped-vocab.txt="" data-blogger-escaped-what="character"> library(lda)
    >  corpus <- data-blogger-escaped-doclines="" data-blogger-escaped-lexicalize="" data-blogger-escaped-lower="TRUE," data-blogger-escaped-pre="" data-blogger-escaped-sep=" " data-blogger-escaped-vocab="vocablist)">
    
    
    崩壊型ギブスサンプリングのLDAを実行する。
    
    
    • トピック数:10
    • サンプリング回数:25
    • ハイパーパラメータα:0.1
    • ハイパーパラメータβ:0.1
    > result <- data-blogger-escaped-0.1="" data-blogger-escaped-10="" data-blogger-escaped-25="" data-blogger-escaped-compute.log.likelihood="TRUE)" data-blogger-escaped-corpus="" data-blogger-escaped-lda.collapsed.gibbs.sampler="" data-blogger-escaped-pre="" data-blogger-escaped-vocablist="">
    
    
    可視化。
    
    
    > require("ggplot2")
     要求されたパッケージ ggplot2 をロード中です 
     警告メッセージ: 
     パッケージ '‘ggplot2’' はバージョン 2.15.2 の R の下で造られました  
    > require("reshape2")
     要求されたパッケージ reshape2 をロード中です 
    > theme_set(theme_bw())
    > top.words <- data-blogger-escaped-5="" data-blogger-escaped-by.score="TRUE)" data-blogger-escaped-result="" data-blogger-escaped-top.topic.words="" data-blogger-escaped-topics=""> N <- data-blogger-escaped-6=""> topic.proportions <- data-blogger-escaped-colsums="" data-blogger-escaped-document_sums="" data-blogger-escaped-result="" data-blogger-escaped-t=""> topic.proportions <- data-blogger-escaped-dim="" data-blogger-escaped-n="" data-blogger-escaped-sample="" data-blogger-escaped-topic.proportions=""> topic.proportions[is.na(topic.proportions)] <- data-blogger-escaped-10="" data-blogger-escaped-1=""> colnames(topic.proportions) <- data-blogger-escaped-2="" data-blogger-escaped-apply="" data-blogger-escaped-collapse=" " data-blogger-escaped-paste="" data-blogger-escaped-top.words=""> topic.proportions.df <- data-blogger-escaped-cbind="" data-blogger-escaped-data.frame="" data-blogger-escaped-document="factor(1:N))," data-blogger-escaped-id.vars="document" data-blogger-escaped-melt="" data-blogger-escaped-topic.proportions="" data-blogger-escaped-variable.name="topic"> qplot(topic, value, fill=document, ylab="proportion", data=topic.proportions.df, geom="bar") +
    + opts(axis.text.x = theme_text(angle=90, hjust=1)) +
    + coord_flip() + facet_wrap(~ document, ncol=3)
    
    するとこんなグラフが。 ちなみに、イテレーションを500した場合のグラフ。 ドキュメント3ドキュメント1は、「パイレーツ・オブ・カリビアン」について書かれていそうだ。
  7. データファイル作成プログラム
  8. 参考として、今回使用したPythonコード。コメント皆無で恐縮です。
    #!/usr/bin/env python
    # -*- encoding: utf_8 -*-
    
    import re, random
    import nltk
    
    class MyDocs:
      def __init__(self, rawDocs, stopwordFilePath, stemmer):
        self.docs = []
        for rawDoc in rawDocs:
          tokens = nltk.word_tokenize(rawDoc)
    
          tokens = self.tolowerTokens(tokens)
          tokens = self.removeNotASCII(tokens)
          tokens = self.removeEndComma(tokens)
          tokens = self.stemmingTokens(tokens, stemmer)
          tokens = self.removeMeaninglessTokens(tokens)
          tokens = self.removeStopword(tokens, stopwordFilePath)
    
          self.docs.append(tokens)
    
      def tolowerTokens(self, tokens):
        newTokens = [token.lower() for token in tokens]
        return newTokens
    
      def removeNotASCII(self, tokens):
        newTokens = []
        for token in tokens:
          rep = re.sub(r'[^\x20-\x7e]', '', token)
          newTokens.append(rep)
        return newTokens
    
      def stemmingTokens(self, tokens, stemmer):
        if stemmer is None:
          stemmer = nltk.LancasterStemmer()
        newTokens = [stemmer.stem(token) for token in tokens]
        return newTokens
    
      def removeMeaninglessTokens(self, tokens):
        newTokens = []
        for token in tokens:
          if not re.match(r'^[^a-z]+.*$', token):
            newTokens.append(token)
        return newTokens
    
      def removeEndComma(self, tokens):
        newTokens = []
        for token in tokens:
          rep = re.sub(r'\.$', '', token)
          newTokens.append(rep)
        return newTokens
    
      def removeStopword(self, tokens, stopwordFilePath):
        f = open(stopwordFilePath)
        stopwords = f.read().split()
        f.close()
        newTokens = []
        for token in tokens:
          if not token in stopwords:
            newTokens.append(token)
        return newTokens
    
      def getVocablary(self):
        allTokens = []
        for doc in self.docs:
          allTokens += doc
        return sorted(set(allTokens))
    
      def getDocForRLDA(self):
        docForR = []
        for doc in self.docs:
          docStr = ' '.join(doc)
          docStr += '\n'
          docForR.append(docStr)
        return docForR
    
    
    def main():
      docs = []
      for fileid in nltk.corpus.webtext.fileids():
        docs.append(nltk.corpus.webtext.raw(fileid))
    
      stopwordFilePath = './stopword.list'
      stemmer = nltk.LancasterStemmer()
    
      mydocs = MyDocs(docs, stopwordFilePath, stemmer)
    
      vocabs = mydocs.getVocablary()
      f = open('./vocab.txt', 'w')
      for vocab in vocabs:
        f.write(vocab + '\n')
      f.close()
    
      docForR = mydocs.getDocForRLDA()
      f = open('./docR.txt', 'w')
      for doc in docForR:
        f.write(doc)
      f.close()
    
    if __name__ == '__main__':
      main()
    

おわり

2013年2月24日日曜日

[SSLの勉強2]:クライアント証明書と認証

本などで勉強しても全く頭に入らないので、手を動かして理解する。
今回は、クライアントの認証を導入してみる。前回の設定等が済まされた状態を前提とする。

  • Mac Book Air
  • Mac OS X 10.8.2
  • OpenSSL 0.9.8
  • Apache 2.2.22
  • Google Chrome 24.0.1312

  1. クライントの秘密鍵・証明書作成
  2. 前回と同じように~/pkiで作業を行う。
    $ cd ~/pki
    $ mkdir ~/pki/client
    
    まずは、クライアントの秘密鍵の作成。
    $ openssl genrsa -des3 -out ~/pki/client/client.key 1024
    Generating RSA private key, 1024 bit long modulus
    ..++++++
    .....++++++
    e is 65537 (0x10001)
    Enter pass phrase for /Users/shu222/pki/client/client.key:
    Verifying - Enter pass phrase for /Users/shu222/pki/client/client.key:
    次に、クライアントの認証局への署名要求書の作成。
    $ openssl req -new -days 365 -key ~/pki/client/client.key -out ~/pki/client/csr.pem
    Enter pass phrase for /Users/shu222/pki/client/client.key:
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [JP]:
    State or Province Name (full name) [Kobe]:
    Locality Name (eg, city) [Chuo-ku]:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (eg, YOUR name) []:noah
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    CAで署名する。クライアント証明書の出来上がり。
    $ openssl ca -in ~/pki/client/csr.pem -keyfile ~/pki/demoCA/private/cakey.pem -cert ~/pki/demoCA/cacert.pem -out ~/pki/client/cert.pem
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Enter pass phrase for /Users/testuser/pki/demoCA/private/cakey.pem:
    Check that the request matches the signature
    Signature ok
    Certificate Details:
            Serial Number:
                bd:48:b8:5b:4c:1c:57:12
            Validity
                Not Before: Feb 23 13:55:05 2013 GMT
                Not After : Feb 21 13:55:05 2023 GMT
            Subject:
                countryName               = JP
                stateOrProvinceName       = Kobe
                organizationName          = Internet Widgits Pty Ltd
                commonName                = noah
            X509v3 extensions:
                X509v3 Basic Constraints: 
                    CA:FALSE
                Netscape Cert Type: 
                    SSL Server
                Netscape Comment: 
                    OpenSSL Generated Certificate
                X509v3 Subject Key Identifier: 
                    0A:F6:CB:01:4E:FD:0C:4B:DB:3E:E1:6B:76:9A:C6:63:B8:49:64:57
                X509v3 Authority Key Identifier: 
                    keyid:09:18:4F:0E:9D:62:76:25:9D:1D:7F:34:9E:CC:5F:47:C0:DA:41:6B
    
    Certificate is to be certified until Feb 21 13:55:05 2023 GMT (3650 days)
    Sign the certificate? [y/n]:y
    
    
    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    
  3. ApacheのSSL設定
  4. Apacheを停止しておく。
    $ sudo apachectl stop
    httpd-ssl.confに以下の設定を記述する。

    認証局の証明書があるディレクトリのパス
    SSLCACertificatePath "/Users/testuser/pki/demoCA"
    認証局の証明書ファイルのパス
    SSLCACertificateFile "/Users/testuser/pki/demoCA/cacert.pem"
    クライントの認証方式。{none | optional | require | optional_no_ca}が選択できるよう。
    SSLVerifyClient require
    証明書チェインにおいて認証局を辿る深さ。今回はオレオレなので1。
    SSLVerifyDepth  1
  5. ブラウザにクライアント証明書を設定
  6. まず、クライアント証明書をpkcs12形式に変換する。
    $ openssl pkcs12 -export -in ~/pki/client/cert.pem -inkey ~/pki/client/client.key -certfile ~/pki/demoCA/cacert.pem -out ~/pki/client/cert.p12
    Chromeの場合、メニューバーの「Chrome」→「環境設定...」→一番下にスクロールして「詳細設定を表示...」
    →HTTP/SSLのエリアの「証明書の管理」→キーチェーンアクセスが起動→メニューバーの「ファイル」→「読み込む...」
    →クライアント証明書のファイル(上の場合だと、cert.p12)を選択して「開く」
    これでブラウザはクライアント証明書をサーバに送れるようになる。
    ちなみに設定前は、以下のような画面で警告される。

おわり

2013年2月23日土曜日

[SSLの勉強1]:CA構築とサーバ証明書

本などで勉強しても全く頭に入らないので、手を動かして理解する。
いわゆる自己認証・自己証明書作成をやってみる。

  • Mac Book Air
  • Mac OS X 10.8.2
  • OpenSSL 0.9.8
  • Apache 2.2.22

  1. openssl.cfgの作成
  2. ユーザホームディレクトリにpkiというディレクトリを作成し、そこで作業することとする。
    $ mkdir ~/pki
    $ cd ~/pki
    $ sudo cp /System/Library/OpenSSL/openssl.cnf /System/Library/OpenSSL/openssl.cnf.org
    $ vi /System/Library/OpenSSL/openssl.cnf
    今回使用したファイルは以下のとおり。

    openssl.cfg
    #
    # OpenSSL example configuration file.
    # This is mostly being used for generation of certificate requests.
    #
    
    HOME   = .
    RANDFILE  = $ENV::HOME/.rnd
    
    oid_section  = new_oids
    
    [ new_oids ]
    
    ####################################################################
    [ ca ]
    default_ca = CA_default  # The default ca section
    
    ####################################################################
    [ CA_default ]
    
    dir  = ./demoCA
    certs  = $dir/certs
    crl_dir  = $dir/crl
    database = $dir/index.txt
    new_certs_dir = $dir/newcerts
    
    certificate = $dir/cacert.pem 
    serial  = $dir/serial 
    crlnumber = $dir/crlnumber
    crl  = $dir/crl.pem
    private_key = $dir/private/cakey.pem
    RANDFILE = $dir/private/.rand
    
    x509_extensions = usr_cert
    
    name_opt  = ca_default
    cert_opt  = ca_default
    
    default_days = 3650
    default_crl_days= 30
    default_md = sha1
    preserve = no
    
    policy  = policy_match
    
    [ policy_match ]
    countryName  = match
    stateOrProvinceName = match
    organizationName = match
    organizationalUnitName = optional
    commonName  = supplied
    emailAddress  = optional
    
    [ policy_anything ]
    countryName  = optional
    stateOrProvinceName = optional
    localityName  = optional
    organizationName = optional
    organizationalUnitName = optional
    commonName  = supplied
    emailAddress  = optional
    
    ####################################################################
    [ req ]
    default_bits  = 2048
    default_keyfile  = privkey.pem
    distinguished_name = req_distinguished_name
    attributes  = req_attributes
    x509_extensions  = v3_ca 
    
    string_mask = nombstr
    
    [ req_distinguished_name ]
    countryName   = Country Name (2 letter code)
    countryName_default  = JP
    countryName_min   = 2
    countryName_max   = 2
    
    stateOrProvinceName  = State or Province Name (full name)
    stateOrProvinceName_default = Kobe
    
    localityName   = Locality Name (eg, city)
    localityName_default  = Chuo-ku
    
    0.organizationName  = Organization Name (eg, company)
    0.organizationName_default = Internet Widgits Pty Ltd
    
    organizationalUnitName  = Organizational Unit Name (eg, section)
    
    commonName   = Common Name (eg, YOUR name)
    commonName_max   = 64
    
    emailAddress   = Email Address
    emailAddress_max  = 64
    
    [ req_attributes ]
    challengePassword  = A challenge password
    challengePassword_min  = 4
    challengePassword_max  = 20
    
    unstructuredName  = An optional company name
    
    [ usr_cert ]
    basicConstraints=CA:FALSE
    
    nsComment   = "OpenSSL Generated Certificate"
    
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid,issuer
    
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    
    [ v3_ca ]
    subjectKeyIdentifier=hash
    
    authorityKeyIdentifier=keyid:always,issuer:always
    
    basicConstraints = CA:true
    
    [ crl_ext ]
    authorityKeyIdentifier=keyid:always,issuer:always
    
    [ proxy_cert_ext ]
    basicConstraints=CA:FALSE
    
    nsComment   = "OpenSSL Generated Certificate"
    
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid,issuer:always
    
    proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
  3. CA構築
  4. $ /System/Library/OpenSSL/misc/CA.sh -newca
    CA certificate filename (or enter to create)
    
    Making CA certificate ...
    Generating a 2048 bit RSA private key
    ...................................................................+++
    ....................................................................................................................................+++
    writing new private key to './demoCA/private/./cakey.pem'
    Enter PEM pass phrase: <== 任意のパスワードを入力
    Verifying - Enter PEM pass phrase: <== もう一度入力
    -----
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [JP]:
    State or Province Name (full name) [Kobe]:
    Locality Name (eg, city) [Chuo-ku]:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (eg, YOUR name) []:noah <== ホスト名(FQDN)入力
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Enter pass phrase for ./demoCA/private/./cakey.pem:  <== 任意のパスワードを入力
    Check that the request matches the signature
    Signature ok
    Certificate Details:
            Serial Number:
                a5:f1:29:54:f4:12:9e:c4
            Validity
                Not Before: Feb 20 16:02:51 2013 GMT
                Not After : Feb 20 16:02:51 2016 GMT
            Subject:
                countryName               = JP
                stateOrProvinceName       = Kobe
                organizationName          = Internet Widgits Pty Ltd
                commonName                = noah
            X509v3 extensions:
                X509v3 Subject Key Identifier: 
                    40:8C:0E:CF:F6:70:8F:09:83:E0:4A:19:31:63:3A:66:3D:9C:23:0E
                X509v3 Authority Key Identifier: 
                    keyid:40:8C:0E:CF:F6:70:8F:09:83:E0:4A:19:31:63:3A:66:3D:9C:23:0E
                    DirName:/C=JP/ST=Kobe/O=Internet Widgits Pty Ltd/CN=noah
                    serial:A5:F1:29:54:F4:12:9E:C4
    
                X509v3 Basic Constraints: 
                    CA:TRUE
    Certificate is to be certified until Feb 20 16:02:51 2016 GMT (1095 days)
    
    Write out database with 1 new entries
    Data Base Updated
    
    作業ディレクトリのdemoCAに認証局証明書(cacert.pem)などができている。
    $ ls ~/pki/demoCA/
    cacert.pem certs  index.txt index.txt.old private
    careq.pem crl  index.txt.attr newcerts serial
    CAの証明書の中身は以下で確認できる。
    $ openssl x509 -in ~/pki/demoCA/cacert.pem -text
  5. サーバの秘密鍵作成
  6. サーバ用のディレクトリを作成して作業。パスワード設定のため入力を求められます。
    $ mkdir ~/pki/server
    $ openssl genrsa -des3 -out ~/pki/server/server.key 1024
    $ ls ~/pki/server
    server.key
    
    これがサーバの秘密鍵になります。
  7. サーバ証明書作成
  8. サーバの証明書に信頼性を持たせるため認証局に署名をしてもらう必要があります。
    これによって、そのサーバが本物であることをクライアントに示すことができます。
    ここでは、認証局も自前なので一般的になんの信頼性もないサーバ証明書になります。(いわゆるオレオレ)

    まずは、署名要求書の作成。CA構築時と全く同じ回答をします。
    $ openssl req -new -days 365 -key ~/pki/server/server.key -out ~/pki/server/csr.pem
    Enter pass phrase for /Users/testuser/pki/server/server.key:
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [JP]:
    State or Province Name (full name) [Kobe]:
    Locality Name (eg, city) [Chuo-ku]:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:
    Organizational Unit Name (eg, section) []:
    Common Name (eg, YOUR name) []:noah
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    $ ls ~/pki/server/
    csr.pem  server.key
    このファイルを使って認証局に署名してもらいます。
    $ openssl ca -in ~/pki/server/csr.pem -keyfile ~/pki/demoCA/private/cakey.pem -cert ~/pki/demoCA/cacert.pem -out ~/pki/server/cert.pem
    Using configuration from /System/Library/OpenSSL/openssl.cnf
    Enter pass phrase for /Users/testuser/pki/demoCA/private/cakey.pem:
    Check that the request matches the signature
    Signature ok
    Certificate Details:
            Serial Number:
                bd:48:b8:5b:4c:1c:57:11
            Validity
                Not Before: Feb 23 02:48:56 2013 GMT
                Not After : Feb 21 02:48:56 2023 GMT
            Subject:
                countryName               = JP
                stateOrProvinceName       = Kobe
                organizationName          = Internet Widgits Pty Ltd
                commonName                = noah
            X509v3 extensions:
                X509v3 Basic Constraints: 
                    CA:FALSE
                Netscape Cert Type: 
                    SSL Server
                Netscape Comment: 
                    OpenSSL Generated Certificate
                X509v3 Subject Key Identifier: 
                    0B:BB:C9:A4:6F:8D:93:B8:D3:E1:EA:62:C2:30:FD:46:6B:6A:1F:15
                X509v3 Authority Key Identifier: 
                    keyid:09:18:4F:0E:9D:62:76:25:9D:1D:7F:34:9E:CC:5F:47:C0:DA:41:6B
    
    Certificate is to be certified until Feb 21 02:48:56 2023 GMT (3650 days)
    Sign the certificate? [y/n]:y
    
    
    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    
    一度エラーがでたので、以下の対処を行った。
    $ openssl ca -in ~/pki/server/csr.pem -keyfile ~/pki/demoCA/private/cakey.pem -cert ~/pki/demoCA/cacert.pem -out ~/pki/server/cert.pem
    <省略>
    Certificate is to be certified until Feb 21 02:46:04 2023 GMT (3650 days)
    Sign the certificate? [y/n]:y
    failed to update database
    TXT_DB error number 2
    $ mv ~/pki/demoCA/index.txt ~/pki/demoCA/index.txt.old
    $ touch ~/pki/demoCA/index.txt
    なぜこのエラーがでるのかが、不明。
  9. ApacheのSSL設定
  10. 最低限の設定しかここではしないため、適宜環境・要件に合わせて読み替えてください。
    起動している場合は、Apacheを停止しておく。
    $ sudo apachectl stop
    Apacheに設定する秘密鍵として、パスワード無しの秘密鍵を現在の秘密鍵から作成しておく。
    openssl rsa -in ~/pki/server/server.key -out ~/pki/server/servernopw.key 
    Enter pass phrase for /Users/testuser/pki/server/server.key:
    writing RSA key
    Apacheの設定ファイルを2つ(httpd.conf, httpd-ssl.conf) /etc/apache2/httpd.conf:この行のコメントアウトを外す
    Include /private/etc/apache2/extra/httpd-ssl.conf
    /etc/apache2/extra/httpd-ssl.conf:以下2行でサーバ証明書と秘密鍵を指定する。
    SSLCertificateFile "/Users/testuser/pki/server/cert.pem"
    SSLCertificateKeyFile "/Users/testuser/pki/server/servernopw.key"
    以下にhttpd-ssl.confを載せておく。
    Listen 443
    
    AddType application/x-x509-ca-cert .crt
    AddType application/x-pkcs7-crl    .crl
    
    SSLPassPhraseDialog  builtin
    SSLSessionCache        "shmcb:/private/var/run/ssl_scache(512000)"
    SSLSessionCacheTimeout  300
    SSLMutex  "file:/private/var/run/ssl_mutex"
    
    <VirtualHost _default_:443>
    DocumentRoot "/Library/WebServer/Documents"
    ServerName www.example.com:443
    ServerAdmin you@example.com
    ErrorLog "/private/var/log/apache2/error_log"
    TransferLog "/private/var/log/apache2/access_log"
    
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5
    SSLCertificateFile "/Users/testuser/pki/server/cert.pem"
    SSLCertificateKeyFile "/Users/testuser/pki/server/servernopw.key"
    
    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>
    <Directory "/Library/WebServer/CGI-Executables">
        SSLOptions +StdEnvVars
    </Directory>
    BrowserMatch "MSIE [2-5]" \
             nokeepalive ssl-unclean-shutdown \
             downgrade-1.0 force-response-1.0
    CustomLog "/private/var/log/apache2/ssl_request_log" \
              "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
    </VirtualHost>
    
  11. 接続確認
  12. ブラウザで接続してみる。
    Chromeではこんな感じで警告が出る。「このまま続行」をクリックすると

    サイトが表示される。

おわり

2013年2月13日水曜日

備忘録:Macで特定ウィンドウのスクリーンショットを撮るショートカット

忘れてしまう。。。

「コマンド」 + 「Shift」 + 「4」 + 「Space」
これでマウスカーソルがカメラになるので、キャプチャしたいウィンドウを選択する。

おわり

2013年2月7日木曜日

PythonでHTMLパース:リンクとアンカーテキスト抽出

HTMLParserを利用してHTMLのタグ解析を行う。
特定のサイトにあるAタグを抽出して、リンクURLとアンカーテキストの組を作る。

  • さくらVPS
  • CentOS 6.2
  • Python 2.6.6

  • ソースコード
  • #!/usr/bin/env python
    # -*- encoding: utf-8 -*-
    
    import re
    
    from urllib import urlopen
    from HTMLParser import HTMLParser
    
    class out_link_parser(HTMLParser):
      def __init__(self):
        HTMLParser.__init__(self)
        self.links = {}
        self.linkurl = ''
    
      # aタグのみ処理を行い、href属性の内容をlinkurlに格納
      def handle_starttag(self, tag, attrs):
        if tag == 'a':
          attrs = dict(attrs)
          if 'href' in attrs:
            self.linkurl = attrs['href']
    
      # これは書かなくてもよい
      def handle_endtag(self, tag):
        pass
    
      # linkurlに値が入っている場合のみ、(つまりAタグの場合)
      # urlをキー:アンカーテキストをバリューとしてディクショナリに追加
      def handle_data(self, data):
        if self.linkurl:
          self.links[self.linkurl] = data
          self.linkurl = ''
    
    
    def main():
      target = 'http://www.python.jp/'
      url = urlopen(target)
      html = url.read()
      parser = out_link_parser()
    
      # 日本語があるのでUnicodeに変換
      parser.feed(html.decode('utf-8'))
      parser.close()
    
      for k, v in parser.links.items():
        k_str = k.encode('utf-8')
        # アンカーテキストの先頭/末尾のスペースや改行などを除去
        v_str = re.sub('^[ \n\r\t]+|[ \n\r\t]+$', '', v).encode('utf_8')
     
        # 相対パスやアンカーの場合、ルートのURLを先頭に付与
        if re.match('^/', k_str):
          print "%s: %s" % (re.sub('^/', target, k_str), v_str)
        elif re.match('^#', k_str):
          print "%s: %s" % (re.sub('^#', target + '#', k_str), v_str)
        else:
          print "%s: %s" % (k_str, v_str)
          
    
    if __name__ == '__main__':
      main()
    
    
  • 実行結果
  • http://www.python.jp/pyjug/: PyJUGについて
    http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tar.bz2: ソースコード
    http://confoo.ca/: CanFoo
    http://www.python.jp/psf/donations/: 
    http://www.python.org/download/releases/3.3.0/: Python 3.3.0
    http://www.python.jp/#content-body: 
    http://www.python.org: 公式ウェブサイト
    http://www.python.org/psf/donations/: Pythonに募金を!
    http://www.python.jp/Zope/: 以前のwww.python.jpサイト
    http://pypi.python.org/pypi: Pythonパッケージインデックス
    http://www.python.jp/about/: Pythonとは
    http://www.python.org/download/releases/2.7.3/: Python 2.7.3
    http://code.google.com/p/python-doc-ja/: ドキュメント翻訳プロジェクト
    http://www.python.jp/: 
    http://docs.python.jp/3.3/: ドキュメント (nightly)
    http://python.org/download/releases/3.3.0/: リリース
    http://www.python.jp/news/: ニュース
    http://www.python.org/ftp/python/3.3.0/Python-3.3.0.tar.bz2: ソースコード
    http://www.python.jp/pyjug: Legal Statements
    http://docs.python.jp/2.7/: 日本語ドキュメント
    http://www.python.jp/download/: ダウンロード
    http://www.google.com/calendar/ical/kj670le78ju5alcbt1khect5ks%40group.calendar.google.com/public/basic.ics: Python Calendar Japan
    http://www.python.jp/doc/: ドキュメント
    http://www.timparkin.co.uk/: design by Tim Parkin
    http://www.python.jp/mailman/listinfo/python-ml-jp: Python日本語メーリングリスト
    http://www.python.jp/channews.rdf: RSS
    https://github.com/tokyo-scipy/archive/tree/master/005: Tokyo.SciPy #5
    http://python.org/community/awards/psf-distinguished-awards/: 特別功労賞
    http://www.numfocus.org/johnhunter: John Hunter
    http://www.python.org/psf/license/: オープンソースライセンス
    http://wiki.python.org/moin/Languages: 各国語のPython情報
    http://www.python.org/ftp/python/3.3.0/python-3.3.0.msi: Windows インストーラ
    http://www.python.jp/#left-hand-navigation: 
    http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi: Windows インストーラ
    http://www.python.jp/about: Pythonについてもっと詳しく
    https://github.com/tokyo-scipy/archive: Tokyo.SciPy
    そこそこまともにとれました。

おわり

2013年1月31日木曜日

備忘録:grepで前後複数行も表示

ログを解析する際に検索対象のイベントを判別する文字列とタイムスタンプが連続した別々の行に出力されている場合など

前の行も表示
# grep -B 1 "hogehoge" ./higehige.txt
後の行も表示
# grep -A 1  "hogehoge" ./higehige.txt

おわり