Подбор пар на сайте Facebook

Сайт Facebook – это популярная социальная сеть, которая первоначально была ориентирована на студентов колледжей, но затем открылась для более широкой аудитории. Как и другие социальные сети, она позволяет пользователям создавать профили, вводить о себе демографическую информацию и общаться с друзьями на сайте. Кроме того, Facebook предоставляет API, позволяющий запрашивать информацию о людях и узнавать, являются ли два указанных человека друзьями. С помощью этого API можно построить реальный набор данных для подбора пар.

Во время работы над этой книгой сайт Facebook очень трепетно относился к конфиденциальности, поэтому смотреть можно лишь профили собственных друзей. API следует таким же правилам, то есть требует наличия учетной записи и ограничивает возможности запросов. Поэтому, чтобы проработать пример из этого раздела, вы должны создать учетную запись на сайте Facebook и обзавестись по меньшей мере 20 друзьями.

Получение ключа разработчика

Если у вас есть учетная на сайте Facebook, то вы можете запросить ключ разработчика на странице http://developers.facebook.com.

Вы получите две строки – ключ для доступа к API и секретный ключ. Первый необходим для идентификации, второй – для созданий свертки запросов, о чем мы поговорим ниже. Создайте новый файл facebook. py, импортируйте в него необходимые модули и задайте некоторые константы:

import urllib,md5,webbrowser,time from xml.dom.minidom import parseString

apikey="Sarn ключ для доступа к API" secret="Ваш секретный ключ"

FacebookSecureURL = "https://api.facebook.com/restserver.php" Добавим еще два вспомогательных метода: getsinglevalue получает следующее значение из поименованного узла, а callid возвращает число, сгенерированное на основе системного таймера.

def getsinglevalue(node,tag):

nl=node.getElementsByTagName(tag) if len(nl)>0: tagNode=nl[0]

if tagNode.hasChildNodes( ):

return tagNode.firstChild.nodeValue return ”

def callid( ):

return str(int(time.time( )*10))

Для некоторых вызовов API сайта Facebook требуется посылать порядковый номер, в качестве которого можно взять любое число, лишь бы оно было больше предыдущего номера. Системный таймер позволяет легко удовлетворить этому условию.

Создание сеанса

Процедура создания сеанса на сайте Facebook спроектирована так, что позволяет создавать приложение, которым смогут воспользоваться другие люди, хотя их имя и пароль вам неизвестны. Достигается это путем выполнения нескольких шагов:

1.         С помощью API сайта Facebook запросить маркер.

2.         Послать на страницу регистрации запрос, в URL которого указан маркер.

3.         Подождать, пока пользователь зарегистрируется.

4.         Запросить у API сайта Facebook сеанс, указав маркер. Поскольку в этих вызовах используется несколько общих переменных, лучше обернуть их в класс. Создайте в файле facebook.py новый класс fbsession и включите в него метод __init__, реализующий перечисленные выше шаги:

class fbsession: def __init__(self):

self.session_secret=None

self.session_key=None

self.token=self.createtoken( )

webbrowser.open(self.getlogin( ))

print "После регистрации нажмите клавишу Enter:",

raw_input( )

self.getsession( )

Метод __init__ вызывает несколько других методов, которые нам предстоит добавить в класс. Прежде всего необходим способ отправки запросов

API сайта Facebook. Метод sendrequest открывает соединение с сайтом Facebook и посылает запрос, содержащий указанные аргументы. Возвращаемый документ в формате XML разбирается с помощью библиотеки minidom. Добавьте этот метод в класс:

def sendrequest(self, args): args[‘api_key’] = apikey args[‘sig’] = self.makehash(args)

post_data = urllib.urlencode(args) url = FacebookURL + "?" + post_data data=urllib.urlopen(url).read( ) return parseString(data)

