<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tecnotravel 2.0 &#187; Programación</title>
	<atom:link href="http://tecnotravel.com.ar/category/programacion/feed/" rel="self" type="application/rss+xml" />
	<link>http://tecnotravel.com.ar</link>
	<description>Turismo, Tecnología y Social Media</description>
	<lastBuildDate>Sun, 25 Mar 2012 20:59:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Acceso automático a Facebook por OAuth en Python</title>
		<link>http://tecnotravel.com.ar/2010/09/12/acceso-automatico-a-facebook-por-oauth-en-python/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=acceso-automatico-a-facebook-por-oauth-en-python</link>
		<comments>http://tecnotravel.com.ar/2010/09/12/acceso-automatico-a-facebook-por-oauth-en-python/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 22:56:05 +0000</pubDate>
		<dc:creator>Agustin Sarria</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Tecnología]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://tecnotravel.com.ar/?p=2910</guid>
		<description><![CDATA[Breve tutorial para configurar un acceso a facebook desde Python <a href="http://tecnotravel.com.ar/2010/09/12/acceso-automatico-a-facebook-por-oauth-en-python/">Sigue leyendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="plus-one-wrap"><g:plusone href="http://tecnotravel.com.ar/2010/09/12/acceso-automatico-a-facebook-por-oauth-en-python/"></g:plusone></div><div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Ftecnotravel.com.ar%2F2010%2F09%2F12%2Facceso-automatico-a-facebook-por-oauth-en-python%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Ftecnotravel.com.ar%2F2010%2F09%2F12%2Facceso-automatico-a-facebook-por-oauth-en-python%2F&amp;source=tecnotravel20&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<div id="_mcePaste">En mi trabajo me encontré con la necesidad de acceder de manera automática a información de Facebook de una cuenta que poseemos para luego poder guardarla en una base de datos sin tener que hacerlo interactivamente desde la página de la aplicación.</div>
<p><img class="alignright size-full wp-image-2925" title="Pytho_FB_Oauth" src="http://tecnotravel.com.ar/wp-content/uploads/2010/09/python3.png" alt="" width="110" height="110" /></p>
<div id="_mcePaste">Dado que no encontré código en Python 2.6 que me sirviera para tal fin, decidí meterme un poco más en el asunto y luego de varias horas de investigación, logré realizar el acceso automatizado y obtener el access_token sin tener que hacer login interactivo con el usuario.</div>
<div id="_mcePaste">Espero que a alguien le sirva para hacer clientes de FB o aplicaciones de automatización.</div>
<div>Las pasos que debí superar en este intento fueron:</div>
<div id="_mcePaste">
<ul>
<li><span style="font-size: 13px; line-height: 19px;">Conseguir un ID de desarrollador de Facebook para autorizaciòn OAuth: Esto se hace desde la <a href="http://developers.facebook.com/" target="_blank">página de desarrolladores de Facebook</a> siguiendo los pasos de <a href="http://developers.facebook.com/docs/authentication/desktop" target="_blank">Autenticación para Escritorio</a> ingresando a <a href="http://developers.facebook.com/setup/" target="_blank">la página de alta de aplicación</a>. </span><span style="font-size: 13px; line-height: 19px;"><br />
En el caso de que de error, no hay problema: ingresar a la <a href="http://www.facebook.com/developers/" target="_blank">página de desarrolladores</a> y allí (luego de registrarnos) aprecerá una lista con las aplicaciones que hemos creado. Ingresamos en cualquiera de ellas o en &#8220;Mis Aplicaciones&#8221; y veremos nuestro ID de aplicación, Clave API y Clave Secreta.</span></li>
<li><span style="font-size: 13px; line-height: 19px;">Conseguir los módulos Pyton <a href="http://www.crummy.com/software/BeautifulSoup/download/3.x/" target="_blank">BeautifulSoup</a> y <a href="http://github.com/facebook/python-sdk/" target="_blank">API de Facebook</a> e instalarlos con<br />
&gt;pyton setup.py install</span><br />
<span style="font-size: 13px; line-height: 19px;">para ambos módulos.</span></li>
</ul>
</div>
<div id="_mcePaste">Lecturas recomendadas para poder usar el módulo:</div>
<div id="_mcePaste">
<ul>
<li><span style="font-size: 13px; line-height: 19px;"><a href="http://developers.facebook.com/docs/authentication/permissions" target="_blank">Permisos extendidos de la variable &#8216;scope&#8217; </a>: para entender qué permisos de acceso debemos habilitar y solicitar.</span></li>
<li><span style="font-size: 13px; line-height: 19px;">Explicación de la <a href="http://developers.facebook.com/docs/api" target="_blank">API Graph</a> que es la que usa Facebook para manejar sus objetos.<span id="more-2910"></span><br />
</span></li>
</ul>
</div>
<div id="_mcePaste">Y con esto, ya podemos armar un módulo. Es autoexplicativo en los comentarios. Cualquier mejora que se les ocurra, no duden en comentar.</div>
<div>Más adelante les traeré la automatización de acceso a Twitter desde Python.</div>
<div id="_mcePaste">Hasta la próxima!</div>
<div><strong>Código:</strong></div>
<div><strong><br />
</strong></div>
<div style="font-family: 'courier new'; font-size: small;">#test_fb.py</div>
<div style="font-family: 'courier new'; font-size: small;"># -*- coding: utf-8 -*-</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">import</span> facebook</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">from</span> BeautifulSoup <span style="color: #ff9900;">import</span> BeautifulSoup</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">import</span> urllib2</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">import</span> urllib</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">import</span> cookielib</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;"><span style="color: #ff9900;">import</span> re</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#crear un contenedor de cookies ya que Facebook envía y recibe y no estoy en un navegador</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">cookie_j = cookielib.CookieJar()</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">cookie_h = urllib2.HTTPCookieProcessor(cookie_j)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">opener = urllib2.build_opener(cookie_h)</div>
<div style="font-size: small;"><span style="color: #0000ff;">## En caso de estar detrás de un firewall o proxy, hay que agregar este código &#8220;des-comentándolo&#8221;</span></div>
<div style="font-size: small;"><span style="color: #0000ff;"> ## reemplazando </span><span style="color: #0000ff;">proxy.blablabla.com por la dirección de nuestro proxy y PUERTO por el número de</span></div>
<div style="font-size: small;"><span style="color: #0000ff;">## puerto </span><span style="color: #0000ff;">y</span><span style="color: #0000ff;"> modificar el módulo facebook.py como si indica al final de este código</span></div>
<div style="font-family: 'courier new'; font-size: small;">
<div><span style="color: #0000ff;">#ph = urllib2.ProxyHandler(dict(https=&#8217;proxy.blablabla.com:PUERTO&#8217;))</span></div>
<div><span style="color: #0000ff;">#opener.add_handler(ph)</span></div>
</div>
<div style="font-size: small;"><span style="color: #ff0000;">#listo el contenedor de cookies, creé un opener que use estas cookies</span></div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#ahora pido a Facebook una página para poder loguear a un usuario con mi ID de cliente (la aplicación)</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">id=XXXXXXXX <span style="color: #ff0000;">#aquí va nuestro ID de cliente (aplicación)</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">f=opener.open(<span style="color: #339966;">&#8216;https://graph.facebook.com/oauth/authorize?client_id=&#8217;+ id +&#8217;&amp;redirect_uri=http://www.facebook.com/connect/login_success.html&amp;<br />
type=user_agent&amp;display=popup&amp;scope=manage_pages,read_stream,<br />
read_insights,email,user_status,friends_status&#8217;</span> )</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#Todos estos parámetros que aparecen en scope son autorizaciones extendidas para poder acceder a información adicional del usuario</span></div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#como emails, posts en el muro, fotos, etc. Para más información http://developers.facebook.com/docs/authentication/permissions</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">urllib2.install_opener(opener)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">doc=f.read()</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">soup = BeautifulSoup(&#8221;.join(doc))</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">url= soup(<span style="color: #339966;">&#8216;form&#8217;</span>,id=<span style="color: #339966;">&#8216;login_form&#8217;</span>)[0][<span style="color: #339966;">'action'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">#parse del form de logueo para armar los datos de post</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data={}</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'charset_test'</span>]=<span style="color: #339966;">&#8216;€,´,€,´,?,?,?&#8217;</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'next'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;,id=&#8217;next&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'api_key'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;api_key&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'return_session'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;return_session&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'cancel_url'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;cancel_url&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'legacy_return'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;legacy_return&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'display'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;display&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'session_key_only'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;session_key_only&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'skip_api_login'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;skip_api_login&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'trynum'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;trynum&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'lsd'</span>]=soup(<span style="color: #339966;">&#8216;input&#8217;</span>,id=<span style="color: #339966;">&#8216;lsd&#8217;</span>)[0][<span style="color: #339966;">'value'</span>]</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#aquí van el usuario y el password</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'email'</span>]=<span style="color: #339966;">&#8216;EMAIL_DEL_USUARIO&#8217;</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">data[<span style="color: #339966;">'pass'</span>]=<span style="color: #339966;">&#8216;CLAVE_DEL_USUARIO&#8217;</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">values=urllib.urlencode(data)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">req = urllib2.Request(url, values)</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#obtengo la validación con oauth por parte del usuario</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">response = urllib2.urlopen(req)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">the_page = response.read()</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#busco la dirección de retorno para informar a FB que el usuario aceptó</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">a=re.search(<span style="color: #339966;">&#8216;https.{,}&#8221;&#8216;</span>, the_page)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">url=the_page[a.start():a.end()-1]</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">new_url=url.replace(<span style="color: #339966;">&#8216;\\&#8217;</span>,<span style="color: #339966;">&#8221;</span>)</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#abro y recibo ahora el url con el access_token en el querystring</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">response = urllib2.urlopen(new_url)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">the_page=response.geturl()</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">a=re.search(<span style="color: #339966;">&#8216;access_token=(.{,})&amp;&#8217;</span>, the_page)</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#parse manual del access token</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">access_token=urllib.unquote(the_page[a.start()+13:a.end()-1])</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">print access_token</div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;">#a partir de este momento, poseo el access_token que me permite hacer llamadas a la API Graph de Facebook</span></div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;"># EJEMPLO: cómo acceder a los comentarios del muro</span></div>
<div id="_mcePaste" style="font-size: small;"><span style="color: #ff0000;"># Los resultados están devueltos en JSON</span></div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">graph = facebook.GraphAPI(access_token)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">user = graph.get_object(&#8220;me&#8221;)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">feed = graph.get_connections(user[<span style="color: #339966;">"id"</span>], <span style="color: #339966;">&#8220;feed&#8221;</span>)</div>
<div id="_mcePaste" style="font-family: 'courier new'; font-size: small;">print feed</div>
<h2>Modificación de facebook.py para hacerlo funcionar con un proxy:</h2>
<p>El módulo facebook.py es la API de acceso al Graph de Facebook. Veremos que al estar detrás de un proxy, no funciona como esperábamos. Las modificaciones a hacerle son las siguientes:</p>
<pre><span style="font-family: Georgia, 'Bitstream Charter', serif; color: #444444;"><span style="line-height: 22px;">Le agregamos en la línea 40: el import urllib2:
...
import cgi
import hashlib
import time
import urllib
<span style="color: #0000ff;"><strong><span style="color: #0000ff;">import urllib2</span>
</strong></span>import cookielib
... </span></span></pre>
<pre><span style="font-family: Georgia, 'Bitstream Charter', serif; color: #444444;"><span style="line-height: 22px;">En la línea 173 le agregamos el siguiente código en azul, y modificamos la línea siguiente en verde:
        post_data = None if post_args is None else urllib.urlencode(post_args)
<span style="color: #0000ff;">        <span style="color: #ff0000;"> # código agregado</span>
        cookie_j = cookielib.CookieJar()
        cookie_h = urllib2.HTTPCookieProcessor(cookie_j)
        opener = urllib2.build_opener(cookie_h)
        ph = urllib2.ProxyHandler(dict(https='proxy.BLABLABLA.com:PUERTO'))
        opener.add_handler(ph)
        urllib2.install_opener(opener)
        <span style="color: #ff0000;">#fin Código modificado</span></span>

       <span style="color: #ff0000;"> #código modificado</span>
 <span style="color: #008000;">       file = urllib2.urlopen("https://graph.facebook.com/" + path + "?" +
                              urllib.urlencode(args), post_data)</span>
 </span></span><span style="color: #444444; font-family: Georgia, 'Bitstream Charter', serif; line-height: 22px;">       <span style="color: #ff0000;"> #fin código modificado</span></span></pre>
<p><span style="font-family: Georgia, 'Bitstream Charter', serif; color: #444444;"><span style="line-height: 22px;">Espero que les resulte útil esta última adición. Cualquier duda, o si desean el módulo facebook.py modificado, solicítenlo por este medio.</span></span></p>
<p><span style="font-family: Georgia, 'Bitstream Charter', serif; color: #444444;"><span style="line-height: 22px;">Saludos!</span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://tecnotravel.com.ar/2010/09/12/acceso-automatico-a-facebook-por-oauth-en-python/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

