-
-
Save torohima/4978c845158db6eb6337e76f28f16378 to your computer and use it in GitHub Desktop.
Download all photos from facebook Page
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(async () => { | |
function sleep(ms) { | |
return new Promise((resolve) => setTimeout(resolve, ms)); | |
} | |
function findToken() { | |
const tags = Array.from( | |
document.body.querySelectorAll("script:not([src])") | |
); | |
let fb_dtsg = ""; | |
let id = ""; | |
for (const tag of tags) { | |
let matches = tag.textContent.match( | |
/"token":"([a-zA-Z0-9_-]+):([0-9]+):([0-9]+)"/ | |
); | |
if (matches) { | |
fb_dtsg = `${matches[1]}:${matches[2]}:${matches[3]}`; | |
matches = tag.textContent.match(/"pageID":"([0-9]+)"/); | |
if (matches) { | |
id = matches[1]; | |
break; | |
} else { | |
matches = tag.textContent.match( | |
/"rawSectionToken":"([0-9]+):([0-9]+)"/ | |
); | |
if (matches) { | |
id = btoa(`app_collection:${matches[1]}:${matches[2]}:5`); | |
break; | |
} | |
} | |
} | |
} | |
return { fb_dtsg, id }; | |
} | |
async function findDocId(method) { | |
const regex = new RegExp( | |
`__d\\("${method}\\.graphql"(.*)params:\\{id:"([0-9]+)"` | |
); | |
const promises = await Promise.all( | |
Array.from( | |
document.head.querySelectorAll( | |
'script[crossorigin="anonymous"][async="1"][src]' | |
) | |
).map((tag) => { | |
return fetch(tag.getAttribute("src")) | |
.then((response) => response.text()) | |
.then((content) => { | |
return content.match(regex); | |
}); | |
}) | |
); | |
return promises.find((item) => !!item)[2]; | |
} | |
async function getLinks( | |
{ fb_dtsg, id, doc_id, isPage, method }, | |
cursor = null | |
) { | |
const variables = isPage | |
? `{"count":10,"cursor":${cursor},"scale":4,"id":"${id}"}` | |
: `{"count":8,"cursor":${cursor},"scale":1,"id":"${id}"}`; | |
const data = { | |
doc_id, // __d\("PagesCometPhotosTabMainViewAllPhotosSectionPaginationQuery\.graphql"(.*)params:\{id:"([0-9]+)" | |
fb_dtsg, // "token":"([a-zA-Z0-9]+):([0-9]+):([0-9]+)" | |
variables, | |
fb_api_caller_class: "RelayModern", | |
fb_api_req_friendly_name: method, | |
}; | |
const formBody = []; | |
for (const property in data) { | |
const encodedKey = encodeURIComponent(property); | |
const encodedValue = encodeURIComponent(data[property]); | |
formBody.push(encodedKey + "=" + encodedValue); | |
} | |
return fetch("https://www.facebook.com/api/graphql/", { | |
headers: { | |
"content-type": "application/x-www-form-urlencoded", | |
"user-agent": | |
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", | |
"x-fb-friendly-name": method, | |
}, | |
body: formBody.join("&"), | |
method: "POST", | |
}) | |
.then((response) => response.json()) | |
.then(({ data }) => { | |
if (isPage) { | |
return { | |
images: data.node.allPhotos.edges.map((item) => { | |
return { | |
...item.node.image, | |
...item.node.viewer_image, | |
}; | |
}), | |
page: data.node.allPhotos.page_info, | |
}; | |
} | |
return { | |
images: data.node.pageItems.edges.map( | |
(item) => item.node.node.viewer_image | |
), | |
page: data.node.pageItems.page_info, | |
}; | |
}); | |
} | |
window.scrollTo(0, document.body.scrollHeight); | |
await sleep(1000); | |
let cursor = null; | |
const limit = +prompt("Số link tối đa sẽ lấy", "999999") || 999999; | |
window.allImages = []; | |
const { fb_dtsg, id } = findToken(); | |
const isPage = !!id.match(/^([0-9]+)$/); | |
const method = isPage | |
? "PagesCometPhotosTabMainViewAllPhotosSectionPaginationQuery" | |
: "ProfileCometAppCollectionPhotosRendererPaginationQuery"; | |
const doc_id = await findDocId(method); | |
if (!fb_dtsg || !doc_id) { | |
throw new Error("Không tìm thấy token"); | |
} | |
console.log("%cBắt đầu lấy link", "color: green;"); | |
while (true) { | |
let { images, page } = await getLinks( | |
{ fb_dtsg, id, doc_id, isPage, method }, | |
cursor ? `"${cursor}"` : null | |
); | |
window.allImages.push(...images); | |
console.log("%cĐã lấy được %d link ảnh", "color: green;", window.allImages.length); | |
// await sleep(1000); // sleep 1s | |
if (!page.has_next_page) { | |
break; | |
} | |
cursor = page.end_cursor; | |
if (++window.allImages.length > limit) { | |
break; | |
} | |
} | |
console.log(window.allImages); | |
const styles = ["color: green", "font-size: 20px", "padding: 10px"].join(";"); | |
console.log( | |
"%cĐã lấy thành công %d link ảnh, gõ copy(window.allImages.map(({ uri }) => uri).join('\\n')) để sao chép links vào clipboard", | |
styles, | |
window.allImages.length | |
); | |
})().catch((error) => { | |
console.log(error); | |
alert("Vui lòng tải lại trang và thử lại."); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment