実践スクレイピング

33,838 views

Published on

  • Be the first to comment

実践スクレイピング

  1. 1. 実践スクレイピング 不条理な現実との折り合いの付け方 ふるかわだいすけ/mogya.com
  2. 2. ふるかわだいすけ フリーランスWEBエンジニア http://mogya.com/ http://mogya com/ Twitter: @mogya 自己紹介
  3. 3. ふるかわだいすけ フリーランスWEBエンジニア http://maidmail.jp/ 自己紹介
  4. 4. http://oasis.mogya.com/ モバイラーズオアシス
  5. 5. http://oasis.mogya.com/ 携帯/スマートフォン対応
  6. 6. 実践スクレイピング 今日のテーマ
  7. 7. はじめてのスクレイピング ・Hpricot X th ・Xpath ・店名を取ってみる 実践スクレイピング ・1ページに全部入っている場合 id ・id=xxx方式 方式 ・一覧ページ→詳細ページ ・「次へ」対応 「次へ 対応 現実のスクレイピング まとめ 目次
  8. 8. photo by Big Ben(Gaijin Bikers) はじめてのスクレイピング
  9. 9. 例えばこんなページ http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01570
  10. 10. こうなっているところから http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01570
  11. 11. require 'rubygems' require 'hpricot' require 'open-uri' url = 'http://www mcdonalds map php?strcode=01570' http://www.mcdonalds…map.php?strcode=01570 page = Hpricot( open(url).read );nil page sea c ( S op a e 3 ) page.search(".Shopname h3").inner_te t e text 店名を取ってみる
  12. 12. Hpricot • HTMLパーサー • xpathでHTMLから切り出しができる Hpricot
  13. 13. page = Hpricot( open(url).read ) page.search(".Shopname h3").inner_text “body div h1” “div#Content1 “di #C t t1 h1” “.content title” .content_title (page/".content_title")[0].inner_text XPath(XML Path Language)
  14. 14. /html/body/table/tbody/tr[3]/td/ 勝手にtbodyとか補足する点に注意 Firebugを使うとラクチン http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01570
  15. 15. require 'rubygems' require 'hpricot' require 'open-uri' open-uri url = 'http://www.mcdonalds・・・map.php?strcode=01570' page = Hp icot( open( l) ead ) nil Hpricot( open(url).read );nil page.search(".Shopname h3").inner_text 店名を取ってみる
  16. 16. page = Hpricot( open(url).read ) ↓ page = Hpricot( open(url).read );nil irbの場合
  17. 17. userAgent = "mogya scraper under construction. ”+ ”you can contact me at mogya+scraper@mogya.com" page = Hpricot( open(_url, "User-Agent" => userAgent ).read ) 連絡がつくようにしておく
  18. 18. Require “kconv” userAgent = "mogya scraper under construction. ”+ ”you can contact me at mogya+scraper@mogya.com" page = Hpricot( open(url, "User-Agent" => userAgent ).read.toutf8 ) ※読みにくいので、以降のサンプルでは省略しました 文字コードの問題
  19. 19. • Aj でデ タを動的ロ ド Ajaxでデータを動的ロード →スクレイピングだとデータが取れない • JSの読み出し元を見ればいいんじゃね? •ブラウザでアクセスしてみる →403 forbidden •以降、サイトまるごと403 forbiddenになった →「本気だ!」 ※このデザインになる前の話 余談:防衛反応 http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01570
  20. 20. photo by Big Ben(Gaijin Bikers) 実践スクレイピング
  21. 21. http://www.burgerkingjapan.co.jp/locations/ 1ページに全部入っている場合 http://www.first-kitchen.co.jp/shop/
  22. 22. バーガーキング http://www.burgerkingjapan.co.jp/locations/
  23. 23. require 'rubygems' i ' b ' require 'hpricot' require 'open-uri' url = 'htt // l 'http://www.burgerkingjapan.co.jp/locations/' b ki j j /l ti /' page = Hpricot( open(url).read );nil page.search( li dl ).each{|part| page search(".li dl") each{|part| p part.search("dd h4 a").inner_text } バーガーキング http://www.burgerkingjapan.co.jp/locations/
  24. 24. id=xxxx方式 http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01578
  25. 25. require 'rubygems' require 'hp icot' eq i e 'hpricot' require 'open-uriʻ url_template url template = 'http://www.mcdonalds ・・・ strcode=%05i' 0.upto(10000){|i| url = sprintf(url_template,i) page = Hpricot( open(url).read );nil p page search(" Shopname h3") inner text page.search(".Shopname h3").inner_text sleep 3 } id=xxxx方式 http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01578
  26. 26. 新店舗情報を見ると idのmax値がわかることが多い 新店舗情報を見ると、idのmax値がわかることが多い id=xxxx方式 http://www.mcdonalds.co.jp/shop/map/map.php?strcode=01578
  27. 27. 飛び飛びで見て最低値を推測 0.step(10000,100){|i| url = sprintf(url template i) sprintf(url_template,i) page = Hpricot( open(url).read );nil p "#{url}:"+page.search(".Shopname h3").inner_text sleep 3 } id=xxxx方式
  28. 28. 飛び飛びで見て最低値を推測 0.step(10000,100){|i| url = sprintf(url template i) sprintf(url_template,i) page = Hpricot( open(url).read );nil p "#{url}:"+page.search(".Shopname h3").inner_text sleep 3 } id=xxxx方式
  29. 29. 一覧ページ→詳細ページ http://www.bagus-99.com/company/shop.html
  30. 30. 一覧ページ→詳細ページ http://www.bagus-99.com/company/shop.html
  31. 31. require 'rubygems' q yg require 'hpricot' require 'open-uri' archive_url = 'http://www.bagus-99.com/netcafe/store/' archive_page = Hpricot( open(archive_url).read );nil archive_page.search("td.darker2/a").each{|url_part| url = archive_url + url_part['href'] page = Hpricot( open(url).read ) il i ( ( l) d );nil 以下略 sleep 1 } 一覧ページ→詳細ページ http://www.bagus-99.com/company/shop.html
  32. 32. 「次へ」対応 http://www.mapion.co.jp・・・search=mapAreabtn
  33. 33. 「次ページへ」がある時 「次ページへ」がない時 次ペ ジへ」がない時 XPATHではムリ! 「次へ」対応 http://www.mapion.co.jp・・・search=mapAreabtn
  34. 34. def parse(url) p ( ) page = Hpricot( open(url).read ) page.search(".address").each{|part| p part.search("h2").inner_text } next_url = (page.inner_html.scan( /HREF="(.*)"><strong>次ページへ/ / "( *)" 次 ジ / )[0][0]) rescue nil if (next_url) parse("http://www.mapion.co.jp"+next_url) ("htt // i j "+ t l) end end url = “http://www.mapion.co.jp/c/f?・・・admi3=13101・・・" parse(url) 「次へ」対応 http://www.mapion.co.jp・・・search=mapAreabtn
  35. 35. photo by Big Ben(Gaijin Bikers) 現実のスクレイピング
  36. 36. 現実1:データ大杉 http://www.doutor.co.jp/shopsearch/index.html#
  37. 37. → 47回回せばOK? 現実1:データ大杉 http://www.mapion.co.jp・・・BT=all
  38. 38. 現実1:データ大杉 http://www.mapion.co.jp・・・BT=all
  39. 39. URLをじーっと眺めると。 1.東京都の各エリア http://www.mapion.co.jp/c/f?・・・&admi2code=13&BT=all&admi3=13101&search.x=15&search.y=8 http://www mapion co jp/c/f? &admi2code 13&BT all&admi3 13101&search x 15&search y 8 http://www.mapion.co.jp/c/f?・・・&admi2code=13&BT=all&admi3=13102&search.x=25&search.y=5 : 2.それ以外の県 . れ以外 県 http://www.mapion.co.jp/c/f?・・・&admi2code=40&mx=100&vp=10&BT=all http://www.mapion.co.jp/c/f?・・・&admi2code=41&mx=100&vp=10&BT=all →2パターンに分けてスクレイピング に分 グ 対処1:地道に対応
  40. 40. Flashの検索フォーム 検索 現実2:強敵Flash http://sp.chizumaru.com/dbh/lotteria/top.aspx?account=lotteria
  41. 41. Flashの検索フォーム 検索 現実2:強敵Flash http://sp.chizumaru.com/dbh/lotteria/top.aspx?account=lotteria
  42. 42. 現実2:強敵Flash http://sp.chizumaru.com/・・・&arg=
  43. 43. http://sp.chizumaru.com/dbh/lotteria/detailmap.aspx?accou nt=lotteria&accmd=0&arg=&c1=&c2=&c3=&c4=&c5=&c6= &c7 &c8 &c9 &c10 &c11 &c12 &c13 &c14 &c15 &c16 &c7=&c8=&c9=&c10=&c11=&c12=&c13=&c14=&c15=&c16 =&c17=&c18=&c19=&c20=&c21=&c22=&c23=&c24=&c25 =&c26=&c27=&c28=&c29=&c30=&mode=11&key=&pg=1& ad &b d adr=&bid=113106 3 06 6桁とかw 現実2:強敵Flash http://sp.chizumaru.com/dbh/lotteria/detailmap.aspx・・・bid=113106
  44. 44. http://sp.chizumaru.com/dbh/lotteria/detailmap.aspx?accoun t=lotteria&bid=113106 現実2:強敵Flash
  45. 45. 鉄壁! ・ページリスト:取れない(Flashだから) ・一覧ページのURL:取れない (座標指定なのでパターンを読めない) ・個別ページ:id多すぎ 現実2:強敵Flash
  46. 46. 対応:偶然発見!
  47. 47. http://www.pronto.co.jp/solare/ 注)BGMが鳴ります 現実3:強敵Flash2
  48. 48. 数が少ないので手作業で片付けましたw 対策3:あきらめる
  49. 49. 余談:渡る世間に鬼はなし http://www.manboo.co.jp/
  50. 50. 余談:渡る世間に鬼はなし http://www.manboo.co.jp/
  51. 51. 現実4:Tableレイアウト
  52. 52. 現実4:Tableレイアウト
  53. 53. XPATHがこんなふうになる page.search("/html/body/table/tr[3]/td/table/tr/td/table/tr/td[2]/tab le/tr[3]/td/table/tr[3]/td/table/tr/td/table/tr/td/a ) le/tr[3]/td/table/tr[3]/td/table/tr/td/table/tr/td/a”) ひどい場合、そもそもXPATHで表現できないことも 対応 ・1カ所くらいclassがついていることもある ・FireBugで何とかなる間はなんとかする ・どうにもならない時は、正規表現で取得 現実4:Tableレイアウト
  54. 54. 現実5:InvalidなHTML
  55. 55. 現実5:InvalidなHTML
  56. 56. 問題:xpathで読めなくなってしまう 対策:読み込んだタイミングで直してしまう page = Hpricot( H i t( open(url).read.gsub( "</script>¥n<body>","</script>¥n“ </script>¥n<body> </script>¥n ) );nil 対策:アドホックに直す
  57. 57. th便利 ・xpath便利 ・スクレイピングは個別対応の嵐 スクレイピングは個別対応の嵐 ・validなHTMLを書きましょう まとめ
  58. 58. おしまい
  59. 59. おしまいだってば!
  60. 60. もうないよ!
  61. 61. 時間があまった?
  62. 62. じゃあしょうがない
  63. 63. About モバイラーズオアシス モバイラ ズオアシス おまけ
  64. 64. 「情報はどこから?」 情報はどこから?」 よくいただく質問
  65. 65. こたえ
  66. 66. ブログ
  67. 67. ・・・正直ムリ(><)
  68. 68. twitter
  69. 69. • t itt で「電源 OR コンセント -切」をwatch twitterで「電源 ンセント 切 を t h • 99%はどうでもいい話だけど、 高速で読み飛ばせるので対応可能 • 敵はbotと診断メーカー twitter
  70. 70. • t itt で「電源 OR コンセント -切」をwatch twitterで「電源 ンセント 切 を t h • 99%はどうでもいい話だけど、 高速で読み飛ばせるので対応可能 • 効能 •電源情報収集 •宣伝 •SEO 顧客の声を聞く •顧客の声を聞く twitter
  71. 71. on ExpressionEngine バックエンド
  72. 72. 管理をCMSに投げる
  73. 73. システム構成 • Ce tOS5 3 CentOS5.3 • Apache2.2.3 • E pressionEngine v.1.6.4 ExpressionEngine 1 6 4 • MySQL 5.0 • jQuery 1.3.2 132 • GoogleMapsAPI システム構成
  74. 74. システム構成 ee_Net_UserAgent_Mobile ee Net UserAgent Mobile 通常のリクエスト 通常 リク ト Expression spot_search 結果ページの Engine リクエスト DB 検索クエリ Search.php システム構成

×