xai1981's blog

http://twitter.com/xai1981

Linux で環境変数を追加する

Adobe AIR SDKlinux にインストールしました。 その際にSDKへのパスを環境変数に$AIR_HOMEとして追加したので、その備忘録です。

設定

一時的な設定

export AIR_HOME=/home/xai/AIR_SDK/

恒久的な設定

.bash_profile を vim で開きます。

vim .bashrc

任意の場所に下記1行を追加し、保存して閉じます。

export AIR_HOME="/home/xai/AIR_SDK"

確認

環境変数全体の確認

[xai ~]$ export
declare -x AIR_HOME="/home/xai/AIR_SDK"
declare -x G_BROKEN_FILENAMES="1"
declare -x HISTCONTROL="ignoreboth"
declare -x HISTSIZE="10000"
declare -x HOME="/home/xai"
declare -x HOSTNAME="localhost.localdomain"
declare -x LANG="ja_JP.UTF-8"
declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="xai"

環境変数を指定して確認

[xai ~]$ echo $AIR_HOME
/home/xai/AIR_SDK

MySQL_データの大文字小文字の区別

あるテーブルで大文字・小文字の区別したいと要望がありました。同じ文字列で大文字・小文字のそれぞれデータのインサートを許容して欲しいそうです。

現状のテーブル構造

mysql> desc sites;
+------------+----------------------+------+-----+-------------------+-------+
| Field      | Type                 | Null | Key | Default           | Extra |
+------------+----------------------+------+-----+-------------------+-------+
| id         | int(10) unsigned     | NO   | PRI | NULL              |       |
| name       | varchar(1000)        | NO   |     | NULL              |       |
| url        | varchar(255)         | NO   | UNI | NULL              |       |
| type       | enum('recruit','ad') | NO   |     | NULL              |       |
| created_at | timestamp            | NO   |     | CURRENT_TIMESTAMP |       |
| updated_at | timestamp            | YES  |     | NULL              |       |
+------------+----------------------+------+-----+-------------------+-------+
6 rows in set (0.00 sec)

jpとJpの違いがるデータのインサート

mysql> INSERT INTO sites (id, name, url, type, created_at)  VALUES (13, 'a01', 'http://www.goo.ne.jp', 'ad', now());
ERROR 1062 (23000): Duplicate entry 'http://www.goo.ne.jp' for key 'sites_url_unique'
mysql> INSERT INTO sites (id, name, url, type, created_at)  VALUES (13, 'a01', 'http://www.goo.ne.jP', 'ad', now());
ERROR 1062 (23000): Duplicate entry 'http://www.goo.ne.jP' for key 'sites_url_unique'

このままではインサートできませんでした。 該当フィールドにBINARY属性を付与します。

mysql> ALTER TABLE sites MODIFY url VARCHAR(255) BINARY;
Query OK, 12 rows affected (0.21 sec)
Records: 12  Duplicates: 0  Warnings: 0

Jpのデータをインサート

mysql> INSERT INTO sites (id, name, url, type, created_at)  VALUES (13, 'a01', 'http://www.goo.ne.jP', 'ad', now());

jp、Jpの違いのあるデータが無事に入りました。

mysql> select * from sites;
+----+--------------------------------+---------------------------------+---------+---------------------+---------------------+
| id | name                           | url                             | type    | created_at          | updated_at          |
+----+--------------------------------+---------------------------------+---------+---------------------+---------------------+
| ...
| 12 | a01                            | http://www.goo.ne.jp            | ad      | 2016-01-31 16:59:13 | NULL                |
| 13 | a01                            | http://www.goo.ne.jP            | ad      | 2016-01-31 17:15:05 | NULL                |
+----+--------------------------------+---------------------------------+---------+---------------------+---------------------+
13 rows in set (0.00 sec)

mysql> select * from sites where url = 'http://www.goo.ne.jp';
+----+------+----------------------+------+---------------------+------------+
| id | name | url                  | type | created_at          | updated_at |
+----+------+----------------------+------+---------------------+------------+
| 12 | a01  | http://www.goo.ne.jp | ad   | 2016-01-31 16:59:13 | NULL       |
+----+------+----------------------+------+---------------------+------------+
1 row in set (0.00 sec)