В строке, выделенной полужирным шрифтом, генерируется сигнатура запроса. Для этого вызывается метод makehash, который конкатенирует все параметры в одну строку и вычисляет ее свертку с помощью секретного ключа. Скоро вы увидите, что после получения сеанса секретный ключ изменяется, поэтому метод проверяет, есть ли у вас уже секретный ключ сеанса. Добавьте метод makehash в класс:

def makehash(self,args):

hasher = md5.new(”.]oin([x + ‘=’ + args[x] for x in sorted(args. keys( ))]))

if self.session_secret: hasher.update(self.session_secret) else: hasher.update(secret) return hasher.hexdigest( )

Теперь можно обращаться к функциям API сайта Facebook. Начнем с функции createtoken, которая создает и сохраняет маркер, необходимый для открытия страницы регистрации:

def createtoken(self):

res = self.sendrequest({‘method’:"facebook.auth.createToken"}) self.token = getsinglevalue(res,’token’)

Добавьте также метод getlogin, который просто возвращает URL страницы регистрации:

def getlogin(self):

return "http://api.facebook.com/login.php?api_key="+apikey+\ "&auth_token=" + self.token

После того как пользователь зарегистрировался, следует вызвать метод getsession для получения ключа и секретного ключа сеанса, который понадобится для шифрования последующих запросов. Добавьте этот метод в класс:

def getsession(self): doc=self.sendrequest({‘method’:’facebook.auth.getSession’,

‘auth_token’:self.token}) self.session_key=getsinglevalue(doc,’session_key’) self.session_secret=getsinglevalue(doc,’secret’)

Для подготовки сеанса надо проделать много работы, но дальше все пойдет легче. В этой статье нас будет интересовать только получение информации о людях, но, заглянув в документацию, вы обнаружите, что можно столь же просто загружать фотографии и информацию о событиях.

Загрузка данных о друзьях

Теперь можно перейти к написанию полезных методов. Метод getfriends загружает идентификаторы друзей зарегистрировавшегося пользователя и возвращает их в виде списка. Добавьте его в класс fbsession: def getfriends(self): doc=self.sendrequest({‘method’:’facebook.friends.get’,

‘session_key’:self.session_key,’call_id’:callid( )})

results=[]

for n in doc.getElementsByTagName(‘result_elt’):

results.append(n.firstChild.nodeValue) return results

Поскольку getfriends возвращает только идентификаторы, нужен еще один метод, который загрузит собственно информацию о конкретном человеке. Метод getinfo вызывает функцию API getInfo, передавая ей список идентификаторов. Он запрашивает всего несколько полей, но при желании вы можете добавить дополнительные поля в строку fields и модифицировать код разбора XML так, чтобы он извлекал соответствующую информацию. Полный список полей приведен в документации для разработчика на сайте Facebook: def getinfo(self,users): ulist=’,’.join(users)

fields=’gender,current_location,relationship_status,’+\ ‘affiliations,hometown_location’

doc=self.sendrequest({‘method’:’facebook.users.getInfo’, ‘session_key’:self.session_key,’call_id’:callid( ), ‘users’:ulist,’fields’:fields})

results={}

for n,id in zip(doc.getElementsByTagName(‘result_elt’),users): # Получить местонахождение

locnode=n.getElementsByTagName(‘hometown_location’)[0] loc=getsinglevalue(locnode,’city’)+’, ‘+getsinglevalue(locnode,’state’)

# Получить название учебного заведения

college=”

gradyear=’0′

affiliations=n.getElementsByTagName(‘affiliations_elt’) for aff in affiliations: # Тип 1 – это колледж if getsinglevalue(aff,’type’)==’1′: college=getsinglevalue(aff,’name’) gradyear=getsinglevalue(aff,’year’)

results[id]={‘gender’:getsinglevalue(n,’gender’),

‘status’:getsinglevalue(n,’relationship_status’), ‘location’:loc,’college’:college,’year’:gradyear} return results

Результаты представлены в виде словаря, который отображает идентификатор пользователя на набор информации о нем. Этим словарем можно воспользоваться, чтобы создать набор данных для подбора пар. Если хотите, можете протестировать новый класс в интерактивном сеансе: >>> import facebook >>> s=facebook.fbsession( ) После регистрации нажмите клавишу Enter: >>> friends=s.getfriends( ) >>> friends[1] u’iY5TTbS-0fvs.’ >>> s.getinfo(friends[0:2])

{u’iA810MUfhfsw.’: {‘gender’: u’Female’, ‘location’: u’Atlanta, ‘}, u’iY5TTbS-0fvs.’: {‘gender’: u’Male’, ‘location’: u’Boston, ‘}}

Построение набора данных для подбора пар

Последний вызов API сайта Facebook, который нам потребуется, определяет, являются ли два человека друзьями. Эта информация станет «ответом» в нашем наборе данных. Функции нужно передать два списка идентификаторов одинаковой длины, а вернет она список, содержащий по одному числу для каждой пары, – 1, если это друзья, и 0 в противном случае. Добавьте в класс следующий метод:

def arefriends(self,idlist1,idlist2): id1=’,’.join(idlist1) id2=’,’.join(idlist2)

doc=self.sendrequest({‘method’:’facebook.friends.areFriends’,

‘session_key’:self.session_key,’call_id’:callid( ), ‘id1′:id1,’id2’:id2})

results=[]

for n in doc.getElementsByTagName(‘result_elt’):

results.append(n.firstChild.nodeValue) return results

И соберем все вместе, чтобы создать набор данных для работы с библиотекой LIBSVM. В результате мы получим список друзей зарегистрировавшегося пользователя, загрузим информацию о них и создадим строку для каждой пары. Затем для каждой пары проверим, являются ли они друзьями. Добавьте в класс метод makedataset:

def makedataset(self):

from advancedclassify import milesdistance

#    Получить всю информацию о моих друзьях friends=self.getfriends( ) info=self.getinfo(friends) ids1,ids2=[],[]

rows=[]

#    Вложенный цикл для проверки каждой пары for i in range(len(friends)):

f1=friends[i] data1=info[f1]

# Начинаем с i + 1, чтобы не повторять уже сделанное for j in range(i+1,len(friends)): f2=friends[j] data2=info[f2] ids1.append(f1) ids2.append(f2)

# Генерируем на основе данных некоторые числа if data1[‘college’]==data2[‘college’]: sameschool=1 else: sameschool=0

male1=(data1[‘gender’]==’Male’) and 1 or 0 male2=(data2[‘gender’]==’Male’) and 1 or 0

row=[male1,int(data1[‘year’]),male2,int(data2[‘year’]),sameschool] rows.append(row) # Вызываем arefriends для каждой пары блоками arefriends=[]

for i in range(0,len(ids1),30): j=min(i+20,len(ids1)) pa=self.arefriends(ids1[i:]],ids2[i:J]) arefriends+=pa return arefriends,rows

Этот метод заменяет пол и состояние числами, чтобы набор можно было использовать совместно с LIBSVM. В последнем цикле запрашивается состояние «дружественности» для каждой пары людей. Это делается блоками, так как Facebook ограничивает длину одного запроса.

Создание SVM-модели

Чтобы построить SVM-модель на основе полученных данных, создайте новый сеанс и сгенерируйте набор данных: >>> reload(facebook)

<module ‘facebook’ from ‘facebook.pyc’> >>> s=facebook.fbsession( ) После регистрации нажмите клавишу Enter: >>> answers,data=s.makedataset( )

К этому набору библиотечные функции применимы непосредственно:

>>> param = svm_parameter(kernel_type = RBF) >>> prob = svm_problem(answers,data) >>> m=svm_model(prob,param)

>>> m.predict([1,2003,1,2003,1]) # Два человека, окончившие один колледж в один год

1.0

>>> m.predict([1,2003,1,1996,0]) # Разные колледжи, разные годы окончания

0.0

Разумеется, вы получите другие результаты, но, как правило, модель считает, что два человека, окончившие один и тот же колледж или родившиеся в одном городе, могут быть друзьями.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100