【9週目】未経験からTECH::EXPERTでプログラミングやってみた

f:id:b1840943:20180701230217p:plain

 

今週は僕の開発最終週だったので、仕上げを中心にやりました。グループで個々が機能を開発して、それをマージして一つのアプリとしてちゃんと動くのを見るとやっぱテンション上がりますね!

 

スタイリング

マージするとやっぱりスタイリングが崩れるところがどうしても出てくると思うんですね。Bootstrapを入れてたブランチと入れてないブランチをマージしたりするとBootstrapが悪さしたりとか。cssファイルをimportする順番のせいで上書きされちゃったりとか。そこの調整をしました。

 

主にサイドバーなんですが、一つは現在いるページへのボタン背景を変えました。

 

f:id:b1840943:20180701225838p:plain

 

jQueryで今ユーザーが見ているページを取得して、それとリンク先が合致すればクラスを追加してます。こんな感じですね。

 

$(function(){
  $('.gnavi_item a').each(function(){
    var $href = $(this).attr('href');
    if(location.href.match($href)) {
      $(this).addClass('is_current');
    } else {
      $(this).removeClass('is_current');
    }
  });
});

 

その他もろもろきれいにしました。かなり細かい部分ばっかりなんで省略します。

 

スクレイピング

実際に誰かにアプリを見せるときにユーザーが全然いなかったらさみしいですよね。なのでダミーユーザーを30人前後準備することになりました。

 

手動で一人一人フォームから登録していくこともできますが、エンジニアを称する人間がそんな人海戦術を是とするなんて言語道断だという結論になったので、スクレイピングで女性の画像を引っ張ってきてseedでデータベースに入れていくことにしました。

 

 

いや、ちゃんとやりましたよ…?

 

だいぶ前にカリキュラムで書いたコードを改変して使いました。今回はメイン画像を一枚、サブ画像を二枚取得します。取得先は女優さんがたくさん一覧で出ているページです。女優一覧ページの女優名にリンクが貼ってあり、そのリンク先にその女優の画像がぶわっと並んでる感じです。

 

require "mechanize"

def image_page_urls
  agent = Mechanize.new
  links = []

  current_page = agent.get("取りたい画像があるURL")
  elements = current_page.search('.image_list .imageBox a')

  # get_imageで取得できない画像もあるので、多めにfirst(n)に指定する
  elements.first(40).each do |ele|
    links << ele.get_attribute('href')
  end

  links.each_with_index do |link, i|
    get_image('取りたい画像があるhost' + link, i)
  end
end

def get_image(link, i)
  agent = Mechanize.new
  page = agent.get(link)

  begin
    main_image = page.search('#1_img')
    agent.get(main_image.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}.jpg"  
  rescue
    return # メイン画像が取れなかったらこの女優は諦める
  end
  
  begin
    sub_image1 = page.search("#{i+2}_img")
    agent.get(sub_image1.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub1.jpg"
  rescue
    begin
      sub_image1 = page.search("#{i+3}_img")
      agent.get(sub_image1.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub1.jpg"
    rescue
      begin
        sub_image1 = page.search("#{i+4}_img")
        agent.get(sub_image1.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub1.jpg"
      rescue
        puts "取得できませんでした"
      end
    end
  end

  begin
    sub_image2 = page.search("#p1_#{i+5}_img")
    agent.get(sub_image2.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub2.jpg"
  rescue
    begin
      sub_image2 = page.search("#p1_#{i+6}_img")
      agent.get(sub_image2.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub2.jpg"
    rescue
      begin
        sub_image2 = page.search("#p1_#{i+7}_img")
        agent.get(sub_image2.first.attributes["src"]).save "/Users/kosaburokaneko/projects/techexpert/pairs_clone/app/assets/images/avatar/user#{i+1}_sub2.jpg"
      rescue
        puts "取得できませんでした"
      end
    end
  end
end

image_page_urls

 

なんでこんなbeginとrescueがこんなことになってるかというと、画像があったりなかったりするページだったので画像を取得できない可能性があったんですね。なのでもしメイン画像が取得できなかったらその女優は諦めて次の女優に移るというようにしてます。サブ画像については取得できなかったら次の画像を取りに行って、それを二回頑張って無理だったら諦めるという風にしてます。

 

あと取得画像の制限ももっと上手な方法があると思うんだよなあ…スクレイピングはほぼやったことがないんだけど、やっぱり取得成功してデータがもりもり増えるの見てるとなんか興奮するからもっと勉強したい。

 

で、取得できた画像はそれぞれ

  • メイン画像: user_1.jpg
  • サブ画像1: user_1_sub1
  • サブ画像2: user_1_sub2
  • メイン画像: user_2.jpg
  • サブ画像1: user_2_sub1
  • サブ画像2: user_2_sub2

という風にユーザー別に保存するようにしました。最近each_with_indexが大活躍してます。

 

保存した画像はcarrier_waveを使って保存する必要があって、それをユーザーと紐づかせなければいけません。なのでseed.rbには以下のように書きました。

 

32.times do
  password = Faker::Internet.password(8)

  User.create(
    name: Faker::Japanese::Name.last_name,
    gender: 2,
    email: Faker::Internet.free_email,
    password: password,
    birthday: Faker::Time.between(50.years.ago, 20.years.ago, :all).to_s[0, 10],
    nationality_id: 48,
    narrow_address_id: rand(1..48),
  )
end

32.times do |i|
  CapturedImage.create(
    content: File.open(Rails.root + "app/assets/images/avatar/user#{i+1}.jpg"),
    status: 0,
    user_id: "#{i+1}".to_i,
  )
  CapturedImage.create(
    content: File.open(Rails.root + "app/assets/images/avatar/user#{i+1}_sub1.jpg"),
    status: 1,
    user_id: "#{i+1}".to_i,
  )
  CapturedImage.create(
    content: File.open(Rails.root + "app/assets/images/avatar/user#{i+1}_sub2.jpg"),
    status: 1,
    user_id: "#{i+1}".to_i,
  )
end

 

Fakerで日本語使う方法がいまいちわからなかったので、ruby-faker-japaneseというgemで対応しました。それでユーザー登録に必要な情報をダミーで入れて32人作成してます。

 

下の段がcarrier_waveの部分ですが、contentの部分は先ほど保存した画像を開くように設定してます。ちなみにstatusが0はメイン画像で、1はサブ画像です。これでユーザーとユーザー画像がちゃんとひも付けされるようになりました。この二つのファイルがあれば何百人だろうが自動でできます。

 

終わり

というわけで、僕の役目は終わりました。あとはグループでこのアプリを発表するだけです。とうとうここまで来てしまいました。

 

グループでスクラム開発をできたこともそうですが、既存のサービスのクローンをつくるのはすごい勉強になりました。どういう技術が実際に使われてるのかとか、CSSの細かなテクニックとか、自分で開発するプロセスじゃなかなかたどり着けない、既存サービスを研究することで初めてわかったことがいくつもありました。

 

スクールのカリキュラムとして既存サービスをコピーするのか、オリジナルサービスをつくるのか、どちらがいいのかは難しいところだと思います。正直自分でやる前は「既存サービスのコピーなんて大した勉強になんないでしょ」と思ってましたが、全然そんなことありませんでした。むしろ今では一からサービスを作るよりも勉強になる部分がたくさんあると思うようになりました。

 

あまり経験がない中でオリジナルサービスを作ろうとするとどうしても技術的に背伸びしにくい気がするんですよね。技術的にがんばるというよりも、サービス全体として一つ作り上げる方に意識が向くというか。なので結果的に本当の自分の技術的ポテンシャルより一段落ちる気がしてます。

 

でも自分の個性とか出す場所としてはオリジナルサービスってすごくいいと思います。デザインにこだわってもいいし、アイディアで勝負もできるし。もちろん技術的にすごいサービスってとこを狙ってもいいですし。

 

でもいろいろ考えた上で、多くの人には既存サービスをコピーする方が転職には役立つんじゃないかと思います。転職目的では。大概WEBサービスのアイディアなんてすでに作られてるので、どうせそういうインパクト勝負ができないんだったらコピーした方が見た目もきれいだしいろんな話もできると思うんだよなあ。