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

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

ただいまの
回答率

91.06%

  • Ruby

    6154questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • RubyGems

    283questions

    RubyGemsはRubyによるプログラミングのためのパッケージマネジメントツールです。ユーザはこれを使用することで、Rubyライブラリのダウンロードやアップデートや、依存関係の自動解決が可能になります。

mechanizeのスクレイピングでレコードが重複してしまう

受付中

回答 1

投稿 編集

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

退会済みユーザー

http://ranking.bunkyodo.co.jp/rankings/detail/0000/4

コチラのページから、タイトル、出版社名を取得したいと考えています。

<div class="col-sm-6">
    <div class="col-sm-2"><span class="text-danger">第1位</span></div>
    <div class="col-sm-4">
        <img src="/img/cover/9784047340893.jpg" class="img-responsive" style="max-height: 150px; " alt="オーバーロード  10 謀略の統治者" />            </div>
    <div class="col-sm-6">
        <h5 class="">オーバーロード  10 謀略の統治者</h5>
        <p class="">KADOKAW</p>
    </div>
</div>

<div class="col-sm-6">
    <div class="col-sm-2"><span class="text-danger">第6位</span></div>
    <div class="col-sm-4">
        <img src="/img/cover/9784763135070.jpg" class="img-responsive" style="max-height: 150px; " alt="コーヒーが冷めないうちに" />            </div>
    <div class="col-sm-6">
        <h5 class="">コーヒーが冷めないうちに</h5>
        <p class="">サンマーク出版</p>
    </div>
</div>
        </div>

以下略

コードは以下のとおりです。

class Bunkyodo_scraping
  def self.bunkyodo_ranking
    agent = Mechanize.new
    page = agent.get("http://ranking.bunkyodo.co.jp/rankings/detail/0000/4")
    books = page.search('.col-sm-6')
    books.each do |book|
      rank = book.search('.col-sm-2').inner_text
      title = book.search('h5').inner_text
      publisher = book.search('p').inner_text
      ranking_data = Bunkyodo.new(title: title, rank: rank, publisher: publisher)
      ranking_data.save
    end
  end

これをコンソールで実行すると、以下のような実行内容になります。

[62] pry(main)> Bunkyodo_scraping.bunkyodo_ranking
   (0.2ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `bunkyodos` (`title`, `rank`, `publisher`, `created_at`, `updated_at`) VALUES ('オーバーロード  10 謀略の統治者', 0, 'KADOKAW', '2016-06-06 06:05:00', '2016-06-06 06:05:00')
   (0.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `bunkyodos` (`title`, `publisher`, `created_at`, `updated_at`) VALUES ('', '', '2016-06-06 06:05:00', '2016-06-06 06:05:00')
   (0.7ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `bunkyodos` (`title`, `rank`, `publisher`, `created_at`, `updated_at`) VALUES ('コーヒーが冷めないうちに', 0, 'サンマーク出版', '2016-06-06 06:05:00', '2016-06-06 06:05:00')
   (0.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `bunkyodos` (`title`, `publisher`, `created_at`, `updated_at`) VALUES ('', '', '2016-06-06 06:05:00', '2016-06-06 06:05:00')


以下略

titieとpublisherがなぜか2回取得されてしまいます。

該当ページのHTMLに「.col-sm-6」が2つあることが問題かと思うのですが、
解決策をご教授ください。よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

0

ご認識の通り「.col-sm-6」が2個ある(しかも入れ子になっている)ためです。
そこまで分かっているのであれば、CSSセレクタまたはXPathの指定を工夫されればよいかと思います。

当該ページのHTMLソースを見て思いついた方法のひとつは、「<div class="row"> の子要素 である <div class="col-sm-6">」を選択する方法です。

books = page.search('div.row > .col-sm-6')

もうひとつは「<div class="col-sm-6"> を子要素に持つ <div class="col-sm-6">」を選択する方法です。こちらはCSSセレクタでは無理だと思う(わたしは)ので、XPathでの指定となります。

books = page.search('//div[@class="col-sm-6"][div[@class="col-sm-6"]]')

ちなみに、上記いずれの場合も、ページの構造に依存して、ランキングが1位、6位、2位、7位、・・・ という順番で取得されます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/07 05:36 編集

    非常にわかりやすい解説ありがとうございます!
    ちなみに「ページの構造に依存して、ランキングが1位、6位、2位、7位、・・・ という順番で取得されます」というのは仰る通りでした…。このHTML構造だと、ランキングを順番通りに取得するのは難しいでしょうか?

    キャンセル

  • 2016/06/07 08:15

    ranking_data を rank でソートした方が簡単だと思いますよ。

    キャンセル

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

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

関連した質問

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

  • Ruby

    6154questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • RubyGems

    283questions

    RubyGemsはRubyによるプログラミングのためのパッケージマネジメントツールです。ユーザはこれを使用することで、Rubyライブラリのダウンロードやアップデートや、依存関係の自動解決が可能になります。