Skip to content

Instantly share code, notes, and snippets.

@tekei
Created August 8, 2012 14:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tekei/3295352 to your computer and use it in GitHub Desktop.
Save tekei/3295352 to your computer and use it in GitHub Desktop.
instapaper文字化け再登録ツール (エッセンス版)
# instapaper文字化け再登録ツール (エッセンス版)
# 利用にはOauthキーが必要ですので、Webサービス化する予定です。
#
# 利用に関して
# ・ 修正したRead Laterは、再登録するため登録日付が「今」に変更されます。
# (表示順が逆転します)
# ・ 有料会員である必要があります
# (InstapaperのFull APIの利用規約がそうなっている)
require 'open-uri'
require 'resolv-replace'
require 'timeout'
require 'charlock_holmes'
require 'active_support/core_ext'
# use https://github.com/mattb/instapaper_full
require 'instapaper_full'
OAUTH_KEY = 'xxxxxxxxx'
OAUTH_SECRET = 'xxxxxxxxxx'
username = 'xxxx@xxxxx.xxxxxx'
password = 'xxxxxxx'
ip = InstapaperFull::API.new :consumer_key => OAUTH_KEY, :consumer_secret => OAUTH_SECRET
ip.authenticate(username, password)
module CorrectHelper
module_function
def scraping_title(url)
begin
html = ""
timeout(5){
option = {'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 8.0)'}
option[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_PEER
option[:ssl_ca_cert] = "#{File.dirname(__FILE__)}/ca-bundle.crt"
html = open(url, option) { |c| c.read }
}
title = html.delete("\n\r")[/<title>(.*)<\/title>/i, 1].strip
return nil if title.blank?
encoding = CharlockHolmes::EncodingDetector.detect(html)[:encoding]
title.encode("UTF-8", encoding)
rescue => e
$stderr.puts "[scraping_title] HTTP Error = #{e.inspect}"
nil
end
end
def valid_check(url, title)
# instapaperの機能 private urlで登録したパターンは対象外にする
return nil unless url =~ /^https?:/
urls = url.split('/')
# instapaperがタイトル取得をあきらめたパターン
return :retry if (urls.size > 3 && title == urls[-1])
return :utf if valid_check_utf8(title)
return :sjis if valid_check_sjis(title)
end
# 本来、codepointsメソッドを利用した場合UCS-2の値が取得出来る。
# この値がUTF-8の規則に合致している場合、異常が発生していると考えられる
def valid_check_utf8(str)
utf8_contain = false
pattern = 0
pos = 0
str.codepoints do |c|
if (c >= 0x00 && c <= 0x7f) then
return false if (pattern != 0)
elsif (c >= 0x80 && c <= 0xbf) then
return false if (pattern == 0)
utf8_contain = true
pos += 1
pattern, pos = 0, 0 if (pos == pattern)
elsif (c >= 0xc2 && c <= 0xdf) then
return false if (pattern != 0)
pattern, pos = 1, 0
elsif (c >= 0xe0 && c <= 0xef) then
return false if (pattern != 0)
pattern, pos = 2, 0
elsif (c >= 0xf0 && c <= 0xf7) then
return false if (pattern != 0)
pattern, pos = 3, 0
else
return false
end
end
return (utf8_contain && (pattern == 0) && (pos == 0))
end
# SJISっぽいかチェックする
def valid_check_sjis(str)
sjis_contain = false
upper_code = true
str.codepoints do |c|
return false if c >= 0x100
if upper_code then
if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xef)) then
upper_code = false
end
else
if ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc)) then
sjis_contain = true
upper_code = true
else
return false
end
end
end
return sjis_contain
end
end
# read later直下のみ対応。
ip.bookmarks_list(:limit => 100).each do |b|
if b['type'] == 'bookmark' then
correct_type = CorrectHelper::valid_check(b['url'], b['title'])
unless correct_type.nil?
puts "URL : #{b['url']}"
puts "元のタイトル : #{b['title']}"
correct_title = nil
case correct_type
when :utf then
correct_title = b['title'].codepoints.to_a.pack("C*").force_encoding('utf-8')
when :sjis then
correct_title = b['title'].codepoints.to_a.pack("C*").force_encoding('windows-31j').encode("utf-8")
else
correct_title = CorrectHelper::scraping_title(b['url'])
# 実処理では、scraping_titleの値はキャッシュを行っています。
end
puts "正しそうなタイトル : #{correct_title}"
ip.bookmarks_add(:url => b['url'], :title => correct_title, :description => b['description'])
end
end
end
puts "変換できました!"
@tekei
Copy link
Author

tekei commented Aug 15, 2012

iso-8859-1で記述されたフランス語サイトで誤変換が発生したり、
また、Intrapaperがタイトル取得をあきらめたパターンに対応

@tekei
Copy link
Author

tekei commented Aug 18, 2012

現状で発生を確認しているパターンに対応。
EUC, JISに対する文字化けは確認出来ていない。
なお、ほとんどが「valid_check_utf8」パターンでの文字化け。

@tekei
Copy link
Author

tekei commented Aug 26, 2012

Webサービスとして、公開しました。
https://correct.herokuapp.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment