| 1 | #!/usr/bin/python
|
|---|
| 2 | # -*- coding: utf-8 -*-
|
|---|
| 3 |
|
|---|
| 4 | import sys
|
|---|
| 5 | import codecs
|
|---|
| 6 | import feedparser
|
|---|
| 7 | import re
|
|---|
| 8 | import time
|
|---|
| 9 |
|
|---|
| 10 | #sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 | # 定数
|
|---|
| 14 | LIMIT = 100; # 結果表示するユーザ数の最大数
|
|---|
| 15 | PAGE = 5; # 処理するページ数
|
|---|
| 16 | ROW = 20; # 1ページあたりのブックマーク数
|
|---|
| 17 | SLEEP = 3; # ウェイト秒
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 | # id をチェックし、不正なら 1 を返します
|
|---|
| 21 | def check_id(id):
|
|---|
| 22 |
|
|---|
| 23 | regexp = re.compile('[a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9]$')
|
|---|
| 24 |
|
|---|
| 25 | if regexp.match(id):
|
|---|
| 26 | return
|
|---|
| 27 | else:
|
|---|
| 28 | return 1
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 | # idのブックマークRSSページのURLをリストで返します
|
|---|
| 32 | def get_my_rss(id):
|
|---|
| 33 |
|
|---|
| 34 | my_rss = []
|
|---|
| 35 |
|
|---|
| 36 | for p in range(PAGE):
|
|---|
| 37 |
|
|---|
| 38 | of = p * ROW + (p==0)
|
|---|
| 39 | my_rss.append( "http://b.hatena.ne.jp/" + id + "/rss?of=" + str(of) )
|
|---|
| 40 |
|
|---|
| 41 | return my_rss;
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 | # RSSページからブックマークしたエントリーURLをリストで返します
|
|---|
| 45 | def get_my_bookmarks(my_rss):
|
|---|
| 46 |
|
|---|
| 47 | my_bookmarks = []
|
|---|
| 48 |
|
|---|
| 49 | for rss_url in my_rss:
|
|---|
| 50 |
|
|---|
| 51 | feed = feedparser.parse(rss_url)
|
|---|
| 52 |
|
|---|
| 53 | for item in feed['entries']:
|
|---|
| 54 | my_bookmarks.append('http://b.hatena.ne.jp/entry/rss/' + item.link)
|
|---|
| 55 |
|
|---|
| 56 | time.sleep(SLEEP);
|
|---|
| 57 |
|
|---|
| 58 | return my_bookmarks;
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 | # url がはてなのものでユーザを含む場合、ユーザ名を返します
|
|---|
| 62 | def get_commenter_id_from_url(url):
|
|---|
| 63 |
|
|---|
| 64 | regexp = re.compile('http://b\.hatena\.ne\.jp/([^/]+)/')
|
|---|
| 65 |
|
|---|
| 66 | m = regexp.match(url)
|
|---|
| 67 |
|
|---|
| 68 | if m:
|
|---|
| 69 | return m.group(1)
|
|---|
| 70 | else:
|
|---|
| 71 | return
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 | # target(正規表現) が url にマッチすれば 1 を返します
|
|---|
| 75 | def check_target_in_url(url, target):
|
|---|
| 76 |
|
|---|
| 77 | regexp = re.compile(target)
|
|---|
| 78 |
|
|---|
| 79 | m = regexp.match(url)
|
|---|
| 80 |
|
|---|
| 81 | if m:
|
|---|
| 82 | return 1
|
|---|
| 83 | else:
|
|---|
| 84 | return
|
|---|
| 85 |
|
|---|
| 86 |
|
|---|
| 87 | # 各ブックマークページのブックマーカーから
|
|---|
| 88 | # 自分(id)よりも早くブックマークしているユーザをカウントします
|
|---|
| 89 | def get_commenters(id, bookmarks):
|
|---|
| 90 |
|
|---|
| 91 | users = {};
|
|---|
| 92 | for url in bookmarks:
|
|---|
| 93 |
|
|---|
| 94 | feed = feedparser.parse(url)
|
|---|
| 95 |
|
|---|
| 96 | me = 0
|
|---|
| 97 |
|
|---|
| 98 | for item in feed['entries']:
|
|---|
| 99 |
|
|---|
| 100 | link = item.link
|
|---|
| 101 |
|
|---|
| 102 | if not link:
|
|---|
| 103 | continue
|
|---|
| 104 |
|
|---|
| 105 | if me:
|
|---|
| 106 |
|
|---|
| 107 | user = get_commenter_id_from_url(link)
|
|---|
| 108 |
|
|---|
| 109 | if user:
|
|---|
| 110 | if users.has_key(user):
|
|---|
| 111 | users[user] += 1
|
|---|
| 112 | else:
|
|---|
| 113 | users[user] = 1
|
|---|
| 114 |
|
|---|
| 115 | else:
|
|---|
| 116 |
|
|---|
| 117 | if check_target_in_url(link, 'http://b\.hatena\.ne\.jp/' + id + "/"):
|
|---|
| 118 | me = 1
|
|---|
| 119 |
|
|---|
| 120 | time.sleep(SLEEP)
|
|---|
| 121 |
|
|---|
| 122 | return users;
|
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 125 | #--- メインルーチン
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 | # ID入力とチェック
|
|---|
| 129 | print "input hatena id, and push enter"
|
|---|
| 130 | id = raw_input()
|
|---|
| 131 |
|
|---|
| 132 | if check_id( id ):
|
|---|
| 133 | print "ID [" + id + "] is wrong!"
|
|---|
| 134 | sys.exit(1)
|
|---|
| 135 |
|
|---|
| 136 | # 集計
|
|---|
| 137 | users = get_commenters(id, get_my_bookmarks( get_my_rss(id) ) )
|
|---|
| 138 |
|
|---|
| 139 | # 結果表示
|
|---|
| 140 | count = 1
|
|---|
| 141 | for key,value in sorted(users.items(), key=lambda (k, v): (v, k), reverse=True):
|
|---|
| 142 | if count < LIMIT + 1:
|
|---|
| 143 | print "%d : %d : %s http://b.hatena.ne.jp/%s/" %(count , value, key, key)
|
|---|
| 144 | count += 1
|
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 | '''
|
|---|
| 149 | early-hatena-bookmarkers.py - お気に入りをふやそう!
|
|---|
| 150 |
|
|---|
| 151 | DESCRIPTION
|
|---|
| 152 |
|
|---|
| 153 | このスクリプトは、あるIDがブックマークしているエントリーを
|
|---|
| 154 | IDよりも早くブックマークしているユーザを集計表示します。
|
|---|
| 155 |
|
|---|
| 156 | SYNOPSIS
|
|---|
| 157 |
|
|---|
| 158 | # python early-hatena-bookmarkers.py
|
|---|
| 159 |
|
|---|
| 160 | 上記コマンドで実行すると、IDを入力してください。
|
|---|
| 161 | 結果が表示されるまでにはかなり時間がかかりますので、気長にお待ちください。
|
|---|
| 162 |
|
|---|
| 163 | SEE ALSO
|
|---|
| 164 |
|
|---|
| 165 | http://coderepos.org/share/browser/lang/perl/misc/early-hatena-bookmarkers
|
|---|
| 166 |
|
|---|
| 167 | http://b.hatena.ne.jp/
|
|---|
| 168 |
|
|---|
| 169 | AUTHOR
|
|---|
| 170 |
|
|---|
| 171 | id:bayashi_net
|
|---|
| 172 |
|
|---|
| 173 | LICENSE
|
|---|
| 174 |
|
|---|
| 175 | This module is free software; you can redistribute it and/or
|
|---|
| 176 | modify it under the same terms as Perl itself. See perlartistic.
|
|---|
| 177 | '''
|
|---|
| 178 |
|
|---|