mysql> select * from sites where url = 'http://www.goo.ne.jP';
+----+------+----------------------+------+---------------------+------------+
| id | name | url                  | type | created_at          | updated_at |
+----+------+----------------------+------+---------------------+------------+
| 13 | a01  | http://www.goo.ne.jP | ad   | 2016-01-31 17:15:05 | NULL       |
+----+------+----------------------+------+---------------------+------------+
1 row in set (0.00 sec)
参考サイト

Proxy Server 経由でリクエストする

概要

WEBスクレイピングの際に Proxy Server と接続して自身(リクエスト元)のIPアドレスを、固定IPから変動するIPに変更する方法。Proxy Server からWEBスクレイピングサーバーへ接続した Port Forwarding した上でWEBスクレイピングサーバーから Proxy Server 経由でスクレイピングするため、アクセス先のアクセスログには Proxy Server のIPが残ります。

手順

  1. Proxy Server を用意する
  2. Proxy Server から WEBスクレイピングするサーバーに ssh の Port Forwarding で接続する
  3. 呼び出し元のプログラムを修正してオプションで Proxy Server と Proxy Port を設定できるようにする

Proxy Server を用意する

[root@my.proxy.server ~]# yum -y install squid
===========================================================
 Package            Arch   Version         Repository Size
===========================================================
Installing:
 squid              x86_64 7:3.1.10-29.el6 base       1.7 M

Transaction Summary
===========================================================
Install       1 Package(s)
Complete!
[root@my.proxy.server ~]# chkconfig --level 35 squid on
[root@my.proxy.server ~]# chkconfig --list squid
squid           0:off   1:off   2:off   3:on    4:off   5:on    6:off
[root@my.proxy.server squid]# diff -u squid.conf.default squid.conf
--- squid.conf.default  2014-10-16 02:52:24.000000000 +0900
+++ squid.conf  2015-01-26 17:36:31.252896670 +0900
@@ -61,6 +61,8 @@
 # Squid normally listens to port 3128
 http_port 3128
 
+forwarded_for off
+
 # We recommend you to use at least the following line.
 hierarchy_stoplist cgi-bin ?
 
@@ -75,3 +77,7 @@
 refresh_pattern ^gopher:       1440    0%      1440
 refresh_pattern -i (/cgi-bin/|¥?) 0    0%      0
 refresh_pattern .              0       20%     4320
+
+header_access X-Forwarded-For deny all
+header_access Via deny all
+header_access Cache-Control deny all

Proxy Server から WEBスクレイピングするサーバーに ssh の Port Forwarding で接続する

[xai1981@my.proxy.com ~]$ ssh -i buff/key.pem -NR 5000:127.0.0.1:3128 ec2-user@my.scraping.com

呼び出し元のプログラムを修正してオプションで Proxy Server と Proxy Port を設定できるようにする

diff --git a/app/lib/ XXXX/Net/Curl.php b/app/lib/XXXX/Net/Curl.php
index 6a13ee9..2d9e767 100644
--- a/app/lib/XXXX/Net/Curl.php
+++ b/app/lib/XXXX/Net/Curl.php
@@ -14,6 +14,8 @@ class Curl
     public static $receivePath = null;
     public static $isRedirectable = false;
     public static $redirectDepth = 1;
