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
2.2k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
スクレイピングの安定運用のために苦労したところ、工夫したところ
Bayside Tech Bridge 2 016.08.21
クローリングのスペシャリストが語る、クローラー運用の裏側!
shida
August 21, 2016
More Decks by shida
See All by shida
受託開発で ビジネスづくりを楽しむ
shida
0
2.6k
受託アジャイルでの契約書作り請求や、外注パートナーへの支払いスキームまで
shida
0
970
DevLOVEリンスタカフェ vol.7
shida
1
230
DevLOVE リンスタカフェ vol2 成長を促すKPIが見つからん
shida
0
150
現場の開発者でもできるユーザー中心かつ 仮説検証型の企画アプローチ
shida
0
3.1k
ユーザーが「それいいね!」と言うまで
shida
0
3.4k
ハイブリッドアプリの 受け入れテスト自動化
shida
0
260
SkypインタビューとKA法による分析
shida
4
1k
CucumberによるHTML5アプリの 受け入れテスト自動化
shida
1
540
Other Decks in Programming
See All in Programming
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
370
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
Cloudflare is Agents
chimame
0
150
Built Our Own Background Agent at LayerX
layerx
PRO
9
5.1k
プロポーザルを書いてもらう
pvcresin
0
290
メールのエイリアス機能を履き違えない
isshinfunada
0
230
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
160
React本体のコードリーディング
high_g_engineer
1
140
VibeCodingからAgenticWorkflowへ
starfish719
0
330
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
480
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
310
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.7k
Featured
See All Featured
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
260
Thoughts on Productivity
jonyablonski
76
5.3k
Abbi's Birthday
coloredviolet
3
9.3k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
240
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
460
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
The untapped power of vector embeddings
frankvandijk
2
1.8k
Why Our Code Smells
bkeepers
PRO
340
58k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Being A Developer After 40
akosma
91
590k
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໊ ࢀՃऀ֤͕ࣗؔΘ͍ͬͯΔαʔϏεͷݱঢ়ใࠂɺ໘͍ͯ͠Δ ՝ͷڞ༗ͱ૬ޓΞυόΠεͱ͔ɺϦϯελܥͷຊͷಡॻձ ͝ڵຯ͋ΕΛ͔͚͍ͯͩ͘͞!