質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

3626閲覧

Rubyのクレイピングでn番目の要素(HTMLタグ)を取得したい

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2018/01/10 12:09

編集2018/01/10 12:50

HTMLからスクレイピングをするとき、構造が複雑で簡単にタグを指定できない場面に遭遇しました。

まず、スクレイピングしたHTMLの構造は以下のとおりです。

HTML

1<div class="products-mainImg "><img src="/products/products_images/l/PRD2009-09-0046_100012_00_1487742558_58abd4de0e038.png" height="350" width="350" alt=""></div> 2 3<div class="products-detailBox"> 4<div class="products-detailBox__inner"> 5<dl class="products-detailBox__list"> 6<dt class="products-detailBox__term">発売日</dt> 7<dd class="products-detailBox__desc"> 8<table class="products-saleDate" summary="販売地域について:北海道~東海"> 9 <tr> 10 <th>北海道</th> 11 <td>2017年3月<br /></td> 12 </tr> <tr> 13 <th>東北</th> 14 <td>2017年3月<br /></td> 15 </tr> <tr> 16 <th>北関東・信越</th> 17 <td>2017年3月<br /></td> 18 </tr> <tr> 19 <th>首都圏</th> 20 <td>2017年3月<br /></td> 21 </tr> <tr> 22 <th>東海(静岡含む)</th> 23 <td>2017年3月<br /></td> 24 </tr></table> 25<table class="products-saleDate" summary="販売地域について:北陸~沖縄"> 26 <tr> 27 <th>北陸</th> 28 <td>2017年3月<br /></td> 29 </tr> <tr> 30 <th>近畿</th> 31 <td>2017年3月<br /></td> 32 </tr> <tr> 33 <th>中国</th> 34 <td>2017年3月<br /></td> 35 </tr> <tr> 36 <th>四国</th> 37 <td>2017年3月<br /></td> 38 </tr> <tr> 39 <th>九州・沖縄</th> 40 <td>2017年3月<br /></td> 41 </tr></table> 42 43<p class="products-detailBox__areaLink"><a href="#areaBox" class="linkTxt00 js-lightBox">販売地域について</a></p> 44</dd> 45<dt class="products-detailBox__term">内容量</dt> 46<dd class="products-detailBox__desc">135ml</dd> 47<dt class="products-detailBox__term">原材料</dt> 48<dd class="products-detailBox__desc">グレープフルーツ果汁、異性化液糖、食塩/香料、酸味料、甘味料(アスパルテーム・L−フェニルアラニン化合物、スクラロース)、ビタミンC、ポリリン酸Na、カロテン色素</dd> 49<dt class="products-detailBox__term">栄養成分</dt> 50<dd class="products-detailBox__desc">[ 1カップ 当り ]<br />熱量:13kcal<br />たんぱく質:0g<br />脂質:0g<br />炭水化物:3.2g<br />食塩相当量:0.17g<br />ビタミンC:40mg</dd> 51 52<dt class="products-detailBox__term">アレルギー<br>関連情報</dt> 53<dd class="products-detailBox__desc"> 54<p class="products-detailBox__note01"><i class="products-detailBox__icon"><img src="img/detail/icon_material/icon_thumb.png" height="17" width="35" alt=""></i>色のアイコンは原材料に使用されております</p> 55<p class="products-detailBox__stitle">特定原材料</p> 56<ul class="products-detailBox__material"> 57 <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0101_off.png" width="60" height="77" alt="卵:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0102_off.png" width="60" height="77" alt="乳:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0103_off.png" width="60" height="77" alt="小麦:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0104_off.png" width="60" height="77" alt="えび:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0105_off.png" width="60" height="77" alt="かに:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0106_off.png" width="60" height="77" alt="そば:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0107_off.png" width="60" height="77" alt="落花生:不使用"></li></ul> 58<p class="products-detailBox__note02">卵・乳を含む製品と共通の設備で製造しています。</p> 59 60<p class="products-detailBox__stitle">特定原材料に準ずるもの</p> 61<ul class="products-detailBox__material"> 62 <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0201_off.png" width="60" height="77" alt="あわび:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0202_off.png" width="60" height="77" alt="いか:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0203_off.png" width="60" height="77" alt="いくら:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0204_off.png" width="60" height="77" alt="オレンジ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0205_off.png" width="60" height="77" alt="キウイフルーツ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0206_off.png" width="60" height="77" alt="牛肉:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0207_off.png" width="60" height="77" alt="くるみ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0208_off.png" width="60" height="77" alt="さけ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0209_off.png" width="60" height="77" alt="さば:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0210_off.png" width="60" height="77" alt="大豆:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0211_off.png" width="60" height="77" alt="鶏肉:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0212_off.png" width="60" height="77" alt="バナナ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0213_off.png" width="60" height="77" alt="豚肉:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0214_off.png" width="60" height="77" alt="まつたけ:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0215_off.png" width="60" height="77" alt="もも:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0216_off.png" width="60" height="77" alt="やまいも:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0217_off.png" width="60" height="77" alt="りんご:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0218_off.png" width="60" height="77" alt="ゼラチン:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0219_off.png" width="60" height="77" alt="ごま:不使用"></li> <li class="products-detailBox__material__item"><img src="img/detail/icon_material/icon_material_0220_off.png" width="60" height="77" alt="カシューナッツ:不使用"></li></ul> 63 64 65</dd> 66<dt class="products-detailBox__term">製造工場</dt> 67<dd class="products-detailBox__desc">国内で製造しています。</dd> 68<dt class="products-detailBox__term">JANコード</dt> 69<dd class="products-detailBox__desc">4902888341731</dd> 70</dl> 71</div> 72<p class="products-detailBox__txtDate">※2018年01月10日現在の情報です。</p> 73<!-- /.products-detailBox --></div>

