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

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

新規登録して質問してみよう
ただいま回答率
85.49%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Ruby

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

Ruby on Rails

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

Q&A

解決済

2回答

1106閲覧

スクレイピングできるサイトとできないサイトがある

renren643

総合スコア279

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Ruby

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

Ruby on Rails

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

0グッド

0クリップ

投稿2017/09/30 10:23

スクレイピングをできるサイトとできないサイトがあります。
例えばヤフーの記事一覧を取得するなら、
1、記事一覧の一番上の記事を検証し、css(xpath)を抜き出す
2、記事一覧の2番目の記事を検証し、css(xpath)を抜き出す
3、#topicsfb > div.topicsindex > ul.emphasis > li:nth-child(1) > a と#topicsfb > div.topicsindex > ul.emphasis > li:nth-child(1) > a
が出てきたとすると、共通部分だけを抜きだし、くり返し処理する。
つまり、この場合だと
nth-child(記事の順番)のところを抜き出し #topicsfb > div.topicsindex > ul.emphasis > li > aとする。(以下、実際のコード)

require "open-uri" require "nokogiri" url = "https://www.yahoo.co.jp/" user_agent = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36' charset = nil html = open(url, "User-Agent" => user_agent) do |f| charset = f.charset f.read end doc = Nokogiri::HTML.parse(html, nil, charset) doc.css('#topicsfb > div.topicsindex > ul.emphasis > li > a').each do |node| puts node.text end

この場合はうまく行ったのですが、
同様のやり方で、やってみるとできないサイトがあります。
(このサイトの記事は、#post-9999 > div > header > h2 > a 、#post-9998 > div > header > h2 > aなど、数字の部分が記事によってことなっていたため、#post> div > header > h2 > aとした。このサイトはこのやり方ではできませんでした。)

doc = Nokogiri::HTML.parse(html, nil, charset) doc.css('#post > div > header > h2 > a').each do |node| puts node.text end

この二つのサイトでは何がちがうのでしょうか?
もしくは、私のやり方に不備があるのでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

プログラムは自分が書いた通りにしか動きません。
上手く行かないのは基本的に自分のやり方が間違っていると思ってください。
nokogiriの前にスタイルシートの理解が不足しているように思います。
#post#post-9999はまったく違うので、一致するはずがありませんよね?

いきなり全部やろうとせずに1つずつやってみると良いです。
まずは、doc.css('#post') でどうなるか試そうと考えるわけです。
p doc.css('#post') を実行すると、id="post"の要素しかヒットしない事が分かるはずです。

この時点で、このアプローチ=やり方が間違っている事が分かります。

cssでは正規表現は使えません。
しかし、これはrubyなのでうまくcssの指定方法とrubyの機能を組み合わせばいいのです。

以下に例を示します。

例えば、こういう記事のdivがあったとして、まとめてループで処理したい場合、さきほどの説明で分かるように異なるIDをcssの指定では直接取れません。

html

1<div id="post-1">...</div> 2<div id="post-2">...</div> 3<div id="post-3">...</div>

そこで、まずはdiv全部を取得してループで回しながら、idがpost-数字にマッチするかどうかチェックして
マッチしないものはスキップするという風にします。

ruby

1require 'nokogiri' 2 3html =<<HTML 4<html> 5<head> 6 <title>テスト</title> 7</head> 8<body> 9 10<div>ダミー</div> 11<div id="post">id数字なし</div> 12 13<div id="post-1"><h2>記事1</h2></div> 14<div id="post-2"><h2>記事2</h2></div> 15<div id="post-3"><h2>記事3</h2></div> 16 17</body> 18</html> 19HTML 20 21doc = Nokogiri::HTML.parse(html) 22doc.css('div').each do |div| 23 unless div.attributes.key?('id') && div.attributes['id'].value =~ /\Apost-([0-9]+)\z/ 24 next 25 end 26 27 puts div.css('h2').text 28end

これを実行すると、このように出力されます。

記事1 記事2 記事3

このようにスクレイピングはパズルのように考えて工夫する事が必要です。

投稿2017/09/30 11:15

mingos

総合スコア4025

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

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

renren643

2017/09/30 12:53

回答ありがとうございます。確かに、言われてみればidって固有のものなので、それを壊したら取得できませんよね。。。このように、普遍的かつ、理由も明確に間違えを指摘していただけると大変 助かりますし、とても勉強になりました。ありがとうございます。
mingos

2017/09/30 12:57

下の方の回答のようにxpathで検索する方法ならば、postという文字を含むidという条件を指定できます。 cssの場合は、そういう事が出来ないというだけなので、状況に応じて使い分けてもいいですし、 今回の回答のように、ちょっと工夫すればそれほど大変でもないのでcssだけでやるのもありですね。
guest

0

Ruby

1require 'nokogiri' 2 3html = <<-EOS 4<html> 5<head> 6 <title>テスト</title> 7</head> 8<body> 9 10<div>ダミー</div> 11<div id="post">id数字なし</div> 12 13<div id="post-1"><h2>記事1</h2></div> 14<div id="post-2"><h2>記事2</h2></div> 15<div id="post-3"><h2>記事3</h2></div> 16 17</body> 18</html 19EOS 20 21doc = Nokogiri::HTML.parse(html) 22 23doc.xpath('//div[contains(@id, "post-")]').each do |node| 24 puts node.xpath('h2').text 25end 26

出力例

記事1 記事2 記事3

mingos様のコードを一部引用。
参考:xpathまとめ

投稿2017/09/30 12:31

編集2017/09/30 12:34
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問