概要
いつか横断検索みたいなものを作りたいのでその前段階的に飲食店の情報取得をしてみる
言語
- Ruby
使うライブラリ
- nokogiri
nokogiriは取得したHTMLをパース(解析)するのに使います。
情報の取得部分はrubyの標準ライブラリのnet/httpをつかます。
本題
スクレイピングの基本は
- 通信内容の理解
- コードに落とし込む
以上である。
1. 通信内容の理解
ぐるなびのページに移動してデベロッパーツールで通信を確認します。
今回はこのリクエストからrubyのコードを取得します。
通信を右クリックして「Copy as cURL」を選択します
その後
https://jhawthorn.github.io/curl-to-ruby/
こちらのページにアクセスして貼り付けると
下の部分にRubyのコードが取得できるのでそれを使います。
2. コードに落とし込む
ライブラリインストール
これをコードに落とし込むんですけど、まず最初に述べたライブラリを使うのでGemfileを作ってこんな感じに書きます。
source 'https://rubygems.org'
gem 'nokogiri'
必要なのはこの2つなのでこれを記載した上で
bundle install --path=.bundle
を実行
なんで--path
オプションをつけているかというとこれをつけないとグローバルに入っちゃってプロジェクトレベルの管理がしにくくなるからですね。
コーディング
これで準備ができたので実際のrubyのコードを書いてみましょう。
ファイル名は何でもいいのですが、crawler.rbとかにしましょうか
require 'uri'
require 'nokogiri'
require 'kconv'
require 'net/http'
require 'uri'
area = URI.encode_www_form_component('横浜')
keyword = URI.encode_www_form_component('たこ焼き')
uri = URI.parse("https://r.gnavi.co.jp/area/jp/rs/?fwp=#{area}&date=&fw=#{keyword}")
request = Net::HTTP::Get.new(uri)
request["Authority"] = "r.gnavi.co.jp"
request["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
request["Accept-Language"] = "ja"
request["Cache-Control"] = "max-age=0"
request["Cookie"] = "_td_global=2c7201bb-65d9-447f-8871-5c8aef70e6f0; _ra=1664900409701|e581f62a-e16f-4c02-97dc-b7ab203924e6; GU=e9f8c8528b624ea8cb1a55aadf705bd0; gt=GT139faa476002ac1e4ae520fpfeoIzpEqTDWQ1Rwc2xzV; ds=622474de466075942cc80e90a606c14bc6c474c7b09327535e48d587017aa4c0; gUser=03139faa476003ac1e4ae520L_I2dpFCb1q8eMMN-5-LmU; gcom=%7B%22login_type%22%3A1%2C%22guser_type%22%3A0%7D; _gid=GA1.3.151665219.1669743686; __gads=ID=61224817bcdcc5e2:T=1669743685:S=ALNI_MYQItLoO9f62eC3t0aHssBPge-pXQ; __gpi=UID=00000b86e8eecc21:T=1669743685:RT=1669743685:S=ALNI_MZ324J7fmISVdaU-A1IuoqdhZBTIQ; _ts_yjad=1669743686386; _fbp=fb.2.1669743686439.1159228644; _gcl_au=1.1.1560200380.1669743686; __pp_uid=INDH6tuKhtkFKURk66AXkbVTWOoJTybu; __lt__cid=c5331b8a-2798-4df1-9a8c-afb6b1af0c3c; __lt__sid=ab800c27-56441560; _dctagfq=1318:1670338799.0.0|1319:1670338799.0.0|1320:1670338799.0.0|1321:1670338799.0.0|1536:1670338799.0.0|1841:1670338799.0.0|1856:1670338799.0.0|1871:1670338799.0.0|1886:1670338799.0.0|1901:1670338799.0.0|1916:1670338799.0.0|1931:1670338799.0.0; ___o2u_o2id=0793b44a-526d-4f6f-bbfb-c923eb5be40f; rtosrch=gg7t002%3Dhttps%253A%252F%252Fr.gnavi.co.jp%252Farea%252Fjp%252Frs%252F%253Ffwp%253D%2525E6%2525A8%2525AA%2525E6%2525B5%25259C%2526date%253D%2526fw%253D%2525E3%252581%25259F%2525E3%252581%252593%2525E7%252584%2525BC%2525E3%252581%25258D%26a567203%3Dhttps%253A%252F%252Fr.gnavi.co.jp%252Farea%252Fjp%252Frs%252F%253Ffw%253D%2525E5%2525B1%252585%2525E9%252585%252592%2525E5%2525B1%25258B%2526fwp%253D%2525E6%2525A8%2525AA%2525E6%2525B5%25259C; GHistory=a567203%3A110%3A1669744542%2Cgg7t002%3A110%3A1669744522; ghistory_reserve=a567203%3A1669744542%2Cgg7t002%3A1669744522; __cribnotes_prm=__t_1669744547013_%7B%22uuid%22%3A%227a38921c-4d2e-4d30-bcb9-80d0686da7f0%22%7D; cto_bundle=sGp-Ll9kUDVaaHJYMHN3SkFtYyUyQkFmUTh2QWdka0pTQ0xqWlhHVFpETzB3ckh4dG1ya0J4NTB1Y0Z1V09mOUtMRDJWRlBKbDNSU2FTMWFDRXgyOFU4Q0l6UzAzYWFoWE9TMVd0WmVqOFZVcjBmQ3JHVHJyNkFodzhVcDlKTGdRYTBIWXNEdHdET3RzeENSc0Q0eDRGdUlwJTJGS3pWJTJGaXk1QW9sajk1ZUhJRHNaelpaYSUyRllHR0klMkZlNnhWWXIlMkJYTXB3eU00eUw; s_sess=%20sc_oncook%3D%3B%20sc_prop1%3Dr%3B%20cpnt_referer%3D%3B; _dc_gtm_UA-43329175-1=1; _td=639fb236-c732-4fb7-b246-0a6ed66c2a87; _ga_L9BHK8C28C=GS1.1.1669743685.1.1.1669744820.51.0.0; _ga=GA1.1.111137152.1669743686"
request["Sec-Ch-Ua"] = "\"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\""
request["Sec-Ch-Ua-Mobile"] = "?0"
request["Sec-Ch-Ua-Platform"] = "\"macOS\""
request["Sec-Fetch-Dest"] = "document"
request["Sec-Fetch-Mode"] = "navigate"
request["Sec-Fetch-Site"] = "same-origin"
request["Sec-Fetch-User"] = "?1"
request["Upgrade-Insecure-Requests"] = "1"
request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
doc = Nokogiri::HTML.parse(response.body.toutf8, nil, 'utf-8')
puts '###ページタイトル取得###'
puts doc.title
puts "\n###お店の名前を取得###"
doc.css('.style_restaurantNameWrap__wvXSR').map do |target|
puts target.text
end
細かいコードの解説はこの記事ではしません。
実行結果はこんな感じになるかと思います。
###ページタイトル取得###
【美味しいお店が見つかる!】全国の食事・ディナーでおすすめしたい人気のレストラン|ぐるなび
###お店の名前を取得###
大阪こなもん酒場 たこやき番長 関内店
お好み焼き ポン吉 本店
横浜中華街 保昌 コレットマーレ店
築地銀だこハイボール酒場 新横浜店
築地銀だこハイボール酒場 横浜伊勢佐木町店
築地銀だこハイボール酒場 桜木町店
築地銀だこハイボール酒場 関内店
築地銀だこハイボール酒場 桜木町クロスゲート店
銀だこ酒場 綱島店
粉亭
白木屋48 保土ケ谷東口駅前店
カラオケ ビッグエコー 横浜西口駅前本店
カラオケ ビッグエコー 横浜プラザ店
カラオケ ビッグエコー 横浜西口駅前店
カラオケ ビッグエコー 新横浜駅前店
カラオケ ビッグエコー 横浜相鉄口駅前店
カラオケ ビッグエコー 新横浜アリーナ通り店
カーヴ隠れや 横浜西口店
ヨイボシ 野毛桜木町店
カラオケ ビッグエコー 横浜相鉄口駅前2号店
「横浜」「たこ焼き」で検索した結果がこんな感じで取得できます。