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

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

ただいまの
回答率

90.84%

  • Ruby on Rails

    6542questions

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

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

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 174
退会済みユーザー

退会済みユーザー

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

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

<div class="products-mainImg "><img src="/products/products_images/l/PRD2009-09-0046_100012_00_1487742558_58abd4de0e038.png" height="350" width="350" alt=""></div>

<div class="products-detailBox">
<div class="products-detailBox__inner">
<dl class="products-detailBox__list">
<dt class="products-detailBox__term">発売日</dt>
<dd class="products-detailBox__desc">
<table class="products-saleDate" summary="販売地域について:北海道~東海">
      <tr>
      <th>北海道</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>東北</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>北関東・信越</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>首都圏</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>東海(静岡含む)</th>
      <td>2017年3月<br /></td>
      </tr></table>
<table class="products-saleDate" summary="販売地域について:北陸~沖縄">
      <tr>
      <th>北陸</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>近畿</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>中国</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>四国</th>
      <td>2017年3月<br /></td>
      </tr>      <tr>
      <th>九州・沖縄</th>
      <td>2017年3月<br /></td>
      </tr></table>

<p class="products-detailBox__areaLink"><a href="#areaBox" class="linkTxt00 js-lightBox">販売地域について</a></p>
</dd>
<dt class="products-detailBox__term">内容量</dt>
<dd class="products-detailBox__desc">135ml</dd>
<dt class="products-detailBox__term">原材料</dt>
<dd class="products-detailBox__desc">グレープフルーツ果汁、異性化液糖、食塩/香料、酸味料、甘味料(アスパルテーム・L−フェニルアラニン化合物、スクラロース)、ビタミンC、ポリリン酸Na、カロテン色素</dd>
<dt class="products-detailBox__term">栄養成分</dt>
<dd class="products-detailBox__desc">[ 1カップ 当り ]<br />熱量:13kcal<br />たんぱく質:0g<br />脂質:0g<br />炭水化物:3.2g<br />食塩相当量:0.17g<br />ビタミンC:40mg</dd>

<dt class="products-detailBox__term">アレルギー<br>関連情報</dt>
<dd class="products-detailBox__desc">
<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>
<p class="products-detailBox__stitle">特定原材料</p>
<ul class="products-detailBox__material">
    <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>
<p class="products-detailBox__note02">卵・乳を含む製品と共通の設備で製造しています。</p>

<p class="products-detailBox__stitle">特定原材料に準ずるもの</p>
<ul class="products-detailBox__material">
    <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>


</dd>
<dt class="products-detailBox__term">製造工場</dt>
<dd class="products-detailBox__desc">国内で製造しています。</dd>
<dt class="products-detailBox__term">JANコード</dt>
<dd class="products-detailBox__desc">4902888341731</dd>
</dl>
</div>
<p class="products-detailBox__txtDate">※2018年01月10日現在の情報です。</p>
<!-- /.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
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • jun68ykt

    2018/01/10 21:21

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

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2018/01/10 21:50

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

    キャンセル

回答 3

checkベストアンサー

+2

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/10 22:46 編集

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

    キャンセル

  • 2018/01/31 12:35

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

    キャンセル

+1

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

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

require 'nokogiri'
require 'open-uri'

urls = 'http://hogehoge.com'

page = Nokogiri::HTML(open(urls))

puts page.xpath('//dd[@class="products-detailBox__desc"][2]').inner_text

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Bootstrapのcollapseが閉じない

    BootflatというBootstrap3のテンプレを使ってサイトを構築しているのですが、 スマホ表示した時のいわゆる「ハンバーガーアイコン」の挙動がうまくいきません。 開く時

  • 受付中

    figureで画像をマウスオーバーのエフェクトについて

    GRAPHICという場所の写真をマウスオーバーしたら写真が暗くなり文字が表示されるエフェクトをしたいのですがどうすればよろしいでしょうか ちなみにコードは <!DOCTYPE

  • 解決済

    レスポンシブな段組みで右端のアイコンだけ固定したい

    とあるテーブルをいくつかのブロックに分けて、横幅にゆとりがある場合段組みになるようにしたいのですが、テーブルの右横に設置したアイコンが段組みが変わってもついてくるようにしたいです。

  • 解決済

    ページ上部にスクロール設定について

    ページの右下に、クリックするとページ上部に行く設定をしたのですが、スクロール位置を1000以下にすると非表示に設定をhead内に記述したのですが実行できません。 ご教授頂けますと嬉

  • 解決済

    magnific popup でフィルター毎のギャラリーを表示させたい。

    https://sakic.jp/blog/web/masonry-filter こちらの方を参考にmasonry にフィルターをつけたギャラリーを作りました。 それに対してmag

  • 解決済

    CSSにて設定した背景画像が表示されない場合の対処法について

    こんばんは。 タイトル通りcssにて背景画像を設定しているのですが、表示されません。。 色々調べながらcssを書き換えたりしてみたのですが、他の場所のレイアウトが大きく崩れてしまた

  • 解決済

    divで囲んだ部分が縦に並ばない

    前提・実現したいこと divのitemsクラスで囲んだ部分が縦に並ばない。 col-xs-8とcol-xs-4を使い画面を8:4に分けてその4の部分に画像を縦に並べたい。 発生

  • 解決済

    画像の下にテーブルが来てしまう

    前提・実現したいこと 画像の下にテーブルが来てしまう。 画像とテーブルの間に30px隙間を空けて配置したい。 発生している問題・エラーメッセージ エラーは特に発生していない。

同じタグがついた質問を見る

  • Ruby on Rails

    6542questions

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