Chan Myae San Hlaing

Chan Myae San Hlaing

Programmer & Anime Enthusiast

21 Sep 2016

Ruby နဲ့ instagram user တစ်ယောက်ရဲ့ public image တွေကို mass download ဆွဲခြင်း

Cross-posted from Medium.

မနေ့က instagram ကြည့်နေတုန်း သဘောကျတဲ့ anime account လေးတစ်ခုတွေ့တယ်။ ကြည့်ရင်းကြည့်ရင်းနဲ့ အဲ့ပုံလေးတွေ သိမ်းထားချင်စိတ်ဖြစ်လာတယ်။ သိတဲ့အတိုင်း instagram က သူ့ပေါ်လစီအရ ပုံတွေကို ဒေါင်းခွင့်မပေးဘူး။ browser မှာပါ image ကို save as နဲ့ လုပ်လို့မရအောင်လုပ်ထားတယ်။ ဒါပေမဲ့ ဒီပုံဟာ တစ်နေရာရာမှာတော့ ရှိရမှာပါပဲ။

အဲ့ဒါနဲ့ Chrome devtools ဖွင့်ပြီး network tab ကနေ image url ကို ယူပြီး နောက် tab တစ်ခုနဲ့ ဖွင့်ပြီးမှ save လုပ်လိုက်တယ်။ ဒါပေမဲ့ ကျွန်တော်လိုချင်တဲ့ ပုံတွေကအများကြီး။ တစ်ခုချင်း အဲ့လိုလိုက် save လုပ်နေရရင် အဆင်မပြေဘူး။

ဒါမျိုးအချိန်တွေမှာ ပထမဆုံး ပြေးမြင်တာကတော့ site ကို scrape လုပ်ဖို့ပဲ။ ဒါပေမဲ့ ruby လောကမှာ ကိုယ်လုပ်ချင်တဲ့ ကိစ္စတစ်ခုကို ကိုယ့်လိုလုပ်ချင်တဲ့ ရှေ့က လူတွေက ရေးထားတာတွေ ရှိတာများတယ်။ အဲ့ဒါနဲ့ နည်းနည်း ဂူဂဲခေါက်လိုက်တော့ သုံးလေးခုလောက်ကျလာတယ်။ အဲ့ထဲက insta_scrape ဆိုတဲ့ gem လေးက သုံးတဲ့ပုံစံမဆိုးဘူး။ last commit ကိုကြည့်လိုက်တော့ လွန်ခဲ့တဲ့ သုံးလက ဆိုတော့ စိတ်ချရလောက်တယ်။ အဲ့ဒါနဲ့ သူ့ကို install လုပ်ပြီး စမ်းကြည့်တယ်။ သူ့ API က ရိုးရိုးလေးပဲ။ InstaScraper ဆိုတဲ့ top level class ကနေ static method တွေ ခေါ်သုံးရုံပဲ။

1
InstaScrape.long_scrape_user_posts('foofighters', 30)

အဲ့လိုခေါ်လိုက်ရင် အဆင်သင့်ပဲ Post object လေးတွေ array နဲ့ကျလာတယ် တစ်ခုချင်းဆီမှာ @link နဲ့ @image accessor တွေရှိတယ်။ @image က ကိုယ်လိုချင်တဲ့ image url ပဲ။ အဲ့တော့ mechanize တွေ nokogiri တွေ ကိုယ့်ဟာကိုယ် သုံးနေစရာမလိုတော့ဘူးပေါ့။ ကိုယ်မသုံးရဘူးဆိုပေမဲ့ သူကတော့ သုံးမှာပဲလို့တွေးမိလို့ သူ့ gemspec ကိုသွားကြည့်လိုက်တော့ capybara, phantomjs, poltergeist အတွဲဖြစ်နေတယ်။ နောက်မှ စဥ်းစားမိတယ်။ instagram page က Javascript app ဆိုတော့ normal html scrape လို့ရချင်မှရမှာ။ အဲ့တော့ phantomjs + capybara combo ကပိုကောင်းတယ်လို့တွေးမိတယ်။ poltergeist ကတော့ အဲ့နှစ်ခုကိုချိတ်ပေးတဲ့ driver ပါပဲ။ အဲ့တော့မှ ရေးတဲ့သူကိုပိုကျေးဇူးတင်သွားတယ်။ ကိုယ့်ဟာကိုယ်ဆိုတော်တော်တိုင်ပတ်အုံးမှာ။

