UNPKG

instamancer

Version:

Scrape the Instagram API with Puppeteer

520 lines 35.5 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const aws = __importStar(require("aws-sdk")); const fs = __importStar(require("fs")); const readline = __importStar(require("readline")); const winston = __importStar(require("winston")); const path = __importStar(require("path")); const uuid_1 = require("uuid"); const plugins = __importStar(require("../plugins")); const api_1 = require("./api/api"); const getPool_1 = require("./getpool/getPool"); const depotUpload = __importStar(require("./http/depot")); const download_1 = require("./http/download"); const s3Upload = __importStar(require("./http/s3")); const getLogger = (args) => { const transports = []; if (args["logging"] !== "none") { transports.push(new winston.transports.File({ filename: args["logfile"], level: args["logging"], silent: args["logging"] === "none", })); } return winston.createLogger({ level: args["logging"], silent: args["logging"] === "none", transports, }); }; function getOptions(args, logger) { const options = { enableGrafting: args["graft"], executablePath: args["browser"], fullAPI: args["full"], headless: !args["visible"], logger, plugins: [], sameBrowser: args["sameBrowser"], silent: args["quiet"], sleepTime: args["sleep"], strict: args["strict"], total: args["count"], }; for (const pluginName of args["plugin"]) { if (plugins.plugins[pluginName]) { options.plugins.push(new plugins.plugins[pluginName]()); } else { throw new Error("Couldn't find plugin " + pluginName); } } return options; } /** * Build argument parser */ function buildParser(args, callback) { /* tslint:disable:no-unused-expression */ require("yargs")(args) .usage("Usage: $0 <command> [options]") .command("hashtag [id]", "Scrape a hashtag", {}, async (handleArgs) => { await spawn(handleArgs); callback(); }) .command("user [id]", "Scrape a users posts", {}, async (handleArgs) => { await spawn(handleArgs); callback(); }) .command("post [ids]", "Scrape a comma-separated list of posts", {}, async (handleArgs) => { await spawn(handleArgs); callback(); }) .command("search [query]", "Perform a search of users, tags and places", {}, async (handleArgs) => { const logger = getLogger(handleArgs); const options = getOptions(handleArgs, logger); if (!handleArgs["query"]) { throw new Error("query required"); } const search = api_1.createApi("search", handleArgs["query"], options); const result = await search.get(); process.stdout.write("\n"); process.stdout.write(JSON.stringify(result, null, 2)); process.stdout.write("\n"); callback(); }) .command("batch [batchfile]", "Read newline-separated arguments from a file", {}, () => { // A list of functions which create new Promises that are // resolved by buildParser when the spawn commands are // finished // See https://stackoverflow.com/a/45951080/7435520 const functions = []; // Read the list of commands from file readline .createInterface({ crlfDelay: Infinity, input: fs.createReadStream(args[1]), }) .on("line", // For each line, create a new function which // creates a new promise to be resolved by // buildParser (line) => { if (line.length > 0 && line.charAt(0) !== "#") { functions.push(() => new Promise((res) => buildParser(line, res))); } }) .on("close", // When all lines have been read, synchronously // execute the commands by waiting for their // promises to be resolved async () => { for (const f of functions) { await f(); } process.exit(); }); }) /* tslint:disable:object-literal-sort-keys */ .options({ count: { alias: "c", number: true, default: 0, describe: "Number of posts to download (0 for all)", group: "Configuration", }, full: { alias: ["f"], boolean: true, default: false, describe: "Retrieve full post data", group: "Configuration", }, sleep: { alias: ["s"], number: true, default: 2, describe: "Seconds to sleep between interactions", group: "Configuration", }, graft: { alias: "g", boolean: true, default: true, describe: "Enable grafting", group: "Configuration", }, browser: { alias: ["b"], string: true, default: undefined, describe: "Browser path. Defaults to the puppeteer version", group: "Configuration", }, sameBrowser: { boolean: true, default: false, describe: "Use a single browser when grafting", group: "Configuration", }, download: { alias: "d", boolean: true, default: false, describe: "Save images from posts", group: "Download", }, downdir: { default: "downloads/[endpoint]/[id]", describe: "Download path", group: "Download", }, video: { alias: "v", boolean: true, default: false, describe: "Download videos (requires full)", implies: "full", group: "Download", }, sync: { boolean: true, default: false, describe: "Force download between requests", group: "Download", }, threads: { alias: "k", number: true, default: 4, describe: "Parallel download / depot threads", group: "Download", }, waitDownload: { alias: "w", boolean: true, default: false, describe: "Download media after scraping", group: "Download", }, bucket: { string: true, default: undefined, describe: "Upload files to an AWS S3 bucket", group: "Upload", }, depot: { string: true, default: undefined, describe: "Upload files to a URL with a PUT request (depot)", group: "Upload", }, file: { alias: ["o"], string: true, default: "[id]", describe: "Output filename. '-' for stdout", group: "Output", }, type: { alias: ["t"], default: "json", describe: "Filetype", choices: ["csv", "json", "both"], group: "Output", }, mediaPath: { alias: ["m"], boolean: true, default: false, describe: "Add filepaths to _mediaPath", group: "Output", }, visible: { boolean: true, default: false, describe: "Show browser on the screen", group: "Display", }, quiet: { alias: ["q"], boolean: true, default: false, describe: "Disable progress output", group: "Display", }, logging: { alias: ["l"], default: "none", choices: ["none", "error", "info", "debug"], group: "Logging", }, logfile: { string: true, default: "instamancer.log", describe: "Log file name", group: "Logging", }, strict: { boolean: true, default: false, describe: "Throw an error on response type mismatch", group: "Validation", }, plugin: { alias: ["p"], array: true, default: [], describe: "Use a plugin from the plugins directory", group: "Plugins", }, }) .demandCommand() .example("$0 hashtag instagood -fvd", "Download all the available posts, and their media from #instagood") .example("$0 user arianagrande --type=csv --logging=info --visible", "Download Ariana Grande's posts to a CSV file with a non-headless browser, and log all events") .epilog("Source code available at https://github.com/ScriptSmith/instamancer") .strict().argv; /* tslint:enable:no-unused-expression */ } /** * Spawn an instance of the API * @param args */ async function spawn(args) { // Initiate logger const logger = getLogger(args); // Check id if (!(args["id"] || args["ids"])) { throw new Error("Id required"); } // Pick endpoint let ids; if (args["_"][0] === "post") { ids = args["ids"].split(","); args["id"] = ids.length === 1 ? ids[0] : "posts"; args["full"] = true; } else { ids = args["id"]; } // Define options const options = getOptions(args, logger); // Replace downdir const downdir = args["downdir"] .replace("[id]", args["id"]) .replace("[endpoint]", args["_"]); // Replace depot url let depotUrl = args["depot"]; if (depotUrl && depotUrl.includes("[uuid]")) { depotUrl = depotUrl.replace("[uuid]", uuid_1.v4()); if (!args["quiet"]) { process.stdout.write(depotUrl + "\n"); } } // Get s3 bucket const s3Bucket = args["bucket"]; // Check if outputting to stdout const printOutput = args["file"] === "-"; // Connect to object storage let downloadUpload; let toCSVFunc = download_1.toCSV; let toJSONFunc = download_1.toJSON; if (depotUrl) { // Depot const depotConfig = { directory: downdir, url: depotUrl, logger, }; downloadUpload = depotUpload.depot.bind(depotConfig); toCSVFunc = depotUpload.toCSV.bind(depotConfig); toJSONFunc = depotUpload.toJSON.bind(depotConfig); } else if (s3Bucket) { // s3 const s3Config = { bucket: s3Bucket, directory: downdir, s3: new aws.S3(), logger, }; downloadUpload = s3Upload.s3.bind(s3Config); toCSVFunc = s3Upload.toCSV.bind(s3Config); toJSONFunc = s3Upload.toJSON.bind(s3Config); } else { // Download downloadUpload = download_1.download.bind({ directory: downdir, logger, }); } // Start API logger.info("Starting API at " + Date.now()); const obj = api_1.createApi(args["_"][0], ids, options); await obj.start(); // Start download pool const getPool = new getPool_1.GetPool(args["threads"], downloadUpload); // Pick between synchronous and parallel downloads const downloadFunction = args["sync"] ? downloadUpload : getPool.add.bind(getPool); // Add pause callback function handleKeypress(str, key) { if (key.name === "space") { obj.pause(); } else if (key.name === "c" && key.ctrl) { process.stdout.write("\n"); process.kill(process.pid, "SIGINT"); } } process.stdin.on("keypress", handleKeypress); // Array of urls and filenames let downloadMedia = []; // Download posts const posts = []; for await (const post of obj.generator()) { // Add _mediaPath key if (args["mediaPath"]) { post["_mediaPath"] = []; } // Identify download urls if (args["download"] && ("node" in post || "shortcode_media" in post)) { // Check the scraping level if (args["full"]) { // Check if album const postObject = post; const children = postObject.shortcode_media.edge_sidecar_to_children; if (children !== undefined) { for (const child of children.edges) { const shortcode = child.node.shortcode; // Check if video let mediaUrl; let mediaType; if (child.node.is_video && args["video"]) { mediaUrl = child.node.video_url; mediaType = FILETYPES.VIDEO; } else { mediaUrl = child.node.display_resources.pop().src; mediaType = FILETYPES.IMAGE; } saveMediaMetadata(post, args, downloadMedia, downdir, mediaUrl, shortcode, mediaType); } } else { const shortcode = postObject.shortcode_media.shortcode; // Check if video let mediaUrl; let mediaType; if (postObject.shortcode_media.is_video && args["video"]) { mediaUrl = postObject.shortcode_media.video_url; mediaType = FILETYPES.VIDEO; } else { mediaUrl = postObject.shortcode_media.display_resources.pop() .src; mediaType = FILETYPES.IMAGE; } saveMediaMetadata(post, args, downloadMedia, downdir, mediaUrl, shortcode, mediaType); } } else { const postObject = post; saveMediaMetadata(post, args, downloadMedia, downdir, postObject.node.thumbnail_src, postObject.node.shortcode, FILETYPES.IMAGE); } } // Save post posts.push(post); // Output if required if (printOutput) { process.stdout.write(JSON.stringify(post, null, 2) + "\n"); } // Download the identified media if (!args["waitDownload"]) { for (const asset of downloadMedia) { await downloadFunction(...asset); } downloadMedia = []; } } // Download remaining media for (const asset of downloadMedia) { await downloadFunction(...asset); } // Close download pool await new Promise((resolve) => { getPool.close(resolve); }); await Promise.all(getPool.promises); // Replace filename const filename = args["file"] .replace("[id]", args["id"]) .replace("[endpoint]", args["_"]); // Save file if (!printOutput) { if (args["type"] !== "json") { let saveFile = filename; if (args["type"] === "both" || args["file"] === "[id]") { saveFile += ".csv"; } await toCSVFunc(posts, saveFile); } if (args["type"] !== "csv") { let saveFile = filename; if (args["type"] === "both" || args["file"] === "[id]") { saveFile += ".json"; } await toJSONFunc(posts, saveFile); } } // Remove pause callback process.stdin.removeAllListeners("keypress"); // Close logger logger.close(); } function saveMediaMetadata(post, args, downloadMedia, downDir, url, shortcode, fileType) { if (args["mediaPath"]) { let uri = path.join(downDir, shortcode + "." + fileType); uri = args["swift"] ? "swift://" + uri : uri; post["_mediaPath"].push(uri); } downloadMedia.push([url, shortcode, fileType]); } // Catch key presses readline.emitKeypressEvents(process.stdin); if ("setRawMode" in process.stdin) { process.stdin.setRawMode(true); } // Parse args buildParser(process.argv.slice(2), () => { process.exit(0); }); var FILETYPES; (function (FILETYPES) { FILETYPES["VIDEO"] = "mp4"; FILETYPES["IMAGE"] = "jpg"; })(FILETYPES || (FILETYPES = {})); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2xpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQSw2Q0FBK0I7QUFDL0IsdUNBQXlCO0FBQ3pCLG1EQUFxQztBQUNyQyxpREFBbUM7QUFFbkMsMkNBQTZCO0FBQzdCLCtCQUFnQztBQUNoQyxvREFBc0M7QUFDdEMsbUNBQThDO0FBRTlDLCtDQUEwQztBQUMxQywwREFBNEM7QUFDNUMsOENBQXdEO0FBQ3hELG9EQUFzQztBQUV0QyxNQUFNLFNBQVMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFO0lBQ3ZCLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUN0QixJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxNQUFNLEVBQUU7UUFDNUIsVUFBVSxDQUFDLElBQUksQ0FDWCxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO1lBQ3hCLFFBQVEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQ3pCLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQ3RCLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssTUFBTTtTQUNyQyxDQUFDLENBQ0wsQ0FBQztLQUNMO0lBQ0QsT0FBTyxPQUFPLENBQUMsWUFBWSxDQUFDO1FBQ3hCLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO1FBQ3RCLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssTUFBTTtRQUNsQyxVQUFVO0tBQ2IsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDO0FBRUYsU0FBUyxVQUFVLENBQUMsSUFBSSxFQUFFLE1BQU07SUFDNUIsTUFBTSxPQUFPLEdBQWE7UUFDdEIsY0FBYyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDN0IsY0FBYyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDL0IsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFN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