Skip to content

Instantly share code, notes, and snippets.

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 dieudv/29a2d55132d6e7a249690aa4bce63aff to your computer and use it in GitHub Desktop.
Save dieudv/29a2d55132d6e7a249690aa4bce63aff to your computer and use it in GitHub Desktop.
Facebook friends / people search / group members backup in web browser
/* Facebook friends / people search / group members backup in web browser
* Scroll down to your friends page or a people search page to load all profiles
* Copy-paste the script below in a web browser console (F12 key or Ctrl+Shift+K shortcut in a browser like Firefox) and execute the desired function, for example by typing FacebookFriendsBackup() in the console and pressing enter
* A textarea will appear at the end of the page so you can copy the data and paste it in a text file before saving it as a CSV file
* You can then view your backup in a spreadsheet editor like LibreOffice Calc
* You can also compare the backup with another one to see who removed you from their friends list or who appeared in a new search (e.g. with the Linux diff command or awk for column diff https://unix.stackexchange.com/questions/174599/using-diff-on-a-specific-column-in-a-file/174603#174603)
* If the friend changed their name or profile URL, you can still find them with their profile ID which is backed up in the last column (open facebook.com/PROFILE_ID in a web browser)
* The Facebook Graph API was not used because they are locking or deprecating most of their endpoints (e.g. https://developers.facebook.com/docs/graph-api/changelog/breaking-changes/#taggable-friends-4-4)
*/
var data = [];
// to make this script work with the new Facebook, you need to open the mobile web version https://m.facebook.com/username/friends
function FacebookFriendsBackup()
{
var mainList = document.getElementsByClassName("timeline")[0].childNodes[1].childNodes[2].childNodes;
var mainLength = mainList.length;
for (var i = 0; i < mainLength; ++i) {
var list = mainList[i].childNodes;
var length = list.length;
for (var j = 0; j < length; ++j) {
var link = list[j].getElementsByTagName("a")[1];
var count = data.length;
data[count] = link.firstChild.nodeValue;
data[count] += "\t" + link.href;
var friendsButton = list[j].firstChild.childNodes[2];
if (!friendsButton) {
friendsButton = list[j].childNodes[2]; // fix for Chromium (for some reason, Facebook generates a different DOM structure with Firefox)
}
var json = JSON.parse(friendsButton.firstChild.firstChild.childNodes[2].getAttribute("data-store"));
data[count] += "\t" + json.id;
}
}
displayData();
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
function OldFacebookFriendsBackup()
{
var list = document.getElementsByClassName("uiProfileBlockContent");
var length = list.length;
// note: firstChild is a bit faster than firstElementChild: https://jsperf.com/firstelementchild-and-firstchild
for (var i = 0; i < length; ++i) {
var link = list[i].getElementsByTagName("a")[0];
data[i] = link.firstChild.nodeValue;
data[i] += "\t" + link.href;
var json = JSON.parse(link.getAttribute("data-gt"));
if (json) { // JSON data is null when the Facebook profile is deactivated
data[i] += "\t" + json.engagement.eng_tid; // get profile ID in case the Facebook user changes their profile URL
}
}
displayData();
}
// we need to hook AJAX response with JavaScript to get the profile ID since it is not displayed in the DOM (username is not reliable to backup since it can change)
// execute this function before opening the page and scrolling
// https://stackoverflow.com/questions/5202296/add-a-hook-to-all-ajax-requests-on-a-page/27363569#27363569
function FacebookPeopleSearchBackup()
{
var count = 0;
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
if (arguments[1] == "/api/graphql/") {
this.addEventListener("load", function() {
var json = JSON.parse(this.responseText);
var list = json.data.serpResponse.results.edges;
var length = list.length;
for (var i = 0; i < length; ++i) {
var user = list[i].relay_rendering_strategy.view_model.profile;
if (user) {
data[count] = user.id;
// comment previous line and uncomment following lines if you want full name and profile URL also
/*data[count] = user.name;
data[count] += "\t" + user.url;
data[count] += "\t" + user.id;*/
console.log(data[count]);
++count;
}
else {
console.log("END");
displayData();
}
}
});
}
origOpen.apply(this, arguments);
};
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
// can be used to backup a people search (for example to see when someone from another country or city moves to a new city)
// note: I probably should not have shared the example in parentheses above because it is not working anymore ("the quieter you become, the more you are able to hear")
// some results could be missing since sometimes the city name is followed by the region instead of the country
function OldFacebookPeopleSearchBackup()
{
//var list = document.getElementById("browse_result_area").getElementsByClassName("FriendRequestOutgoing"); // missing results since friend button is disabled on some profiles
var list = document.querySelectorAll('#BrowseResultsContainer > div, [data-testid="results"] > div');
var length = list.length;
for (var i = 0; i < length; ++i) {
data[i] = JSON.parse(list[i].firstChild.getAttribute("data-bt")).id;
// comment previous line and uncomment following lines if you want full name and profile URL also
/*var link = list[i].getElementsByTagName("a")[1];
data[i] = link.title;
data[i] += "\t" + link.href;
data[i] += "\t" + JSON.parse(list[i].firstChild.getAttribute("data-bt")).id;*/
}
displayData();
}
// can be used to backup group members with things in common (https://www.facebook.com/groups/XXX/members/things_in_common) or all members
function FacebookGroupMembersBackup()
{
// use XPath since there is no identifier, only random class names
var xpath = "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[4]/div/div/div/div/div/div/div/div[2]/div[1]/div/div[2]/div"; // members with things in common
//var xpath = "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[4]/div/div/div/div/div/div/div/div/div/div/div[2]/div[10]/div/div[2]/div"; // all members
var list = $x(xpath)[0].childNodes;
var length = list.length;
for (var i = 0; i < length; ++i) {
var link = list[i].getElementsByTagName("a")[1];
var split = link.href.split("/");
data[i] = split[split.length - 2];
// comment previous line and uncomment following lines if you want full name also
/*data[i] = link.firstChild.nodeValue;
data[i] += "\t" + split[split.length - 2];*/
}
displayData();
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
// can be used to backup group members with things in common (old URL: https://www.facebook.com/groups/XXX/members_with_things_in_common/)
// some results could be missing since sometimes the city uses the original name instead of the translated name
function OldFacebookGroupMembersBackup()
{
var list = document.querySelectorAll("[id^=things_in_common_]"); // members with things in common
var length = list.length;
for (var i = 0; i < length; ++i) {
data[i] = list[i].id.substr(17);
// comment previous line and uncomment following lines if you want full name and profile URL also
/*var link = list[i].getElementsByTagName("a")[1];
data[i] = link.title;
data[i] += "\t" + link.href;
data[i] += "\t" + list[i].id.substr(17);*/
}
displayData();
}
function displayData()
{
var box = document.createElement("textarea");
box.style = "position: relative; z-index: 1"; // show box on top of other elements (needed for the new Facebook with FacebookPeopleSearchBackup())
box.value = data.join('\n');
document.body.appendChild(box);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment