簡単な流れ
- bookmarks.htmlをエクスポートする
- (一部分を削除…←これもRubyでやればいいのでは?(後日、追記しました#「Rubyで不要部分削除」))
- 下記6番のコード(スクリプト)を実行
実際にプログラムを書くときは出力した「bookmarks.html」のコードを表示しながら、少しずつ検証しながら進めていくことになります。
環境
Windows10Pro64bit、ruby2.4、Nokogiri1.10.5
応用
HTMLの解析なのでNokogiriを使います。なぜ見出しが「応用」か?
それは私が素人だからです。「nokogiriはWebから取得したhtmlを解析するものだ」という頭しかないわけです。そうなんです。本質を忘れていました。私は「nokogiriイコールWeb情報!Web情報!!」って頭になっています。
しかし、「あれ?Firefoxから出力したbookmarks.htmlってHTMLだからnokogiriが使えるのでは?」と思って、実験したらできたので「HTML解析イコールNokogiriを使う」ということを思い出しました。
準備
全てのブックマーク(リンク)は、フォルダを作成し、格納しておくこと。そうすると後で見やすくなる。
要するに「他のブックマーク」の中にはフォルダしかない状態にする。
次の2~5を飛ばしてください
bookmarks.htmlを出力して、コードを走らせたら終了です。
コードの「#「Rubyで不要部分削除」」を追記したことで、面倒なことをしなくて済みました。要は1と6だけやれば処理できます。
「あぁ、これが効率化(プログラミング)なんだな」と思いました。
1.「bookmarks.html」をエクスポートする。
今回のターゲットは「他のブックマーク」の中の任意作成フォルダです。
(2.ブックマークをテキストエディタで開く。)
私はVisualStudioCodeを利用しています。
DL、p、DTとか散乱していて、ノイズが激しい。もちろんFirefoxとして必要だから出力しているんだけど、今回必要なのは「URL」と「タイトル」と「カテゴリ」がわかればいいので不要部分を削除する。
※あとでわかったが、「ADD_DATE」があればブックマーク順にソートできるかも。
(3.ctrl+fで「他のブックマーク」を検索。)
とりあえず、まず、とにかく「他のブックマーク」から上を削除する。ちょっとだけスッキリする。タイトルやメタ情報もすべて削除する。
最初のカテゴリから上を削除する。そして、ソースの最下部の終了タグも削除。これでフォルダ名とそれに格納されているリンクだけが残る。
インデントを左端に揃えておく。
自分に必要なタグだけのhtmlにする。
このbookmarks.htmlの中に、個人的に必要ないと思われるランダムな文字列がたくさんある。実際はランダムではなくて「Firefoxがそれを必要だから付加している」のが正解だと思う。特にアイコン画像を文字列化したbase64などがかなりの文字数を占領している。個人的には、ページタイトルとURLだけあればいい。あとフォルダ名か。
(4.ノイズ文字を削除し、Nokogiriで利用しやすくするためにタグ変換する。)
元データを書き換えずに、ごっそり削除したhtmlを「bookmarks_modified.html」として保存する。
(5.「bookmarks_modified.html」をNokogiriで解析し、次のようなハッシュで残)す。
これでかなり見やすくなる、と思う。
Nokogiriの使い方を学べば自分の好きなように加工できます。
{ "フォルダ名" => [ ["ページタイトル", "URL"], ["ページタイトル", "URL"] ], "フォルダ名" => [ ["ページタイトル", "URL"], ["ページタイトル", "URL"] ] }
6.コード記載「4と5のロジックを合わせたもの」
require "nokogiri" require "pp" #■■■フェーズ1「不要部分削除のHTML作成」■■■ bookmarks_str = File.read("bookmarks.html") #「Rubyで不要部分削除」 bookmarks_str.gsub!(/[\s\S]*?他のブックマーク[\s\S]*?<DL><p>/, "") #puts bookmarks_str[(bookmarks_str.length - 15)..bookmarks_str.length]数字部分はこれで検証しました bookmarks_str[(bookmarks_str.length - 15)..bookmarks_str.length] = "" #gsubと同じ役割を果たします #ノイズ除去方法、gsubを使います #bookmarks_str.gsub!(//, "").gsub!(//, "").gsub!(//, "").gsub!(//, "") #正規表現…学習しましょう!「.+」←マジ助かる bookmarks_str.gsub!(/LAST_MODIFIED=".+"/, "").gsub!(/ICON_URI=".+" ICON=".+"/, "") #タグ変換 #個人的に使いやすいdivを利用する bookmarks_str.gsub!(/<DT><H3/, "<div class=\"kategori\"><H3").gsub!(/<\/DL><p>/, "</DL><p></div>") #bookmarks.htmlを書き換えたものを別途保存する File.open("bookmarks_modified.html", "w") do |f| f.puts bookmarks_str end #■■■フェーズ2「ハッシュ作成」■■■ html_code = File.read("bookmarks_modified.html") nokogiri = Nokogiri::HTML(html_code) #1つのarrayには、リンクを複数持つ。 array = nokogiri.css("div.kategori") #ハッシュでデータを持つことにする hash = {} #ハッシュに任意の形でデータを詰めていく array.each do |kategori| key = kategori.css("h3").text links = [] kategori.css("a").each do |link| title = link.text url = link[:href] add_date = link[:add_date] #links = [title, url] 「=」じゃダメ。最後のリンクだけしか残らなくなる links << [title, url, add_date] #←後日追加しました #linksはこんな形[[a, b, c], [a, b, c]] #puts link.keys end hash[key] = links end #pp hash #puts nokogiri.css("a").countで総リンク数が合うはずです #■■■フェーズ3「ハッシュを結果的にどう生かす?」■■■ puts "「↑このハッシュを結果的にどう生かす?」→考え中" puts "ブックマークしたWebサイトをどうしたいか?" puts "とりあえずhtml作成しました。見た目はほぼbookmarks.htmlと同じ?" #■■■フェーズ4「link_collection.html」作成■■■ #add_dateでソートする→ダメだ。Firefoxのブックマークに入れる作業の段階でADD_DATEは付与されるので、ブックマーク追加順をこっちが注意しないといけない File.open("link_collection.html", "w") do |f| hash.each do |key, value| f.puts "<h3>#{key}</h3>" value.each do |title, url| f.puts "<p><a href=\"#{url}\">#{title}</a></p>" end end end
補足
「正規表現で「複数行にまたがる」任意の文字を削除したい。」
Google検索「正規表現 文字列 改行含む」
【参考】https://qiita.com/officemove/items/a6caa20c978197eaff50
ユニークな文字列あってもなくてもいい[\s\S]*?ユニークな文字列あってもなくてもいい [\s\S]*?→これ単体で使うとファイルの中身が真っ白になります。
コード内のnokogiriで取得した「kategori」のイメージ
フォルダ名があって、aリンクが格納分ぶら下がっているイメージ
- kategori
- h3
- a
- a
- …
変数の命名が結構大事だと痛感した。
keysが意外と使える
要素の属性値を取得したい時に「どのキー(文字列)でアクセスしていいのか?」がわからないので、取得した要素に「.keys」メソッドを使うと教えてくれる。
この記事で個人的にベンチ入りにしたメソッドだが、今後もよく使いそうだ。
引き続きnokogiriのメソッドは覚えていこう
- .value
- .attribute
- .text
など。
重要なことはコードを覚えるのではなく、いちからコーディングできること
覚えることは少ない。これは巷でプログラミングの学習でよく言われていること。今回「確かに…」と改めて思った。というのは逆に「全部覚えることはほぼ100%無理」それに私は「プログラマーを目指している」わけではない。そしたら、逆転の発想で「じゃあ本質は何が大事なのか?」を見抜くことだと思う。
ちなみに今回のコードで大事なところは以下です。
- gsubを使うところ
- 正規表現でかなり楽ができるところ
- nokogiriのcssメソッドでどこをとるか?というところ
- 変数命名のわかりやすさ