We are writing a module for authorization in VK API
The application authorization process consists of 3 steps:
- Opening a browser window for user authentication on the VKontakte website.
- User permission to access their data.
- Passing the access_token key to the application to access the API.
At first glance, writing a simple portable script will fail. Although, what prevents us from pretending to be a browser?
To achieve our goals, we will use only standard Python modules:
Create opener
In order to pretend to be a real browser, just loading the necessary pages is not enough. At a minimum, you need to correctly handle cookies and redirects. To do this, create an opener that will do all the work for us:
opener = urllib2.build_opener(
urllib2.HTTPCookieProcessor(cookielib.CookieJar()),
urllib2.HTTPRedirectHandler())
We turn to the authorization page
response = opener.open(
"http://oauth.vk.com/oauth/authorize?" + \
"redirect_uri=http://oauth.vk.com/blank.html&response_type=token&" + \
"client_id=%s&scope=%s&display=wap" % (client_id, ",".join(scope))
)
Details about the treatment parameters can be found in the documentation . It should be noted here that we will use a parameter
displaywith a value wap, because there is practically no javascript in this version of the page. scopeis a list of rights names that we want to access.Parsim answer
Let's look at the authorization page code. We will be most interested in the following section:
For the subsequent submission of the form, it is necessary to parse all the input-s (including hidden), as well as the url to which the form is submitted. We write a simple parser based on
HTMLParser:class FormParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.url = None
self.params = {}
self.in_form = False
self.form_parsed = False
self.method = "GET"
def handle_starttag(self, tag, attrs):
tag = tag.lower()
if tag == "form":
if self.form_parsed:
raise RuntimeError("Second form on page")
if self.in_form:
raise RuntimeError("Already in form")
self.in_form = True
if not self.in_form:
return
attrs = dict((name.lower(), value) for name, value in attrs)
if tag == "form":
self.url = attrs["action"]
if "method" in attrs:
self.method = attrs["method"]
elif tag == "input" and "type" in attrs and "name" in attrs:
if attrs["type"] in ["hidden", "text", "password"]:
self.params[attrs["name"]] = attrs["value"] if "value" in attrs else ""
def handle_endtag(self, tag):
tag = tag.lower()
if tag == "form":
if not self.in_form:
raise RuntimeError("Unexpected end of Log in
Substitute the email and password of the user in the request parameters and submit the form:
parser.params["email"] = email
parser.params["pass"] = password
response = opener.open(parser.url, urllib.urlencode(parser.params))
Allow access
The next step, if the user has not done this yet, we need to give the application the rights that we requested in the scope parameter. To do this, we will be offered a page with a form on which there will be Allow and Deny buttons. Parsim and submit the form using the method described above.
Get token and user_id
If we did everything right, then we will eventually be redirected to a page with a url of the form
http://oauth.vk.com/blank.html#access_token= 533bacf01e11f55b536a565b57531ad114461ae8736d6506a3 & expires_in = 86400 & user_id = 8492
where with simple manipulations we can get the ones we need
access_tokenand user_id.Module usage example
Actually, for the sake of which everything was started - a script for downloading the album:
import vk_auth
import json
import urllib2
from urllib import urlencode
import json
import os
import os.path
import getpass
import sys
def call_api(method, params, token):
if isinstance(params, list):
params_list = [kv for kv in params]
elif isinstance(params, dict):
params_list = params.items()
else:
params_list = [params]
params_list.append(("access_token", token))
url = "https://api.vk.com/method/%s?%s" % (method, urlencode(params_list))
return json.loads(urllib2.urlopen(url).read())["response"]
def get_albums(user_id, token):
return call_api("photos.getAlbums", ("uid", user_id), token)
def get_photos_urls(user_id, album_id, token):
photos_list = call_api("photos.get", [("uid", user_id), ("aid", album_id)], token)
result = []
for photo in photos_list:
#Choose photo with largest resolution
if "src_xxbig" in photo:
url = photo["src_xxbig"]
elif "src_xbig" in photo:
url = photo["src_xbig"]
else:
url = photo["src_big"]
result.append(url)
return result
def save_photos(urls, directory):
if not os.path.exists(directory):
os.mkdir(directory)
names_pattern = "%%0%dd.jpg" % len(str(len(urls)))
for num, url in enumerate(urls):
filename = os.path.join(directory, names_pattern % (num + 1))
print "Downloading %s" % filename
open(filename, "w").write(urllib2.urlopen(url).read())
if len(sys.argv) != 2:
print "Usage: %s destination" % sys.argv[0]
sys.exit(1)
directory = sys.argv[1]
email = raw_input("Email: ")
password = getpass.getpass()
token, user_id = vk_auth.auth(email, password, "2951857", "photos")
albums = get_albums(user_id, token)
print "\n".join("%d. %s" % (num + 1, album["title"]) for num, album in enumerate(albums))
choise = -1
while choise not in xrange(len(albums)):
choise = int(raw_input("Choose album number: ")) - 1
photos_urls = get_photos_urls(user_id, albums[choise]["aid"], token)
save_photos(photos_urls, directory)
and how it looks in work:

Conclusion
Of course, this module is not suitable for use in serious projects, but for personal purposes - completely.
Link to GitHub.