私がスクレイピングを始めた2010年前後の頃は、書籍はまだ出ておらず、試行錯誤の中でやっていましたが、それから少し経ってからRubyでの専門書が出版された記憶があります
ただ、昨今のPythonブーム?により、スクレイピングもPython版は出版される一方、Rubyでの専門書が絶版になってしまい、いつのまにか、スクレイピング=Pythonという、首を傾げたくなるような、Ruby界隈ではなんとなく嫌なムードが漂っています。
そこで、この記事では、ごくごく簡単な例題を交え、RubyとPythonでの比較をしてみたいと思います。
- やりたいこと
- Pythonの場合
- Rubyの場合
- ここまでに参考にしたURL
- 私感
- 切り出した文字列に文字化けは発生する?
- RubyにはPyCallがある
- Ruby使いがPythonのスクレイピング案件をこなすには
- 最後に
やりたいこと
Javascriptで描画せずに、サーバーサイドでHTMLを整形するタイプ(一般的なニュースサイトはごく一部を除き、ほぼこのタイプ)のサイトから情報を取得。
例題では、Yahoo!ニュースの記事から、タイトル(titleタグおよびh1タグのinnerText)を抜き出す。
動作確認は、自宅にあるMacintosh(10.13.6)で行った。
自宅MacのPython(Python3)のバージョンは3.10.0。
Rubyは2.6.5p114。
Pythonの場合
パッケージ(pip3)のインストール
PythonのHTMLパーサの代表格である、Beautiful Soupを導入。
pip3 install bs4
プログラム例
●yahoo.py
from bs4 import BeautifulSoup as bs # SSL: CERTIFICATE_VERIFY_FAILEDが発生する場合はコメントを外して実行 # import ssl # ssl._create_default_https_context = ssl._create_unverified_context import urllib.request as req # YahooニュースのURL(リンク切れの場合は差し替えてください) url ="https://news.yahoo.co.jp/articles/e925ba9c2f157b8cfeee2c5511745f8551cfa0c0" # HTMLファイル(ソースレベルでjavascript描画されていないもの)を取得 html = req.urlopen(url) # htmlファイルを、スクレイピングしやすいようにパースする html_paerse = bs(html, "html.parser") # headerタグ+h1タグの中に、タイトルが紛れている # CSSセレクタで取得 h1 = html_paerse.select("header h1") # h1自体を印字 print(h1) # header h1は2つ存在するが、2つ目がタイトル print(h1[1].text) # こちらはtitleタグの中身 print(html_paerse.title.text)
「header h1」はheaderタグの中にあるh1タグを取得しろ!という意味。
単にh1のみだと、ページによっては多数の結果が取得できてしまう。idやclassなども組み合わせて、いかにシンプルに取得できるかが鍵となります。
実行
python3 yahoo.py
結果
[<h1 class="sc-cBoqAE lRfdj">Yahoo!ニュース</h1>, <h1 class="sc-hgIrPW bDIhnP">大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ</h1>] 大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ 大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ(デイリースポーツ) - Yahoo!ニュース
Rubyの場合
パッケージ(gem)のインストール
RubyのHTMLパーサの代表格である、Nokogiriを導入。
gem install nokogiri
プログラム例
●yahoo.rb
require 'nokogiri' require 'open-uri' # YahooニュースのURL(リンク切れの場合は差し替えてください) url ="https://news.yahoo.co.jp/articles/e925ba9c2f157b8cfeee2c5511745f8551cfa0c0" # HTMLソース取得とパースを一気に行う html_paerse = Nokogiri::HTML(open(url)) # headerタグ+h1タグの中に、タイトルが紛れている # CSSセレクタで取得 h1 = html_paerse.css("header h1") # h1自体を印字 p h1 # header h1は2つ存在するが、2つ目がタイトル puts h1[1].text # こちらはtitleタグの中身(.textは付かない) puts html_paerse.title
実行
ruby yahoo.rb
結果
[#<Nokogiri::XML::Element:0x3fd3bc4f6ae4 name="h1" attributes=[#<Nokogiri::XML::Attr:0x3fd3bc4f69f4 name="class" value="sc-cBoqAE lRfdj">] children=[#<Nokogiri::XML::Text:0x3fd3bc4f69cc "Yahoo!ニュース">]>, #<Nokogiri::XML::Element:0x3fd3bc4f6ad0 name="h1" attributes=[#<Nokogiri::XML::Attr:0x3fd3bc4f6508 name="class" value="sc-hgIrPW bDIhnP">] children=[#<Nokogiri::XML::Text:0x3fd3bc4f64e0 "大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ">]>] 大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ 大谷翔平は復帰目前? 指揮官「明日が最良の日」 右脇腹の張りで3年ぶり5戦連続ベンチ(デイリースポーツ) - Yahoo!ニュース
Rubyの方は、最初の行に、なんとなく複雑な文字列?のようなものが表示されていますが、これはNokogiriのオブジェクトの属性ですので、構造体や配列として、普通にアクセス可能です。
ここまでに参考にしたURL
PythonとRubyで比べる簡単なスクレイピング
qiita.com
【Python】SSL認証に関するエラー返ってきたときの対処法
qiita.com
私感
HTML描画のみのケースはSSLエラー等の対処や、偽装エージェントなどの対策以外は、どちらもCSSセレクタを利用しますので、使用するパッケージに変な方言でもない限り、ほぼ一緒かなと思います。
Javascript描画の場合はSelenium+Chromeランタイムのハンドルになると思うので、こちらも、手順的にはそう変わらないのでは?と思います。
見た目=文法的な違いは?(一般論?)
- RubyもPythonもそれぞれパッケージ名が異なる(パッケージの定義に多少の違いがある)
- Rubyはメソッドチェーンが使用でき、多重カッコ地獄から開放される(Pythonでは関数チェーン)
- Pythonはend文が不要(ただ、改行やインデントルールが厳格すぎて、メンテナンスが面倒な気もする)
- Rubyはreturnやカッコなど含め省略記法が豊富な一方、凝りすぎると、後で何これ?ということになりそう
- 変数の種類や振る舞い方はそれぞれ癖がある(これはどの言語もそう)
こんなところでしょうか。
私は他言語メインの方が読みやすいように、省略記法はなるべく避けたほうが良いかな?と思っています。
また、行折返しよりも、改行して見やすくしたほうが良いでしょうね。
大きな違いは使えるパッケージの方向性でしょうね。
株式市況や統計資料等の数値中心にスクレイピングし、分析等を行いたい場合はPythonなのかもしれませんが、文章を取得して取りまとめたい場合は、Rubyが便利かもしれません。
一方、ハッカーっぽいツールはPython発のほうが豊富な印象はあります。
某動画サイトのダウンロードツールとか。
多少グレーなスクレイピングには向くかもしれません(あくまでもイメージですが)。
以上。
好みの問題や、他にやりたいことなどの兼ね合いから、どちらにするか?でしょうね。
上記の選択肢も含め、どちらか一方といった考えにこだわらずに、プロジェクトでの言語選定では、用途により、両者を使い分けましょう。
切り出した文字列に文字化けは発生する?
𠮷野家の𠮷(つちよし)や、𩸽(ほっけ)、🍣🍺(俗に言う寿司ビール問題)といったサロゲートペア・絵文字対応については、以前はRubyの独壇場だったと思いますが、Pythonも追いついていると思います。
どちらも、文字数カウントや、一文字ずつの切り出しに、異常は発生していないようですね。
RubyにはPyCallがある
ところで、Rubyでは、有志が作成したパッケージPyCallにより、Pythonにしかないライブラリや関数、変数等をRuby上で扱うことができます。
これは便利ですよね!
PyCall github.com
こういったものも含めて考えてみても良いでしょうね。
動作は(Pycallよりも)Python直のほうが早いかと思いますが、既存のRubyソースの改修などでは大いに活躍すると思います。
Ruby使いがPythonのスクレイピング案件をこなすには
ここまでの違いがわかれば、あとは、SQLのアクセスや統計等のパッケージの使い方を覚えれば、RubyとPythonの二刀流で行けそうですね。
SQLに関しては…
…的な通説(都市伝説?)がありそうですが、(スクレイピングを含め)バッチ処理を組んででいる方は、SQLがメインだと思いますけどね。
Java上で動く、JRubyという系統があり、そちらではJDBC使えます。
実際、私はAS/400で実装経験済みです。
(Javaベースのサービスは)初期動作は遅いですが、どのくらいの頻度で実行するかもありますし、常駐させれば問題ないかなと。
最後に
とりあえずは、HTMLのみで取得可能なサイトのスクレイピングを比較しましたが、いかがでしょうか。
機会があればSeleniumについても試してみようかと思います。
それでは、また。