人人网的好友交集小工具

1

Comments

昨晚花了几个小时写了个计算人人网(其实我还是更喜欢叫他校内)当中,任意两个用户的好友之间交集的在线小工具,可以到我的实验室里看看这个小工具:人人网好友交集

话说能写出这样的工具,主要有赖于我的空间提供商将系统换为 FreeBSD 后可以解析 Python 了,而且也没有限制 CGI,所以就成功了~

由于必须从人人网,而非本地,的用户页面,而非接口,获取数据,速度自然不可能快。所以我才有了那个提示:这一过程可能非常缓慢。不过事实上,经过测试,在我的网站的服务器上,速度还是相当了得的,基本上 2s-5s 就能出结果!想我自己的机子上好的时候都要 7s,不好的时候就根本出不来了……

如果单线程进行获取,那就真可以等死人了……所以用了5线程并发,每个线程维护一个链接……此外还连接的是手机人人网,以换来较小的传输流量,较快的解析速度,和较容易的处理方式……

最后,看代码之前声明一下,这个是以 AGPLv3 协议发布的,根据这一协议,如果你修改了这个代码并且使用你修改过的代码为他人服务,你所修改的代码也必须公开,并且以 AGPLv3 协议发布。

由于前台界面的东西大家都有办法获取,我就不给了,这里直接给出那个后台处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python
# - * - coding: UTF-8 - * -
 
# Copyright (C) 2010 Upsuper <quanxunzhen@gmail.com>
# License: AGPLv3
 
from threading import Thread, Lock
from httplib import HTTPConnection
import urllib
import cgi, json
import sys, re
 
# 常数设置
THREADS_NUM = 5             # 最大线程数
RENREN_USER = ''            # 人人网用户名
RENREN_PWD  = ''            # 人人网密码
USER_AGENT  = 'urenren 0.1' # 提交给人人网的 User-Agent
 
# JSON 输出函数
json_dump = lambda v: json.dump(v, sys.stdout)
# 编译匹配用正则表达式
parse_re = re.compile(r'<td><p><a href="[^\?]+\?id=(\d+)[^"]*">'
                      r'<img src="([^"]+)" border="0" /></a></p>'
                      r'<a href="[^"]+">([^<]+)</a></td>')
 
class RequestThread(Thread):
  def __init__(self, id, sid, friends):
    Thread.__init__(self)
    self.__page = '/getfriends.do?curpage=%%d&id=%d&sid=%s' % (id, sid)
    self.__friends = friends
    self.__conn = HTTPConnection('3g.renren.com')
 
  def run(self):
    global curpage, stop_sign
 
    while not stop_sign:
      # 获取当前页面
      curpage_lock.acquire()
      page = curpage
      curpage += 1
      curpage_lock.release()
 
      # 连接获取数据
      conn = self.__conn
      conn.request('GET', self.__page % (page, ), None, {
        'User-Agent': USER_AGENT
      })
      data = conn.getresponse().read()
 
      # 处理获取的数据
      friend_iter = parse_re.finditer(data)
      t_stop_sign = True
      for f in friend_iter:
        t_stop_sign = False
        id = int(f.group(1))
        self.__friends[id] = (f.group(3), f.group(2))
      stop_sign = t_stop_sign
 
def readFriends(id):
  # 初始化多线程
  global curpage, curpage_lock, stop_sign
  curpage = 0
  curpage_lock = Lock()
  stop_sign = False
  threads = []
  friends = {}
 
  # 创建线程
  for i in xrange(THREADS_NUM):
    threads.append(RequestThread(id, sid, friends))
  # 开始执行线程
  for t in threads:
    t.start()
  # 等待线程结束
  for t in threads:
    t.join()
 
  return friends
 
def main():
  # 初始化CGI输出
  print 'Content-Type: text/plain'
  print
 
  # 获取ID信息
  form = cgi.FieldStorage()
  id1, id2 = 0, 0
  if form.has_key('id1'): id1 = int(form['id1'].value)
  if form.has_key('id2'): id2 = int(form['id2'].value)
  if not (id1 and id2):
    json_dump({'error': True})
    return
 
  # 登入人人网
  conn = HTTPConnection('3g.renren.com')
  conn.request('POST', '/login.do',
      urllib.urlencode({'email': RENREN_USER, 'password': RENREN_PWD}),
      {
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': USER_AGENT,
      })
  response = conn.getresponse()
  data = response.read()
  conn.close()
  match = re.search(r'sid=([0-9a-f]+)', data, re.I)
  global sid
  sid = match.group(1)
 
  # 读取好友
  friends1 = readFriends(id1)
  friends2 = readFriends(id2)
  if len(friends1) > len(friends2):
    friends1, friends2 = friends2, friends1
 
  # 判断交集
  intersection = []
  for i in friends1.iterkeys():
    if i in friends2:
      intersection.append((i, friends2[i][0], friends2[i][1]))
  json_dump({'error': False, 'count': len(intersection), 'data': intersection})
 
if __name__ == '__main__':
  try:
    main()
  except:
    json_dump({'error': True})

代码中的配置常数 RENREN_USER 必须是一个已有的人人网账户的帐户名或邮箱地址,反正就是可以用来登入人人网的东西,RENREN_PWD 也必须是前面的账户对应的密码。因为人人网不允许未登入用户查看各种页面(大约是为了防止搜索引擎的人肉吧……不过其实我们有办法让搜索引擎索引到那些内容的~嘿嘿,突然有了一些邪恶的想法~),所以只能弄一个帐号来登入了。

人人网的手机版为了适应部分手机浏览器不支持 Cookies,用了 SID 的策略,这样我也就可以放心大胆地不管 Cookies 了~这个程序还是蛮好写的说~也只有 Python 能提供如此快速的程序构建~

One Response to “人人网的好友交集小工具”

  1. manshow Says:
    2010年3月31日 19:22 回复

    对这个小工具感兴趣,不过不懂代码,可否传我一份 谢谢 donghao1990@hotmail.com

Leave a Reply