Tuto Scap FaceBook groupe (Morceau de code à mettre dans la console)

Salut à tous, petite astuce pour récupérer des profils FB de groupe.
Un morceau de code à injecter dans la console une fois sur le groupe Facebook dit.

Une fois le code mit il y aura un bouton Member download qui apparaît sur la page:

Il suffit de scroller la page (avec un scroll auto) et il récupère tous les membres au format CSV a télécharger.
ID facebook, Nom prénom, page fb du profil, date d’ajout au groupe.

Exemple de csv extrait ci-dessous :

Voici le bout de code :point_down::

function exportToCsv(e,t){for(var n="",o=0;o<t.length;o++)n+=function(e){for(var t="",n=0;n<e.length;n++){var o=null===e[n]||void 0===e[n]?"":e[n].toString(),o=(o=e[n]instanceof Date?e[n].toLocaleString():o).replace(/"/g,'""');0<n&&(t+=","),t+=o=0<=o.search(/("|,|\n)/g)?'"'+o+'"':o}return t+"\n"}(t[o]);var i=new Blob([n],{type:"text/csv;charset=utf-8;"}),r=document.createElement("a");void 0!==r.download&&(i=URL.createObjectURL(i),r.setAttribute("href",i),r.setAttribute("download",e),document.body.appendChild(r),r.click(),document.body.removeChild(r))}function buildCTABtn(){var e=document.createElement("div"),t=(e.setAttribute("style",["position: fixed;","top: 0;","left: 0;","z-index: 10;","width: 100%;","height: 100%;","pointer-events: none;"].join("")),document.createElement("div")),n=(t.setAttribute("style",["position: absolute;","bottom: 30px;","right: 130px;","color: white;","min-width: 150px;","background: var(--primary-button-background);","border-radius: var(--button-corner-radius);","padding: 0px 12px;","cursor: pointer;","font-weight:600;","font-size:15px;","display: inline-flex;","pointer-events: auto;","height: 36px;","align-items: center;","justify-content: center;"].join("")),document.createTextNode("Download ")),o=document.createElement("span"),i=(o.setAttribute("id","fb-group-scraper-number-tracker"),o.textContent="0",document.createTextNode(" members"));return t.appendChild(n),t.appendChild(o),t.appendChild(i),t.addEventListener("click",function(){var e=(new Date).toISOString();exportToCsv("groupMemberExport-".concat(e,".csv"),window.members_list)}),e.appendChild(t),document.body.appendChild(e),e}function parseResponse(e){var t,n;try{t=JSON.parse(e)}catch(e){return void console.error("Fail to parse API response",e)}if(null!==(e=null==t?void 0:t.data)&&void 0!==e&&e.group)o=t.data.group;else{if("Group"!==(null===(e=null===(e=null==t?void 0:t.data)||void 0===e?void 0:e.node)||void 0===e?void 0:e.__typename))return;o=t.data.node}if(null!==(e=null==o?void 0:o.new_members)&&void 0!==e&&e.edges)n=o.new_members.edges;else{if(null===(t=null==o?void 0:o.new_forum_members)||void 0===t||!t.edges)return;n=o.new_forum_members.edges}var e=n.map(function(e){var t=e.node,n=t.id,o=t.name,i=t.bio_text,r=t.url,d=t.profile_picture,t=t.__isProfile,l=(null===(l=null==e?void 0:e.join_status_text)||void 0===l?void 0:l.text)||(null===(l=null===(l=null==e?void 0:e.membership)||void 0===l?void 0:l.join_status_text)||void 0===l?void 0:l.text),e=null===(e=e.node.group_membership)||void 0===e?void 0:e.associated_group.id;return[n,o,r,(null==i?void 0:i.text)||"",(null==d?void 0:d.uri)||"",e,l||"",t]}),o=((t=window.members_list).push.apply(t,e),document.getElementById("fb-group-scraper-number-tracker"));o&&(o.textContent=window.members_list.length.toString())}function main(){buildCTABtn();var e=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(){this.addEventListener("readystatechange",function(){this.responseURL.includes("/api/graphql/")&&4===this.readyState&&parseResponse(this.responseText)},!1),e.apply(this,arguments)}}window.members_list=window.members_list||[["Profile Id","Full Name","ProfileLink","Bio","Image Src","Groupe Id","Group Joining Text","Profile Type"]],main();
6 « J'aime »

