Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
スクレイピングの安定運用のために苦労したところ、工夫したところ
Search
shida
August 21, 2016
Programming
4
2k
スクレイピングの安定運用のために苦労したところ、工夫したところ
Bayside Tech Bridge 2 016.08.21
クローリングのスペシャリストが語る、クローラー運用の裏側!
shida
August 21, 2016
Tweet
Share
More Decks by shida
See All by shida
受託開発で ビジネスづくりを楽しむ
shida
0
2.3k
受託アジャイルでの契約書作り請求や、外注パートナーへの支払いスキームまで
shida
0
860
DevLOVEリンスタカフェ vol.7
shida
1
120
DevLOVE リンスタカフェ vol2 成長を促すKPIが見つからん
shida
0
66
現場の開発者でもできるユーザー中心かつ 仮説検証型の企画アプローチ
shida
0
2.7k
ユーザーが「それいいね!」と言うまで
shida
0
3.1k
ハイブリッドアプリの 受け入れテスト自動化
shida
0
190
SkypインタビューとKA法による分析
shida
4
910
CucumberによるHTML5アプリの 受け入れテスト自動化
shida
1
380
Other Decks in Programming
See All in Programming
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
3
360
Beyond ORM
77web
6
740
Spatial Rendering for Apple Vision Pro
warrenm
0
110
暇に任せてProxmoxコンソール 作ってみました
karugamo
2
720
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
4
270
rails statsで大解剖 🔍 “B/43流” のRailsの育て方を歴史とともに振り返ります
shoheimitani
2
930
わたしの星のままで一番星になる ~ 出産を機にSIerからEC事業会社に転職した話 ~
kimura_m_29
0
180
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
200
선언형 UI에서의 상태관리
l2hyunwoo
0
160
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
5
910
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
760
Recoilを剥がしている話
kirik
5
6.7k
Featured
See All Featured
The World Runs on Bad Software
bkeepers
PRO
65
11k
A Tale of Four Properties
chriscoyier
157
23k
What's in a price? How to price your products and services
michaelherold
243
12k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
95
17k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
KATA
mclloyd
29
14k
Mobile First: as difficult as doing things right
swwweet
222
9k
A better future with KSS
kneath
238
17k
Bash Introduction
62gerente
608
210k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Transcript
εΫϨΠϐϯάͷ҆ఆӡ༻ͷͨΊʹ ۤ࿑ͨ͠ͱ͜Ζɺͨ͠ͱ͜Ζ #BZTJEF5FDI#SJEHF ΫϩʔϦϯάͷεϖγϟϦετ͕ޠΔɺΫϩʔϥʔӡ༻ͷཪଆʂ ג ϏʔɾΞδϟΠϧ݉ɺδʔΫϥυ ג ࢤా༟थ
גࣜձࣾϏʔɾΞδϟΠϧ(΄΅ϑϦʔϥϯεɺ2012ΑΓ) δʔΫϥυגࣜձࣾ औక ݉ ϑϦʔϥϯε͕ू·ͬͯɺνʔϜ։ൃ डୗ։ൃ(8ׂ)ɺࣗࣾαʔϏε։ൃ(2ׂ) ϦʔϯɾελʔτΞοϓɺΞδϟΠϧ(اըɺ։ൃɺӡ༻) RailsɺSwiftɺ Java for
Android ։ൃҊ݅ɺҰॹʹಇ͖͍ͨϑϦʔϥϯεͷํ େืूத!!! ຊൃදͰɺࣗࣾαʔϏεͷ҆ఆӡ༻ͷͨΊʹۤ ࿑ͨ͠ͱ͜Ζɺͨ͠ͱ͜ΖΛ͝հ
ۤ࿑ͨ͠ͱ͜Ζ
+BWB4DSJQU͕࣮ߦ͞Εͳ͍ͱ ใ͕ͱΕͳ͍ αΠτଆͰ+4ͰಈతʹϖʔδΛߏஙͯ͠ΔͨΊ
1PSUFSHFJTUͰεΫϨΠϐϯά Ruby Capybara Poltergeist PhantomJS ରαΠτ Safariͱಉ͡JSΤϯδϯ͕ಈ͘ Headlessϒϥβ CapybaraͷPhantomJSυϥΠό ड͚ೖΕςετ༻ςεςΟϯά
ϑϨʔϜϫʔΫ
require 'capybara/poltergeist' Capybara.register_driver :poltergeist do |app| Capybara::Poltergeist::Driver.new(app) end Capybara.default_driver =
:poltergeist agent = Capybara.current_session agent.visit('URL') number = agent.find('CSSηϨΫλ').text.to_i 1PSUFSHFJTUͰεΫϨΠϐϯά
Ϣʔβʔೝূ͠ͳ͍ͱ ใ͕ͱΕͳ͍
agent.visit login_url agent.find('input[name="email"]').set(email) agent.find('input[name="pasword"]').set(password) agent.find('#login-btn').trigger('click') agent.visit account_url ೝূ͔ͯ͠Βର63-ʹΞΫηε
ຖճೝূ͕͠͠ॏ͍
def save_cookie(agent, user) cookies_str = Base64.encode64( Marshal.dump( agent.driver.browser.cookies)) user.update_attributes(cookies: cookies_str)
end def load_cookie(agent, user) cookies = Marshal.load( Base64.decode64(user.cookies)) cookies.values.each do |cookie| cookie_hash = JSON.parse(cookie.to_json) ["attributes"] agent.driver.browser.set_cookie(cookie_hash) end end $PPLJFʹΑΔೝূ
DPPLJFͷ༗ޮظݶ͕ Ε͍ͯΔ͕࣌͋Δ
DPPLJF͕Ε͍ͯͨΒSFUSZ scrape(need_login: true) do agent.visit('URL') agent.find('CSSηϨΫλ').text.to_i end # εΫϨΠϐϯά͢ΔՕॴ༻ڞ௨ϝιου def
scrape need_login: false begin yield rescue => e if need_login && ! login? login retry end end end
ԿೝূτϥΠ͍ͯ͠Δͱ ϩοΫ͞ΕΔ
agent.driver.headers = { "User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS
X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36 #{Time.now.to_f.to_s}" } 6TFS"HFOUΛͪΐ͍ͪΐ͍ม͑Δ
ΞΫηε͠·͍ͬͯ͘Δͱ ϒϩοΫ͞ΕΔ
Proxy1 (AWS) ΞϓϦ αʔό ର αΠτ ΞΫηεݩΛͪΐ͍ͪΐ͍ม͑Δ Proxy1 (AWS) ᶃϒϩοΫ
ᶄ৽͘͠ىಈ
)5.-ߏ͕มΘΓ εΫϨΠϐϯάࣦഊ ͱ͔
"#ςετͯ͠ΔΒ͘͠ ΞΧϯτຖͰ)5.-͕ҧ͏
Ͱ͖Δ͚ͩදࣔܥ͔ΒεΫϨΠϐϯά͠ͳ͍ ॓ധਓ 9໊ ใදࣔը໘ ॓ധਓ 9 ϑΥʔϜը໘ ໊ ϑΥʔϜ෦ͷϚʔΫΞοϓαʔόʔαΠυͷϓϩάϥϜͱ࿈ ܞ͍ͯ͠ΔͷͰมߋ͕ൃੜ͠ʹ͍͘
<div data-bootstrap-data="{a: 'b', ... }" /> JavaScriptଆʹJSONจࣈྻͰใΛ͍ͯ͠Δͱ͜Ζͱ͔ม ߋ͕ൃੜ͠ʹ͍͘ http://example.com/users/12345678 URLมߋ͕ൃੜ͠ʹ͍͘
αΠτ͕ॏͯ͘ ͨ·ʹλΠϜΞτͨ͠Γ མͪͨΓ͢Δ
ϩʔυͪɺදࣔ࣌ؒΛԆ͢ Capybara.register_driver :poltergeist do |app| Capybara::Poltergeist::Driver.new(app, :timeout => 60) end
Capybara.default_driver = :poltergeist Capybara.default_max_wait_time = 30 agent = Capybara.current_session # ࠷େ60ඵͬͯ͘ΕΔ agent.visit('URL') # ࠷େ30ඵJavaScriptͷඇಉظߋ৽ͳͲͷऴྃΛͬͯ͘ΕΔ number = agent.find('CSSηϨΫλ').text.to_i
εΫϨΠϐϯάࣦഊ ඞ͓͖ͣΔ )5.-ߏͷมԽ ӬଓతΤϥʔ ଓΤϥʔ Ұ࣌తͳΤϥʔ
ϢχοτςετΛఆظతʹࣗಈ࣮ߦ project='ϦϙδτϦ໊' branch='master' api_token='APIτʔΫϯ' url=https://circleci.com/api/v1/project/${project}/ tree/${branch}?circle-token=${api_token} curl \ --header "Accept:
application/json" \ --header "Content-Type: application/json" \ --request POST ${url} CircleCIͷϏϧυΛAPIΛͬͯcron͔Βఆظ࣮ߦ ͚ͨ͜ΒCircleCI͕Slackʹ௨ͯ͘͠ΕΔ
4JEFLJRͷར༻ # 1000ళฮ͋ͬͨͱͯ͠ shops.each do |shop| # ͠10ళฮͰΤϥʔͰॲཧ͕ͱ·ͬͯ͠·ͬͨΒ # 990ళฮ͕ະॲཧʹͳͬͯ͠·͏
shop.scrape end Ұ࣌తͳଓΤϥʔ ಛఆͷshopʹ͚ͩൃੜ͢Δఆ֎ͷΤϥʔ
4JEFLJRͷར༻ ಛఆͷshopͰམͪͯɺଞͷshopͷॲཧݺΕΔ
4JEFLJRͷͦͷଞར ಛఆͷshopͰམͪͯɺଞͷshopͷॲཧݺΕΔ εϨουىಈىಈ·Ͱͷͪ࣌ؒΛ੍ޚ͠ɺରαΠτʹ ෛՙΛ͔͚ա͗ͳ͍ མͪͨ࣌ʹslackʹ௨ͯ͘͠ΕΔ མͪͨεϨουΛϦτϥΠͯ͘͠ΕΔ ࠷େϦτϥΠճࢦఆՄೳ దʹϦτϥΠִؒΛ͛ͳ͕Β(15, 16, 31,
96, 271, ... ) ϦτϥΠ࣌ͷslack௨ΛؒҾ͍ͨΓͰ͖Δ ฒྻॲཧαʔόʔͷεέʔϧΞτͰύϑΥʔϚϯεΞοϓ
·ͱΊ વͰ͖Δ͚ͩεΫϨΠϐϯάΤϥʔɺଓΤϥʔΛճආ͢ ΔΑ͏ʹྗ ͦΕͰશʹճආͰ͖ͳ͍ εΫϨΠϐϯάΤϥʔΛ͔ʹݕ͢ΔΈΛ༻ҙ Ұ࣌తʹଓΤϥʔෆଌͷΤϥʔ͕ൃੜͨ͠߹ɺ֘ॲ ཧҟৗऴྃͭͭ͠ɺ༧ఆ͍ͯͨ͠όονॲཧܧଓ Ұ࣌తΤϥʔ(ଓΤϥʔɺcookie༗ޮظݶΕ)ϦτϥΠ εΫϨΠϐϯάͷӡ༻ʹ͔͔Δ࣌ؒίετΛ͋Β͔͡ΊϓϩδΣ Ϋτॳظʹؔऀʹཧղͯ͠Β͏ඞཁ͕͋Δ(߹ʹΑͬͯ
Ϣʔβʔʹ)
࠷ޙʹએϦϯελΧϑΣ ΦϯϥΠϯ ϦʔϯɾελʔτΞοϓ(ͦͷଞྨࣅ)ख๏Λϕʔεʹͨ͠αʔ Ϗεاըɾ։ൃͷ࣮ફऀͷͨΊͷίϛϡχςΟ աڈ8ճͷΦϑϥΠϯษڧձΛ࣮ࢪ ΠϯλϏϡʔͷํɺϢʔβʔςετͷํɺMVPͷܾΊ ํɺࣾελʔτΞοϓͷۤ࿑ɺͳͲͳͲ ͦΕͷΦϯϥΠϯ൛ ຖिਫ༵ 21:30
GoogleϋϯάΞτʹͯ ݱࡏϝϯόʔ 4໊ ࢀՃऀ֤͕ࣗؔΘ͍ͬͯΔαʔϏεͷݱঢ়ใࠂɺ໘͍ͯ͠Δ ՝ͷڞ༗ͱ૬ޓΞυόΠεͱ͔ɺϦϯελܥͷຊͷಡॻձ ͝ڵຯ͋ΕΛ͔͚͍ͯͩ͘͞!