image url တွေရပြီဆိုရင်တော့ ကျန်တာက အဲဒီ url တွေကနေ ကိုယ်က ဒေါင်းလုတ် ဆွဲဖို့ပဲ။ အဲ့မှာလုပ်လို့ရတာ နှစ်မျိုး စဥ်းစားမိတယ်။ တစ်မျိုးက အဲ့ url တွေကို ဖိုင်တစ်နဲ့ သိမ်းပြီး wget နဲ့ အဲ့ဖိုင်ကနေ ဒေါင်းလုတ်ဆွဲဖို့။ အဲ့ဒါဆို wget ရဲ့ ဒေါင်းလုတ်အပြိုင်ဆွဲတဲ့ feature ကိုအလကားရမယ်။ နောက်တစ်ခုကတော့ ruby နဲ့ပဲ တစ်ခါထဲ ဒေါင်းလုတ်ဆွဲဖို့ပဲ။ wget နဲ့ကုတ်ရေးရတာ ပိုအလုပ်ရှုပ်မယ်လို့တွေးမိတာနဲ့ ruby ရဲ့ open-uri သုံးပြီး ပဲ ရေးလိုက်တယ်။

1
2
3
4
5
6
7
8
posts = InstaScrape.long_scrape_user_posts('anime.girlclub', 30)
posts.each do |p|
  link = p.image
  filename = link.split("/").last.split("?").first
  File.open("instaimages/#{filename}", 'wb') do |f|
    f.write open(link).read
  end
end

အဲ့မှာ filename တွေကို အလွယ်တကူပဲ image url က အတိုင်းပဲပေးလိုက်တယ်။ အဲ့တော့ url ကို / နဲ့ ခွဲထုတ်လိုက်ပြီး နောက်ဆုံး အပိုင်းက filename ပဲပေါ့။ ခက်တာက သူ့ url မှာ query string တွေပါနေပြန်တယ်။ အဲ့တော့ ထွက်လာတဲ့ နောက်ဆုံးပိုင်းကို တစ်ခါ ? နဲ့ပြန်ခွဲပြီး အရှေ့ကအပိုင်းကို ပြန်ယူတယ်။ အဲ့တော့ မှ သပ်သပ်ရပ်ရပ် နံပါတ်လေးတွေနဲ့ ဖိုင်နာမည်လေးတွေရလာတယ်။ ကျန်တာကတော့ File class ကိုသုံး ပြီး open method က stream ကိုဖတ် ပြီး directory တစ်ခုထဲသွား write လုပ်လိုက်တာပါပဲ။

ခုထိကတော့ ဘာမှ error handling ကောင်းကောင်းလုပ်မထားတဲ့ script တစ်ခုပဲ။ Refactor point တွေရှိပေမဲ့ ကိုယ့်အတွက်တော့ ကိုယ်လိုချင်တဲ့ account ဆီကနေဒေါင်းလို့ရသွားပြီဆိုတော့ ဆက်မလုပ်တော့ဘူး။ ဆက်လုပ်မယ်ဆို account name တို့ သိမ်းမဲ့နေရာတို့ကို dyamic ဖြစ်အောင်လုပ်တာတို့ CLI app အဖြစ်ပြောင်းတာတို့ အင်တာနက်မရတဲ့ကိစ္စတွေ Handle လုပ်တာတို့ အများကြီးကျန်သေးတယ် ပြောရမှာပေါ့။ အဲ့နောက်ဆုံး ၁၀ ရာနှုန်းက နောက် ကိုးဆယ်ရာနှုန်းလောက်အချိန်ကုန်ဦးမှာ ဆိုတော့ ခုတော့ တော်သေးပြီ။

by dreamingblackcat 16-Sep-2016