長くてすみません。

このうち、上から2番目のdd要素である内容量の<dd class="products-detailBox__desc">135ml</dd>の135mlという情報を取得したいです。

試しに、

serving_size = page.at('.products-detailBox__list dt:nth-child(2) dd').inner_text

追記:以下のコードもだめでした。

serving_size = page.at('dl dt:nth-child(2) dd').inner_text

としてみたのですが、上手く取得できません。

検索してみたのですが、有用な情報がなかったので、おわかりの方がいましたらご教授いただけますと幸いです。

追記:以下にRubyのコードを記載いたします。

require 'mechanize' class Scraping def self.icecream_urls links = [] # 個別ページのリンクを保存する配列 agent = Mechanize.new (1..4).each do |i| current_page = agent.get("http://www.morinaga.co.jp/products/list.php?id=030#{i}") elements = current_page.search('.products__list__item a') elements.each do |ele| links << ele.get_attribute('href') end end links.each do |link| #get_product に引数(個別ページのURL)を渡す get_product('http://www.morinaga.co.jp/products/' + link) end end def self.get_product(link) # 個別ページからアイスの情報を取得する agent = Mechanize.new page = agent.get(link) product_name = page.at('.headingType01__txt').inner_text # 商品名 image_url = page.at('.products-mainImg img').get_attribute('src') # 商品画像 serving_size = page.search('dd:nth-child(13)').inner_text # 内容量 product = Product.where(name: product_name, image_url: image_url, serving_size: serving_size).first_or_initialize product.save end end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2018/01/10 12:21

可能ならばRubyのコードも全体を載せてもらったほうが、より確実に回答を望めると思います。
退会済みユーザー

退会済みユーザー

2018/01/10 12:50

コメントありがとうございます。Rubyのコードを追記いたしました。
guest

回答3

0

ベストアンサー

"内容量"の次ということでしょうか。

Ruby

1serving_size = page.at('//dt[text()="内容量"]/following-sibling::dd[position()=1]').inner_text

実用的には、一発で目的ノードを選択する記述を考えるより、Arrayで結果を得て順番に探す方が良いかも知れません。

投稿2018/01/10 12:51

編集2018/01/10 13:07
otn

総合スコア84499

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/01/10 13:49 編集

ありがとうございます!内容量の数値が取得できました。 もし可能であれば、'//dt[text()="内容量"]/following-sibling::dd[position()=1]' という記述方法について簡単にご説明いただけますと幸いです。 誠に勝手ながら、初心者なので次回以降に活かしたいと思いまして…。
otn

2018/01/31 03:35

XPathは、 タグ名[選択条件] という風に要素を指定します。括弧は省略可。 ほとんど、英単語を読んだ通りですが、siblingというのは、兄弟姉妹という意味です。
guest

0

2番目に内容量が来ることが確定していてcssのほうが分かりやすいなら、こんなのでもいけます

ruby

1page.at_css("dd:nth-of-type(2)").inner_text

投稿2018/01/10 12:58

teng

総合スコア127

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

xpathで指定してはいかがですか?

Nokogiriを使っていると想定してですが。

Ruby

1require 'nokogiri' 2require 'open-uri' 3 4urls = 'http://hogehoge.com' 5 6page = Nokogiri::HTML(open(urls)) 7 8puts page.xpath('//dd[@class="products-detailBox__desc"][2]').inner_text

投稿2018/01/10 12:56

編集2018/01/10 12:58
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問