Belle initiative, merci !

1 « J'aime »

Bravo et merci !

Merci !

Je me retrouve avec le message d’erreur : « Uncaught SyntaxError: Invalid or unexpected token »

Une idée d’où vient le problème ?

@Gwarpf, tente de le corriger avec ChatGPT, peut-être qu’il y arrivera

2 « J'aime »

Le plus fort, j’ai essayé :joy: Et non ça n’a pas marché, puisque encore une erreur, cette fois-ci « Uncaught SyntaxError: Unexpected string »

La prochaine fois ça serait sympa de me répondre directement avec l’API ChatGPT ! :stuck_out_tongue_winking_eye:

@Gwarpf :joy:

Je ne sais pas dev, sinon je t’aurais aidé.
ChatGPT m’a déjà corrigé des codes donc c’était une suggestion :grin:

Voilà ce qu’il m’a donné, mais je n’ai pas tenté :

function exportToCsv(e, t) {
  var n = "";
  for (var o = 0; o < t.length; o++)
    n += function (e) {
      for (var t = "", n = 0; n < e.length; n++) {
        var o = null === e[n] || void 0 === e[n] ? "" : e[n].toString(),
          o = e[n] instanceof Date ? e[n].toLocaleString() : o;
        (o = o.replace(/\"/g, '""')), 0 < n && (t += ","), (t += o = 0 <= o.search(/(\"|,|\n)/g) ? '"' + o + '"' : o);
      }
      return t + "\n";
    }(t[o]);
  var i = new Blob([n], { type: "text/csv;charset=utf-8;" }),
    r = document.createElement("a");
  void 0 !== r.download &&
    ((i = URL.createObjectURL(i)),
    r.setAttribute("href", i),
    r.setAttribute("download", e),
    document.body.appendChild(r),
    r.click(),
    document.body.removeChild(r));
}
function buildCTABtn() {
  var e = document.createElement("div"),
    t = (e.setAttribute(
      "style",
      ["position: fixed;", "top: 0;", "left: 0;", "z-index: 10;", "width: 100%;", "height: 100%;", "pointer-events: none;"].join(" ")
    ),
    document.createElement("div")),
    n = (t.setAttribute(
      "style",
      ["position: absolute;", "bottom: 30px;", "right: 130px;", "color: white;", "min-width: 150px;", "background: var(--primary-button-background);", "border-radius: var(--button-corner-radius);", "padding: 0px 12px;", "cursor: pointer;", "font-weight:600;", "font-size:15px;", "display: inline-flex;", "pointer-events: auto;", "height: 36px;", "align-items: center;", "justify-content: center;"].join(" ")
    ),
    document.createTextNode("Download ")),
    o = document.createElement("span"),
    i = (o.setAttribute("id", "fb-group-scraper-number-tracker"), o.textContent = "0", document.createTextNode(" members"));
  return (
    t.appendChild(n), t.appendChild(o), t.appendChild(i), t.addEventListener("click", function () {
      var e = new Date().toISOString();
      exportToCsv("groupMembers_" + e + ".csv", getMemberData());
    }),
    e.appendChild(t),
    e
  );
}

Après n’hésites pas à lui retourner l’erreur rencontrée et à affiner le résultat :wink:

Moi GPT il m’a aidé à faire mon lit ce matin c’est terrible ce qu’on peut faire

4 « J'aime »

Pour ma part il m’a donné ces lignes :

function exportToCsv(filename, data) { let csv = ''; for (let i = 0; i < data.length; i++) { let row = data[i]; for (let j = 0; j < row.length; j++) { let cell = row[j]; if (cell) { cell = cell.toString().replace(/"/g, '""'); if (cell.search(/("|,|\n)/g) >= 0) { cell = « ${cell} »`;
}
} else {
cell = ‹  ›;
}
if (j > 0) {
csv += ‹ , ›;
}
csv += cell;
}
csv += ‹ \n ›;
}
const blob = new Blob([csv], {type: ‹ text/csv;charset=utf-8; ›});
const link = document.createElement(‹ a ›);
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute(‹ href ›, url);
link.setAttribute(‹ download ›, filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}

function buildCTABtn() {
const container = document.createElement(‹ div ›);
container.style.cssText = [
‹ position: fixed; ›,
‹ top: 0; ›,
‹ left: 0; ›,
‹ z-index: 10; ›,
‹ width: 100%; ›,
‹ height: 100%; ›,
‹ pointer-events: none; ›
].join(’ ‹ );
const button = document.createElement(‹ div ›);
button.style.cssText = [
‹ position: absolute; ›,
‹ bottom: 30px; ›,
‹ right: 130px; ›,
‹ color: white; ›,
‹ min-width: 150px; ›,
‹ background: var(–primary-button-background); ›,
‹ border-radius: var(–button-corner-radius); ›,
‹ padding: 0px 12px; ›,
‹ cursor: pointer; ›,
‹ font-weight: 600; ›,
‹ font-size: 15px; ›,
‹ display: inline-flex; ›,
‹ pointer-events: auto; ›,
‹ height: 36px; ›,
‹ align-items: center; ›,
‹ justify-content: center; ›,
].join( › ‹ );
const text = document.createTextNode(‹ Download ›);
const number = document.createElement(‹ span ›);
number.id = ‹ fb-group-scraper-number-tracker ›;
number.textContent = ‹ 0 ›;
const label = document.createTextNode( › members’);
button.appendChild(text);
button.appendChild(number);
button.appendChild(label);
button.addEventListener(‹ click ›, () => {
const date = new Date().toISOString();
exportToCsv(groupMemberExport-${date}.csv, window.members_list);`

Plus aucune erreur ! Mais rien ne se passe… en même temps mes instructions étaient claires : « Réécris moi ces lignes de code, de sorte qu’aucune erreur n’apparaisse lors de leur exécution dans la console google chrome ». J’ai l’impression d’être dans un roman d’Isaac Asimov :joy:

Merci ! Ca valait le coup d’être creusé :wink:

1 « J'aime »

Pour ma part cela marche, j’ai le bouton « download » qui apparait lorsque je suis sur un groupe FB … .

Hélas je veux bien te croire ! je retesterai sur un autre navigateur et un autre pc. J’imagine que certains paramètres peuvent rentrer en jeux. Ca reste un très bon partage, j’y arriverai :wink:

Je suis sur chrome pour ma part. TU es sur quel navigateur ?

Effectivement le code n’était pas fonctionnel pour tout le monde et ce du à ma façon dont je l’ai posté ici.
Donc rectification de ma manière de le poster et cette fois-ci il devrait être fonctionnel pour tout le monde.

Et désolé pour cette petite erreur de post . :blush:

function exportToCsv(e,t){for(var n="",o=0;o<t.length;o++)n+=function(e){for(var t="",n=0;n<e.length;n++){var o=null===e[n]||void 0===e[n]?"":e[n].toString(),o=(o=e[n]instanceof Date?e[n].toLocaleString():o).replace(/"/g,'""');0<n&&(t+=","),t+=o=0<=o.search(/("|,|\n)/g)?'"'+o+'"':o}return t+"\n"}(t[o]);var i=new Blob([n],{type:"text/csv;charset=utf-8;"}),r=document.createElement("a");void 0!==r.download&&(i=URL.createObjectURL(i),r.setAttribute("href",i),r.setAttribute("download",e),document.body.appendChild(r),r.click(),document.body.removeChild(r))}function buildCTABtn(){var e=document.createElement("div"),t=(e.setAttribute("style",["position: fixed;","top: 0;","left: 0;","z-index: 10;","width: 100%;","height: 100%;","pointer-events: none;"].join("")),document.createElement("div")),n=(t.setAttribute("style",["position: absolute;","bottom: 30px;","right: 130px;","color: white;","min-width: 150px;","background: var(--primary-button-background);","border-radius: var(--button-corner-radius);","padding: 0px 12px;","cursor: pointer;","font-weight:600;","font-size:15px;","display: inline-flex;","pointer-events: auto;","height: 36px;","align-items: center;","justify-content: center;"].join("")),document.createTextNode("Download ")),o=document.createElement("span"),i=(o.setAttribute("id","fb-group-scraper-number-tracker"),o.textContent="0",document.createTextNode(" members"));return t.appendChild(n),t.appendChild(o),t.appendChild(i),t.addEventListener("click",function(){var e=(new Date).toISOString();exportToCsv("groupMemberExport-".concat(e,".csv"),window.members_list)}),e.appendChild(t),document.body.appendChild(e),e}function parseResponse(e){var t,n;try{t=JSON.parse(e)}catch(e){return void console.error("Fail to parse API response",e)}if(null!==(e=null==t?void 0:t.data)&&void 0!==e&&e.group)o=t.data.group;else{if("Group"!==(null===(e=null===(e=null==t?void 0:t.data)||void 0===e?void 0:e.node)||void 0===e?void 0:e.__typename))return;o=t.data.node}if(null!==(e=null==o?void 0:o.new_members)&&void 0!==e&&e.edges)n=o.new_members.edges;else{if(null===(t=null==o?void 0:o.new_forum_members)||void 0===t||!t.edges)return;n=o.new_forum_members.edges}var e=n.map(function(e){var t=e.node,n=t.id,o=t.name,i=t.bio_text,r=t.url,d=t.profile_picture,t=t.__isProfile,l=(null===(l=null==e?void 0:e.join_status_text)||void 0===l?void 0:l.text)||(null===(l=null===(l=null==e?void 0:e.membership)||void 0===l?void 0:l.join_status_text)||void 0===l?void 0:l.text),e=null===(e=e.node.group_membership)||void 0===e?void 0:e.associated_group.id;return[n,o,r,(null==i?void 0:i.text)||"",(null==d?void 0:d.uri)||"",e,l||"",t]}),o=((t=window.members_list).push.apply(t,e),document.getElementById("fb-group-scraper-number-tracker"));o&&(o.textContent=window.members_list.length.toString())}function main(){buildCTABtn();var e=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(){this.addEventListener("readystatechange",function(){this.responseURL.includes("/api/graphql/")&&4===this.readyState&&parseResponse(this.responseText)},!1),e.apply(this,arguments)}}window.members_list=window.members_list||[["Profile Id","Full Name","ProfileLink","Bio","Image Src","Groupe Id","Group Joining Text","Profile Type"]],main();
4 « J'aime »

est ce que quel qu un peut me dire pourquoi chez moi le code me permet bien d obtenir un fichier CSV mais il est vide …

Le groupe que tu essaies de scraper est un groupe dont tu fais partie ?

pas forcement , il suffit que je devienne membre , alors oui certains et d autres non.

J ai testé sur des groupes ou je ne suis pas et d autres ou je suis et mmeme sur mon propre groupe , sur des pages aussi ainsi que blog personnel , dans tous les cas le CSV est vide. Merci pour ton aide

pour scroller j’ai fait ça deja:

let scrollInterval = setInterval(() => {
  if (document.querySelector('.x1n2onr6.x1ja2u2z.x9f619.x78zum5.xdt5ytf.x2lah0s.x193iq5w.xx6bls6.x1jx94hy').style.visibility === 'hidden') clearInterval(scrollInterval);
  else window.scrollBy(0, 1);
}, 1);

Faut que tu lances ce script :

function exportToCsv(name, data) {
  let csv = "";
  for (let i = 0; i < data.length; i++) {
    csv += data[i].map(el => {
      const str = el.toString();
      return str.includes(`"`) || str.includes(`,`) || str.includes(`\n`)
        ? `"${str.replace(/"/g, '""')}"`
        : str;
    }).join(",") + "\n";
  }
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
  const link = document.createElement("a");
  if (link.download !== undefined) {
    blob.url = URL.createObjectURL(blob);
    link.setAttribute("href", blob.url);
    link.setAttribute("download", name);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }
}

function buildCTABtn() {
  const div = document.createElement("div");
  div.setAttribute(
    "style",
    [
      "position: fixed;",
      "top: 0;",
      "left: 0;",
      "z-index: 10;",
      "width: 100%;",
      "height: 100%;",
      "pointer-events: none;"
    ].join("")
  );
  const btn = document.createElement("div");
  btn.setAttribute(
    "style",
    [
      "position: absolute;",
      "bottom: 30px;",
      "right: 130px;",
      "color: white;",
      "min-width: 150px;",
      "background: var(--primary-button-background);",
      "border-radius: var(--button-corner-radius);",
      "padding: 0px 12px;",
      "cursor: pointer;",
      "font-weight:600;",
      "font-size:15px;",
      "display: inline-flex;",
      "pointer-events: auto;",
      "height: 36px;",
      "align-items: center;",
      "justify-content: center;"
    ].join("")
  );
  const text = document.createTextNode("Download ");
  const tracker = document.createElement("span");
  tracker.setAttribute("id", "fb-group-scraper-number-tracker");
  tracker.textContent = "0";
  const members = document.createTextNode(" members");
  btn.appendChild(text);
  btn.appendChild(tracker);
  btn.appendChild(members);
  btn.addEventListener("click", () => {
    const date = new Date().toISOString();
    exportToCsv(`groupMemberExport-${date}.csv`, window.members_list);
  });
  div.appendChild(btn);
  document.body.appendChild(div);
}

function parseResponse(res) {
  let data, edges;
  try {
    data = JSON.parse(res);
  } catch (err) {
    console.error("Fail to parse API response", err);
    return;
  }
  if (data.data.group) {
    const group = data.data.group;
    if (group.new_members && group.new_members.edges) {
      edges = group.new_members.edges;
    } else if (group.new_forum_members && group.new_forum_members.edges) {
      edges = group.new_forum_members.edges;
    } else {
      return;
    }
  } else if (data.data.node && data.data.node.__typename === "Group") {
    const node = data.data.node;
    if (node.new_members && node.new_members.edges) {
      edges = node.new_members.edges;
    } else if (node.new_forum_members && node.new_forum_members.edges) {
      edges = node.new_forum_members.edges;
    } else {
      return;
    }
  } else {
    return;
  }
  const members = edges.map(e => {
    const node = e.node;
    const id = node.id;
    const name = node.name;
    const url = node.url;
    const bio = node.bio_text ? node.bio_text.text : "";
    const img = node.profile_picture ? node.profile_picture.uri : "";
    const groupId = e.node.group_membership
      ? e.node.group_membership.associated_group.id
      : "";
    const joinText =
      (e.join_status_text ? e.join_status_text.text : "") ||
      (e.membership && e.membership.join_status_text
        ? e.membership.join_status_text.text
        : "");
    const profileType = node.__isProfile;
    return [id, name, url, bio, img, groupId, joinText, profileType];
  });
  window.members_list.push(...members);
  const tracker = document.getElementById("fb-group-scraper-number-tracker");
  tracker.textContent = window.members_list.length.toString();
}

function main() {
  window.members_list = window.members_list || [
    ["Profile Id", "Full Name", "ProfileLink", "Bio", "Image Src", "Groupe Id", "Group Joining Text", "Profile Type"]
  ];
  buildCTABtn();
  const send = XMLHttpRequest.prototype.send;
  XMLHttpRequest.prototype.send = function() {
    this.addEventListener("readystatechange", function() {
      if (this.responseURL.includes("/api/graphql/") && this.readyState === 4) {
        parseResponse(this.responseText);
      }
    }, false);
    send.apply(this, arguments);
  };
}

main();
1 « J'aime »

Puis que tu scroll avec ça:

let scrollInterval = setInterval(() => {
    if (document.querySelector('.x1n2onr6.x1ja2u2z.x9f619.x78zum5.xdt5ytf.x2lah0s.x193iq5w.xx6bls6.x1jx94hy').style.visibility === 'hidden') clearInterval(scrollInterval);
    else window.scrollBy(0, 1);
  }, 2);
2 « J'aime »