+    public static $proxy = '';
+    public static $proxyPort;
 
     // CURLOPT_COOKIEJAR 設定関数
     public static function setCookieJar($path){
@@ -31,6 +33,15 @@ class Curl
     public static function setMaxRedirectCount($count){
         self::$redirectDepth = $count;
     }
+    // CURLOPT_PROXY 設定関数
+    public static function setProxy($url){
+        self::$proxy = $url;
+    }
+    // CURLOPT_PROXYPORT 設定関数
+    public static function setProxyPort($port){
+        self::$proxyPort = $port;
+    }
+
     /**
     * 指定のURLのリソースを取得します。
     *
@@ -51,6 +62,11 @@ class Curl
             curl_setopt($ch, CURLOPT_MAXREDIRS, self::$redirectDepth); 
         }
 
+        if (self::$proxy && is_numeric(self::$proxyPort)) {
+            curl_setopt($ch, CURLOPT_PROXY, self::$proxy);
+            curl_setopt($ch, CURLOPT_PROXYPORT, self::$proxyPort);
+        }
+
 //        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
         curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0');
diff --git a/app/models/Sites/SiteA/SiteA/Crawler.php b/app/models/Sites/SiteA/SiteA/Crawler.php
index a71b952..a05252b 100644
--- a/app/models/Sites/SiteA/SiteA/Crawler.php
+++ b/app/models/Sites/SiteA/SiteA/Crawler.php
@@ -286,6 +286,8 @@ class Crawler extends SitesCrawler implements CrawlerInterface
         try {
             $info = ['schedule_id' => $sId, 'url' => $url];
             Log::info('['.__CLASS__.'.'.__FUNCTION__.'] Try. ', $info);
+            Curl::setProxy('127.0.0.1');
+            Curl::setProxyPort('5000');
             $topHTML = Curl::get($url);
             Log::info('['.__CLASS__.'.'.__FUNCTION__.'] Done.', $info);
         } catch (CurlException $ce) {
参考サイト

アクセスログがロードバランサーにものになっている

仕事でWebサーバー(Zeus)のアクセスログに、大量のログが残っているのに、特定の2,3種類のIPアドレスしか記載されていないことが分かりました。

調べたらところ、特定の2,3種類のIPアドレスロードバランサーのものでした。

修正方法はZeusアドミンから以下の通りです。

  1. Zeus -> Configuration Summary for xai1981.com ->
    Request Logging -> Configuring the Request Log File Format
  2. check "Use a custom format string" %{X-Forwarded-For}i %l %u %t "%r" %s %w "%{Referer}i" "%{User-Agent}i"

用語にもこだわる

プログラマーは名前にこだわる必要があるって言いますが使う用語にもこだわってほしいです。

なぜかと言いますと、表記ゆれは有用なログに対して害悪だからです。

この場合のログは

とおおよそ全ての文字を利用するツールを指します。

プロジェクトを進める上の情報・テキストは「どんな形でもよいので」後から検索出来ればよい、と思っています。 なので上記のいずれかにログが残れば後で調べる時に役に立ちます。 しかし、表記ゆれが起こると、その検索の時にヒットしなくなります。

例えば、ログの中に下記の表記ゆれが起こった場合

通常「食べログ」で検索します。この時、「たべログ」のキーワードを含んだ有用な情報があってもヒットしません。これでは時間と手間をかけて残しているログの意味がなくなってしまいます。

なので用語にもこだわる必要があると考えます。

hoge って分かりにくい

仕事中に会社の仲間に「こういう時どうします?」って質問したりするとき「例えば hoge.com があって、そこで○○ができて ...」と今までは使っていたのですが、 hoge って感覚的に分かりにくい。

それよりも、相手・ueoka.comの方が話がしやすいし、伝わりやすい気がします。

なぜだろう。

hoge って何者(物)でもないから、hoge = 例えばの代名詞とワンクッション、思考が必要だからでは?と思う次第です。

いきなり ueoka.com なら説明不要。ただ hoge よりも面倒なのはその場に合わせて、人だったり物だったり地名だったりと、都度変える必要があるので、そこはコストがかかりますね。

参考サイト

べき等性について

Chef を使ってローカルに開発環境を作りそこで作業するプロジェクトに参加しました。

そこでべき等性という言葉を初めて耳にしました。

べき等性とは

ある操作を何回行っても結果が同じことを意味する数学用語

HTTP メソッドのべき等性

GET, HEAD   べき等、かつ安全である。なんど実行しても結果は同じ。
PUT, DELETE べき等、だが安全ではない
POST        べき等でなく、安全でもない

Chef はべき等性が保たれるように作ってあり、何度実行しても結果・成果物は同じになる。

備考

HTTP の HEAD メソッドとは、レスポンスヘッダーのみ取得するもの。

参考サイト