【android】building gradle project infoが終わらなかった時の対応

久々にandroid studio立ち上げて新規プロジェクトの作成と既存プロジェクトを開こうと思ったらどっちも
「building MyProject gradle project info」が終わらず。。。

よくわからなかったのだが以下を試した

・プロジェクトの作成先を変えてみた
・プロジェクトのディレクトリを移動させてみた
・待ち続けた
・gradle関連のファイルを削除してみた
https://www.youtube.com/watch?v=H1lVGPGxyF4
この動画見ながら以下を削除して開き直してみた。
build、build.gradle、gradle、gradle.properties、gradlew、gradlew.bat、settings.gradle

どれがきっかけかはわからなかったが1度なおったら次回から大丈夫そうだった。
昨日からやってたからけっこう時間かかってしまった。。。以上です

スクレイピングするのに調べたことまとめておく

はじめに

最近スクレイピングするスクリプトを書く機会があったので次回のためにメモしておく。

・主にHTMLでコンテンツが作られているページ。
Javascriptでページを生成しているページ。
この2パターンに対応する必要があった。後者に対応しておけば前者もカバーできるのでいいかな。

で、調べるとPhantomJS、Seleniumあたりがたくさん出てきた。
ブラウザを操作してページを取得してくるようなイメージ。

・PhantomJS
npmでインストールできるのでセットアップが簡単。
PHP PhantomJSというライブラリもあってPHPからも使える。ページへ遷移してHTMLを取得してくるような簡単な処理ならすぐ実装できる。
ただ、サイトにログインとかして何かやるようにちょっと複雑なことをする場合はJavascriptで処理を書いてPHPからそのコマンドを叩くような処理になるのかなと思った。
しかもちょっと難しく感じた。。。

Selenium
自分の理解不足もあるが、セットアップがちょっと面倒だった。
今回やりたかったことはPhantomJSでほぼできたのであまり使わなかった。

・CasperJS
内部的にはPhantomJSを使ってるみたいだけどより簡単に色々できるみたい。
PhantomJS難しくかんじたけどCasperJSの方が簡単にいじれる印象でやりたいこともできた。

実装の方針

取得したHTMLやHTMLの解析結果はDBへ保存する必要があった。
PhantomJSやCasperJSからDBへ登録できるかできないはわからないけど、それはせず。

1. PHPで取得したいURLのリストをファイルへ出力。
2. PantomJSやCasperJSでそのURLリストファイルを読み込んでサイトにアクセスして取得したHTMLをファイルへ出力。
3. PHPで2.の結果ファイルを読み込んでsimple_html_domで解析してDBへ保存

simple_html_domは読み込みサイズの上限があるので解除しておいた方がよさそう。

例)サイズは適当

define('MAX_FILE_SIZE', 600000*10);

結論

PHPとCasperJS使うのが1番簡単そう。やりたいこともできた。以上です。

【CasperJS】ログインする方法メモ

今回やりたかったのはログインが必要なページの取得。
単純にformをsubmitすればいいページとログインボタンをクリックするとjavascriptが動いてごにょごにょやってログイン処理へと遷移するパターンがあるのでそれぞれ実装してみたのでメモしておく。

formをsubmitするパターン

ログイン画面

<form action="/login/do" method="post">
  Email:<input type="text" name="email" id="email" />
  Password:<input type="text" name="password" id="password" />
  <input type="submit" value="Login" />
</form>

スクリプト

var casper = require("casper").create();

casper.start();
casper.open("http://example.com/login/");

casper.then(function() {
  this.fill('form[action="/login/do"', {
    document.querySelector("#email").value = "user@example.com";
    document.querySelector("#password").value = "1234567890";
  }, true);
});

casper.then(function() {
  // ログイン後にやりたい処理を記述
});

casper.run();
onclickするパターン

ログイン画面

<form>
  Email:<input type="text" name="email" id="email" />
  Password:<input type="text" name="password" id="password" />
  <button onclick="onLogin" id="btn-login">Login</button>
</form>
<script>
function onLogin() {
  // ログイン処理・・・
}
</script>

スクリプト

var casper = require("casper").create();

casper.start();
casper.open("http://example.com/login/");

casper.then(function() {
  this.evaluate(function() {
    document.querySelector("#email").value = "user@example.com";
    document.querySelector("#password").value = "1234567890";
    document.querySelector("#btn-login").click()
  }, true);
});

casper.then(function() {
  // ログイン後にやりたい処理を記述
});

casper.run();

以上です

【CasperJS】eachThenとthenOpenで順次スクレイピングしてファイル出力する

今回やりたかったのはURLをリスト化しておいて順次サイトにアクセスしてレスポンスを取得するということ。当初はopenとthenを複数書いていたけどURLの一覧を別ファイル化したかったので今回やりたい経緯となった。ついでに取得したHTMLをファイルに保存する形にした。 

var casper = require('casper').create();
var fs = require("fs");

var urls = [
    {id:1, url:"http://example.com"},
    {id:2, url:"http://example2.com"},
    {id:3, url:"http://example3.com"},
];

casper.start();
casper.eachThen(urls, function(response) {
    var id = response.data.id;
    this.thenOpen(response.data.url, function(response) {
        this.wait(3000, function() {
            fs.write("/path/to/" + id + ".html", casper.getHTML());                                                                                                                                                
        });
    });
});

casper.run();

以上です

macでキャプチャを動画で撮れるLICEcap

よく使うのになぜか名前覚えられないのでメモっておく。
LICEcap

すごいシンプルでとても便利。
macて書いたけど、windowsもあるのか。
動画って書いたけどアニメーションGif。

以上です。

【bootstrap】モーダルが画面からはみ出ないようにサイズ調整する

はじめに

bootstrapのモーダル使っててモーダルサイズが画面からはみ出るのが嫌だったので修正したときのメモ。
今回やったのは以下の2パターン
・テキストベースのモーダル
・画像を大きく表示するための画像ベースのモーダル

テキストベースのモーダル

修正前
f:id:yoppy0066:20170317004307g:plain

修正後
f:id:yoppy0066:20170317004400g:plain

修正後のHTML

<script>
function showModal() {
  $(".modal-content").css({
    "height": $(window).height() - 75,
    "overflow-y": "auto"
  });
  $("#myModal").modal("show");
}
</script>

・・・

<div class="modal fade" id="myModal">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body">                                                                                                                                                                                     
        テキスト                                                                                                                                                                                                   
        テキスト                                                                                                                                                                                                   
        テキスト                                                                                                                                                                                                   
        ・・・                                                                                                                                                                                                     
      </div>                                                                                                                                                                                                       
    </div>                                                                                                                                                                                                         
  </div>                                                                                                                                                                                                           
</div>
画像ベースのモーダル

修正前
f:id:yoppy0066:20170317004435g:plain

修正後
f:id:yoppy0066:20170317004502g:plain

修正後のHTML

<script>
 function showModal() {
     var height = $(window).height() - 150;
     $("#image").css("max-height", height);
     $("#myModal").modal("show");
 }
</script>                                                                                                                                                                                                          

<div class="modal fade" id="myModal">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <img id="image" class="img-responsive" style="margin:0 auto;" src="./sample.png"/>
      </div>
    </div>
  </div>
</div>

無理やりだけどcssでやりかたわからなかったのでjqueryで。
もっと簡単なやり方教えてください。以上です。

【php】Lineアカウントでのログインを実装する

はじめに

FacebookとかTwitterアカウントでのログインは何回かやったことあったけどLineは初めてだった気がしたのでメモしておく。
といっても、ちょっとしたアカウント情報取得するのはやり方どれも同じような感じですけど。

http://milk0824.hatenadiary.jp/entry/2016/04/08/021052
手順はここにわかりやすくまとまっていた。↑にあるように管理画面からLineアプリ作って、クライアントIDとシークレットキーを取得しておく。

実装

define.php

define("LINE_CLIENT_ID", "クライアントID");
define("LINE_CLIENT_SECRET", "シークレットキー");

line_login.php

$callback_url = "https://".$_SERVER["SERVER_NAME"]."/line_callback.php";

$url = sprintf(
    "https://access.line.me/dialog/oauth/weblogin"
    ."?response_type=code"
    ."&client_id=%s"
    ."&redirect_uri=%s"
    ,LINE_CLIENT_ID
    ,$callback_url
);

header("Location: {$url}");
exit;

これでLine側のページが表示されて、IDとパスワードを入力する。

line_callback.php

if (!$_GET["code"]) {
    // エラー                                                                                                                                                                                                      
}

// アクセストークン取得
$url = "https://api.line.me/v1/oauth/accessToken";

$data = array(
    "grant_type" => "authorization_code",
    "client_id" => LINE_CLIENT_ID,
    "client_secret" => LINE_CLIENT_SECRET,
    "code" => $_GET["code"],
    "redirect_uri" => "",
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$response = curl_exec($ch);
curl_close($ch);
$result = (array)json_decode($response, true);

if (empty($result) || isset($result["error"])) {
    // エラー
}

print_r($result);
/*
Array
(
    [mid] => xxxxxxxxxxxxxxxxxxxxxxxxx
    [access_token] => xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    [token_type] => Bearer
    [expires_in] => 2568710
    [refresh_token] => xxxxxxxxxxxxxxxxxxxx
    [scope] =>
)
 */

// プロフィール情報を取得                                                                                                                                                                                          
$url = "https://api.line.me/v2/profile";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.line.me/v2/profile");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $result["access_token"]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);

$result = (array)json_decode($response, true);
if (empty($result) || empty($result["userId"])) {
    // エラー
}

print_r($result);
/*
Array
(
    [userId] => xxxxxxxxxxxxxxxx
    [displayName] => ユーザー名
    [pictureUrl] => ユーザー画像のURL
)
 */

あとは、取得した情報からシステム側でログインの制御とかすれば良さそう。以上です。