28
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TECH::CAMPAdvent Calendar 2017

Day 2

mechanize × xpathでオシャレにスクレイピング

Last updated at Posted at 2017-12-01

はじめに

今回はスクレイピングについての記事を投稿していこうと思います。

突然なんですが、みなさんに質問して見たいことがあります。
みなさんは初めてスクレイピングをした時の気持ちを覚えてますか?
自分個人の話をすると、初めてスクレイピングできた時、になった気分でした。どんな情報でも取ってこられるんじゃないかとワクワクしたものです。

この記事では、Xpathというものの存在を知り、試しに使ってみることを目的としています。習うより慣れよというスタンスのため、Xpathそのものに関しては特に説明いたしません。最初のうちはXpathの記法が理解できないかもしれませんが、それでも、スクレイピングで使うことはできるので、ぜひ試して見てください。

途中でアクシデントが起こりますが、最後までお付き合い頂けると嬉しいです。

#今回やること

  • HTMLタグを指定した基本的なスクレイピングで取りたい情報を抜き取る。
  • 同じものをxpathで指定してスクレイピングしてくる。
  • Qiitaのトレンドをxpathを応用して取ってくる。

Xpathに慣れてみよう

試しにHTMLタグを使ってスクレイピングして見ましょう。

今回は練習としてこちらのサイトを使って見たいと思います。
このサイトから、上の北海道、東北etc...のようなタブを取ってきましょう。

relux公式ページ

まず、ブラウザの検証機能を開き、どのようなHTMLの構造になっているのかを確認します。試しに、北海道のタブがどうなっているかを確認して見ます。下の画像を見て見ましょう。
検証画面

こちらから、aタグのリンクとタイトルを取ってきます。

sample.rb
require 'mechanize'

agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

ScrapingPage = 'https://rlx.jp/magazine/'
current_page = agent.get(ScrapingPage)
areaTabs = current_page.search('li a')

areaTabs.each do | areaTab |
  areaName = areaTab.inner_text
  areaRelPath = areaTab[:href]
  puts "#{ areaName } : #{ areaRelPath }"
end

さて、実行結果を見て見ましょう。

実行結果.txt
北海道 : /magazine/hokkaido                                                                                            
東北 : /magazine/tohoku                                                                                                
北関東 : /magazine/kitakanto                                                                                           
首都圏 : /magazine/shutoken                                                                                            
甲信越 : /magazine/koshinetsu                                                                                          
北陸 : /magazine/hokuriku                                                                                              
東海 : /magazine/tokai                                                                                                 
近畿 : /magazine/kinki                                                                                                 
山陰・山陽 : /magazine/sanin-sanyo                                                                                     
四国 : /magazine/shikoku                                                                                               
九州 : /magazine/kyushu                                                                                                
沖縄 : /magazine/okinawa                                                                                               
 : https://rlx.jp/magazine/shutoken/51849.html                                                                         
東京のど真ん中にもパワースポットあり!ご縁やエネルギーを感じる旅 : https://rlx.jp/magazine/shutoken/51849.html         
 : https://rlx.jp/magazine/tokai/50831.html                                                                            
自然と暮らしが調和した「岐阜県」の美しい温泉地と、一緒に立ち寄りたい観光スポット : https://rlx.jp/magazine/tokai/50831.
 : https://rlx.jp/magazine/shutoken/49735.html                                                                         
都心から1.5時間で到着!箱根のパワースポットを制覇する癒やし旅 : https://rlx.jp/magazine/shutoken/49735.html            
 : https://rlx.jp/magazine/kyushu/50805.html                                                                           
自然の息吹をたっぷりと感じる旅に。熊本県の強力パワースポットまとめ : https://rlx.jp/magazine/kyushu/50805.html         
 : https://rlx.jp/magazine/tokai/49872.html                                                                            
じつは日本イチ神社仏閣が多い!?名古屋のおすすめパワースポット : https://rlx.jp/magazine/tokai/49872.html              
歴史スポット : https://rlx.jp/magazine/tag/%e6%ad%b4%e5%8f%b2%e3%82%b9%e3%83%9d%e3%83%83%e3%83%88                      
散策・探訪 : https://rlx.jp/magazine/tag/%e6%95%a3%e7%ad%96%e3%83%bb%e6%8e%a2%e8%a8%aa                                 
おすすめ : https://rlx.jp/magazine/tag/%e3%81%8a%e3%81%99%e3%81%99%e3%82%81                                            
癒し・リラックス : https://rlx.jp/magazine/tag/%e7%99%92%e3%81%97%e3%83%bb%e3%83%aa%e3%83%a9%e3%83%83%e3%82%af%e3%82%b9
景色・鑑賞 : https://rlx.jp/magazine/tag/%e6%99%af%e8%89%b2%e3%83%bb%e9%91%91%e8%b3%9e                                 
料理・グルメ : https://rlx.jp/magazine/tag/gourmet                                                                     
絶景 : https://rlx.jp/magazine/tag/%e7%b5%b6%e6%99%af                                                                  
高級ホテル : https://rlx.jp/magazine/tag/%e9%ab%98%e7%b4%9a%e3%83%9b%e3%83%86%e3%83%ab                                 
高級旅館 : https://rlx.jp/magazine/tag/%e9%ab%98%e7%b4%9a%e6%97%85%e9%a4%a8                                            
温泉 : https://rlx.jp/magazine/tag/onsen                                                                               
旅館 : https://rlx.jp/magazine/tag/ryokan                                                                              
ホテル : https://rlx.jp/magazine/tag/hotel                                                                             
自然 : https://rlx.jp/magazine/tag/%e8%87%aa%e7%84%b6                                                                  
宿・宿泊 : https://rlx.jp/magazine/tag/%e5%ae%bf%e3%83%bb%e5%ae%bf%e6%b3%8a                                            
観光 : https://rlx.jp/magazine/tag/sightseeing                                                                         
 : https://itunes.apple.com/jp/app/id843104033                                                                         
 : https://play.google.com/store/apps/details?id=com.loco_partners.relux&hl=ja                                         
 : https://www.facebook.com/rlx.jp                                                                                     
 : https://twitter.com/relux_jp                                                                                        
 : https://plus.google.com/+RlxJp/posts                                                                                
 : http://instagram.com/relux_jp                                                                                                                                                                                                            

ナンジャコリャ!!!
いらない要素まで含まれてしまいました。原因は明らかですね。
li a って要素がたくさんあったのです。例えば、該当部分のHTMLをもう一度見てみると、取りたい要素を取ってくるためには、 #gnav2 ul li a としてあげれば良さそうです。

その部分を修正したコードがこちらになります。

sample.rb
require 'mechanize'

agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

ScrapingPage = 'https://rlx.jp/magazine/'
current_page = agent.get(ScrapingPage)
areaTabs = current_page.search('#gnav2 ul li a')

areaTabs.each do | areaTab |
  areaName = areaTab.inner_text
  areaRelPath = areaTab[:href]
  puts "#{ areaName } : #{ areaRelPath }"
end

こうすると、

実行結果.txt
北海道 : /magazine/hokkaido
東北 : /magazine/tohoku
北関東 : /magazine/kitakanto
首都圏 : /magazine/shutoken
甲信越 : /magazine/koshinetsu
北陸 : /magazine/hokuriku
東海 : /magazine/tokai
近畿 : /magazine/kinki
山陰・山陽 : /magazine/sanin-sanyo
四国 : /magazine/shikoku
九州 : /magazine/kyushu
沖縄 : /magazine/okinawa

取ってきたい要素が取れました!
でも、 全然スマートじゃない!!!

もし、今回のようにdivタグに対して、class名が与えられていない場合にはどうするのかや、もっとスマートにスクレイピングしたい。そんなときに役に立つのがXpathなんです!!!

Xpathでスクレイピングしてみよう

上と同じサイトを Xpath を用いてスクレイピングしてみようと思います。
まず、Xpathを使用するために、スクレイピングしてきたい要素のXpathを取得しましょう。
ブラウザの検証機能(gif画像はchromeの物です)を開き、スクレイピングをしたい要素のHTMLを指定。その要素上で右クリックをし、Copyを選択、その後CopyXpathで完了です。

どうです?簡単でしょう?
詳しくは下の動画を参照してください。
gyazo

コピーしてきたXpathはこちらになります。

 //*[@id="gnav2"]/ul/li[1]/a 

そして、スクレイピングをするためのコードを記述していこうと思います。

sample.rb
require 'mechanize'

agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

ScrapingPage = 'https://rlx.jp/magazine/'
current_page = agent.get(ScrapingPage)
areaTabs = current_page.search('//*[@id="gnav2"]/ul/li[1]/a') #この部分だけ編集しています。

areaTabs.each do | areaTab |
  areaName = areaTab.inner_text
  areaRelPath = areaTab[:href]
  puts "#{ areaName } : #{ areaRelPath }"
end

実行結果は次のようになります。
北海道 : /magazine/hokkaido

北海道だけが取ってこれました。
何かおかしいなと思うかもしれませんが、これはこれで正しいのです。XpathはHTML要素一つ一つに与えられていて、どの要素かを特定することができます。今回の場合だと、
'//*[@id="gnav2"]/ul/li[1]/a'
**li[1]**に注目して見ます。Xpathの特徴として、同じタグで複数要素あるものに対しては、配列のように順番を与え、どの要素かを特定しております。配列と異なる点としましては、配列は0番から要素に番号が与えられるのに対し、Xpathでは1番から順番から与えられます。
北海道ではなく、東北を取得してこようとすると、**li[1]の部分がli[2]**というふうになるわけです。

では、全てのタブを取得するように拡張するにはどうしたらいいのでしょうか?
liの番号でどのタブかを指定しているということは、li全てを取ってきたらいいことになります。そのようにコードを変更して見ましょう。

sample.rb
require 'mechanize'

agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

ScrapingPage = 'https://rlx.jp/magazine/'
current_page = agent.get(ScrapingPage)
areaTabs = current_page.search('//*[@id="gnav2"]/ul/li/a') #この部分だけ編集しています。

areaTabs.each do | areaTab |
  areaName = areaTab.inner_text
  areaRelPath = areaTab[:href]
  puts "#{ areaName } : #{ areaRelPath }"
end

実行結果はもちろんエリアのタブの全ての名前とリンクが取ってこれています。

実行結果.txt
北海道 : /magazine/hokkaido
東北 : /magazine/tohoku
北関東 : /magazine/kitakanto
首都圏 : /magazine/shutoken
甲信越 : /magazine/koshinetsu
北陸 : /magazine/hokuriku
東海 : /magazine/tokai
近畿 : /magazine/kinki
山陰・山陽 : /magazine/sanin-sanyo
四国 : /magazine/shikoku
九州 : /magazine/kyushu
沖縄 : /magazine/okinawa

Xpathのメリット

  • コピペで使えるので要素をHTMLの階層構造を考えなくていい! これに尽きます!!!
  • 並列要素は番号を削除するだけで、並列要素全てを取ってこれるので楽。
  • 自分が想定していない要素を取ってくる心配がなくなる。

これらになるかなと思います。

実際にQiitaのトレンドを取得しよう。

さて、それでは、本題に入りたいと思います。QiitaのトレンドをXpathを用いて取得してみようと思います。
先ほどのように、検証画面を開き、一番上の投稿のXpathをcopyしてこようと思います。
qiitaTrendのXpathCopy

今回はわかりやすくするために、上から二個のXpathをコピーしました。
下に、比較しやすいように取ってきた2つを並べて見ました。

//*[@id="appRoot"]/div/div[2]/div/div[2]/div/div[2]/div/a
//*[@id="appRoot"]/div/div[2]/div/div[2]/div/div[3]/div/a

どこが違うかは一目瞭然ですね。それでは、違う数字が入っているところの数字部分を消去し、スクレイピングをして見ます。

qiitaTrend.rb
require 'mechanize'
agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

QiitaTrendURL = 'https://qiita.com/trend'
QiitaTrendPage = agent.get(QiitaTrendURL)

todaysTrends = QiitaTrendPage.search('//*[@id="appRoot"]/div/div[2]/div/div[2]/div/div/div/a')

todaysTrends.each do | trend |
  puts "#{trend.inner_text}: #{trend[:href]\n"
end

これで取れるだろう!と思い試してみると、何も表示されない!!!
どうしてだろうと思い、ChromeのシークレットモードでqiitaのトレンドURLにアクセスしてみる。
qiita login page

なぜだぁぁぁ!!!12月入ってからいつのまにかセキュリティが強化されていました。11月までは、ログインしなくても取れたのに、、、
メールアドレスでログインしているならそのままMechanizeでログイン処理はかけるけど、、、GitHubアカウントでログインしちゃっているし、Seleniumを使ってGitHubアカウントでログインしようとしたけど、2段階認証がかかっていたため、それもできませんでした。突然の仕様変更なので仕方ないですね。

解決したら、またQiitaを書こうと思います。

Xpathの威力を感じてみる。

このままでは、終わるに終われないので、違うサイトを探して見ました。CodeZineという開発者向けのWebサービスから情報を抜き取ってこようと思います。
このページの右側にある人気ランキングを取得してくるスクリプトを書きましょう。

例のごとく、検証をし、Xpathをコピーしてきます。

取ってきたXpathは今回は次のようになります。
//*[@id="Home"]/main/div/aside/section[3]/div/ul[1]/li[1]/a
明らかにliが並列されていることが、gif画像から確認できるので、**li[1][1]**の部分を削除し、コードを記述すると良さそうです。

sample.rb
require 'mechanize'
agent = Mechanize.new
agent.user_agent_alias = 'Windows IE 9'

CodeZineTopURL = 'https://codezine.jp'
current_page = agent.get(CodeZineTopURL)

latestArticles = current_page.search('//*[@id="Home"]/main/div/aside/section[3]/div/ul[1]/li/a')

latestArticles.each do | article |
  puts "#{ article.inner_text }: #{ CodeZineTopURL + article[:href] }\n"
end

たったこれだけで、人気ランキング全てを取ってくることができます。

#終わりに
Xpathはliなどの並列に要素が並ぶものなどでかなり、その力を発揮してくれます。普段の自分のスクレイピングに1アレンジを加えて見てはいかがでしょう?
慣れてしまうと病みつきになりますよ!!!

28
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?