Skip to content

Instantly share code, notes, and snippets.

@mhawksey
Created December 2, 2011 10:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mhawksey/1422745 to your computer and use it in GitHub Desktop.
Save mhawksey/1422745 to your computer and use it in GitHub Desktop.
Google Apps Script to get Friend Follower information from Google+ (Plus) More info http://mashe.hawksey.info/2011/12/google-plus-network-info-to-nodexl/
// modification of Tony Hirst's @psychemedia https://gist.github.com/1288134
// by @mhawksey [https://plus.google.com/u/0/114662816634467534305/about]
//# cache time in seconds; if a file is cached and not older than cachetime, that data will be used
var defCache=36000;
//# Do we want to map the social connections between the friends of the friends ('fr') of the
//# target account(s) or the friends of the followers ('fo') of the target account(s)
var typ='fr';
var edgeSheetName = "Links";
var verticesSheetName = "Nodes";
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetE = doc.getSheetByName(edgeSheetName);
var sheetV = doc.getSheetByName(verticesSheetName);
var gPlusIDs=[ScriptProperties.getProperty("GooglePlusID")];
var batchSize = 50;
function onOpen(){
var menuEntries = [];
// When the user clicks on "addMenuExample" then "Menu Entry 1", the function function1 is executed.
menuEntries.push({name: "Set Collection ID", functionName: "start"});
menuEntries.push({name: "Start/Continue Collection", functionName: "build"});
menuEntries.push({name: "Reset", functionName: "reset"});
doc.addMenu("Google+", menuEntries);
}
function start(){
var gID = Browser.inputBox("Visit https://plus.google.com/me and copy paste the url here (or enter a 21 digit user id):");
gID = gID.match(/[0-9]{21}/, "g");
if (gID.length == 0){
Browser.msgBox("Oops - somthing wrong with that ID");
} else {
ScriptProperties.setProperty("GooglePlusID",gID[0]);
//ScriptProperties.setProperty("debug",Browser.msgBox("Google+ ID set. Start collection", Browser.Buttons.OK_CANCEL));
if (Browser.msgBox("Google+ ID set. Start collection", Browser.Buttons.OK_CANCEL)=="ok"){
build();
}
}
}
function reset(){
ScriptProperties.setProperty("GooglePlusID","");
ScriptProperties.setProperty("cursor",1);
sheetE.clearContents();
sheetV.clearContents();
doc.toast("Reset");
}
function build(){
if (!ScriptProperties.getProperty("GooglePlusID") || ScriptProperties.getProperty("GooglePlusID") == ""){
start();
return;
}
var gPlusIDs=[ScriptProperties.getProperty("GooglePlusID")];
doc.toast("Started Collection");
var part = parseInt(ScriptProperties.getProperty("cursor"));
var oidNames={};
var nodes = [];
var links = [];
var doneList = [];
for (id in gPlusIDs){
var test = gPlusIDs[id];
Logger.log('Top level run: getting '+typ+','+id+','+getuserName(gPlusIDs[id]));
oidNames[gPlusIDs[id]]=getuserName(gPlusIDs[id]);
var oids=getoids(gPlusIDs[id], typ);
oids = oids.split(",");
var oidNames=getUserNames(oids,oidNames);
for (oidID in oidNames){
// if (oidID.length>20) {
nodes.push([oidID,oidNames[oidID][0],oidNames[oidID][1]]);
if (part === 1) {
links.push([gPlusIDs[id],oidID]);
//links.push([oidNames[gPlusIDs[id]][0],oidNames[oidID]]);
}
}
sheetV.getRange(1,1,nodes.length,3).setValues(nodes);
var count=1;
var nextToDo = false;
var fsize=oids.length;
if (fsize>batchSize){
if (!ScriptProperties.getProperty("cursor")){
ScriptProperties.setProperty("cursor", 1);
}
if (ScriptProperties.getProperty("cursor") == "end"){
ScriptProperties.setProperty("cursor", 1);
}
var todo = chunks(oids,batchSize);
part = parseInt(ScriptProperties.getProperty("cursor"));
var oids = todo[part-1];
nextToDo = true;
}
for (oid in oids){
if (typeof oidNames[oids[oid]] != undefined){
var msg = 'Sub-level run: getting '+count+' '+'of'+' '+oids.length;
Logger.log(msg);
doc.toast(msg);
var foids=getoids(oids[oid]);
if (foids != null){
for (oidName in oidNames){
var searchKey = new RegExp(oidName,"gi");
if (foids.search(searchKey) != -1){
links.push([oids[oid],oidName]);
//links.push([oidNames[oids[oid]][0],oidNames[oidName][0]]);
}
}
} else {
Logger.log("Oops - problem with "+oidNames[oids[oid]]);
}
doneList.push(["X"]);
count=count+1;
}
}
sheetE.getRange(sheetE.getLastRow()+1,1,links.length,2).setValues(links);
sheetV.getRange((part-1)*batchSize+1,4,doneList.length,1).setValues(doneList);
if (nextToDo){
part++
if (part<=todo.length){
ScriptProperties.setProperty("cursor", part);
Browser.msgBox("Still more data to collect. Run Google+ > Start/Continue Collection for results "+(part)+" of "+todo.length);
} else {
ScriptProperties.setProperty("cursor", "end");
Browser.msgBox("All done!");
}
}
}
}
function getuserName(oid){
//http://socialgraph.apis.google.com/lookup?q=https%3A%2F%2Fplus.google.com%2F104253436939071070140%2F&pretty=1&callback=
var url='http://socialgraph.apis.google.com/lookup?q=https%3A%2F%2Fplus.google.com%2F'+oid+'%2F&callback=';
var xdata = getGenericCachedData(url);
var data = Utilities.jsonParse(xdata);
var uid='http://profiles.google.com/'+oid;
if (uid in data['nodes']){
var name=[data['nodes'][uid]['attributes']['fn'],data['nodes'][uid]['attributes']['photo']]
} else {
var name='';
}
return name
}
function getUserNames(oids,namelookup){
var oidlookup=[];
for (oid in oids){
if (!(oids[oid] in namelookup) && !(oids[oid] in oidlookup)){
oidlookup.push(oids[oid]);
}
}
var oidblocks = chunks(oidlookup,15);
for (oidblock in oidblocks){
var encoids='%2Chttps%3A%2F%2Fplus.google.com%2F'+oidblocks[oidblock].join('%2Chttps%3A%2F%2Fplus.google.com%2F');
//print encoids
var url='http://socialgraph.apis.google.com/lookup?q=https%3A%2F%2Fplus.google.com%2F'+encoids+'%2F&callback=';
//data=json.load(urllib2.urlopen(url))
var xdata=getGenericCachedData(url);
try {
var data=Utilities.jsonParse(xdata);
} catch(e) {
Logger.log(e);
data={};
data['nodes']=[];
}
for (oid in oidblocks[oidblock]){
var uid='http://profiles.google.com/'+oidblocks[oidblock][oid];
if (uid in data['nodes']){
try {
namelookup[oidblocks[oidblock][oid]]=[data['nodes'][uid]['attributes']['fn'],data['nodes'][uid]['attributes']['photo']];
} catch(e) {
Logger.log(e);
namelookup[oidblocks[oidblock][oid]]=['',''];
}
} else {
namelookup[oidblocks[oidblock][oid]]=['',''];
}
}
}
return namelookup;
}
//---
//based on http://html5example.net/entry/tutorial/simple-python-google-plus-api
function getoids(oid,typIn){
var oids = [];
var typ = typIn || 'fr';
if (typ=='fr'){
var url='https://plus.google.com/u/0/_/socialgraph/lookup/visible/?o=%5Bnull%2Cnull%2C%22'+oid+'%22%5D&rt=j';
} else if (typ=='fo'){
var url='https://plus.google.com/u/0/_/socialgraph/lookup/incoming/?o=%5Bnull%2Cnull%2C%22'+oid+'%22%5D&n=1000&rt=j';
} else {
return; //exit(-1)
}
//req = urllib2.Request(url)
//response = urllib2.urlopen(req)
//data = response.read()
Logger.log('Fetching '+url);
oids = getCachedDataOids(url)
//#print data
//oids.split();
//oids = list(set(oids))
return oids;
}
function getCachedDataOids(url) {
var cache = CacheService.getPublicCache(); // initialise
var oids = cache.get("f"+url.substr(0,240)); // get data if any (url trimmed to prevent error)
if (oids == null || oids == "") { // if null or empty means there is no cached data or last fetch failed
var requestData = {"method":"GET", "headers": { "User-Agent": "http://docs.google.com"}}; // prepare request
var response = UrlFetchApp.fetch(url, requestData); // try fetch
if (response.getResponseCode() == 200) { // if response then
var resp = response.getContentText(); // get response text
var reobg = new RegExp("\\d{21}","g"); // only interested in Google Plus user ID so prepare regexp
oids = resp.match(reobg); // get an array of ids
if (!oids == null){ // if something stringify it
oids = oids.join(",");
}
try {
oids = oids.join(",");
cache.put("f"+url.substr(0,240), oids, defCache); // try and put it in cache
} catch(e){
Logger.log(e+url)
return oids; // if too big just return it
}
}
}
return oids;
}
function getGenericCachedData(url) {
var cache = CacheService.getPublicCache();
var data = cache.get("g"+url.substr(0,240));
if (data == null) {
var requestData = {"method":"GET", "headers": { "User-Agent": "http://docs.google.com"}};
try {
var response = UrlFetchApp.fetch(url, requestData);
if (response.getResponseCode() == 200) {
var data = response.getContentText();
cache.put("g"+url.substr(0,240), data, defCache);
}
} catch(e){
Logger.log(e);
}
}
return data;
}
// http://jsfromhell.com/array/chunk
function chunks(a, s){
for(var x, i = 0, c = -1, l = a.length, n = []; i < l; i++)
(x = i % s) ? n[c][x] = a[i] : n[++c] = [a[i]];
return n;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment