Zpět na hlavní stránku

Scrape Instagramu bez Graph API

Přidal Filip Kalousek dne

Úvod

Jeden klient z roku 2019 chtěl mít fotky z Instagramu na svém webu, v té době bylo dostupné ještě Instagram Developer API přímo pod Instagramem, jenže cca. po roce se Facebook rozhodl hodit veškeré API endpointy pod sebe, tím dostal hodně webů do slepé uličky, začaly být populární knihovny třetích stran, které nabízely celý produkt jako Widget, počet webů sloužících na scrape fotek se také zvyšoval.

Dnes Vám ukážu řešení jak si "scrapnout" obrázek aniž byste řešili věci jako:

  • Cors Policy
  • Expirace obrázku
  • Tokeny od Instagramu

Je důležité, aby profil na který cílíme byl veřejný.

Jak na to?

Založíme si profil na Apify a v Administraci v sekci Store si přidáme Actor Instagram Post Scraper

Stažení Instagram Post Scraper

Co jsou actors?

Actors jsou bezserverové cloudové programy běžící na platformě Apify, které mohou provádět libovolné výpočetní úlohy, jako je odeslání e-mailu nebo procházení webových stránek s miliony stránek. Lze je spouštět ručně, pomocí našeho rozhraní API nebo plánovače a lze je snadno integrovat s jinými aplikacemi.

Nastavíme actora

Nastavíme ho tím, že vložíme:

  • název profilu
  • počet vybraných příspěvků

Uložíme předdefinované hodnoty a poté spustíme proces tlačítkem start

Uložení Instagram Post Scraper

Výsledkem bude toto:

Výsledky Instagram Post Scraper

Pokud budeme chtít koncový endpoint odkaz, kterým budeme získavat data na serveru, klikneme zpět v menu na na tlačítko Saved Tasks, kliknete na Váš uloženy task a vpravo nahoře se ukáže tlačítko API po rozkliknutí dostaneme sadu endpointů, ta kterou budeme potřebovat se nazývá Get last run dataset items, zkopírujeme odkaz a jdeme dále.

Výsledky Instagram Post Scraper

Fresh

Jistě už víte jak funguje Fresh, pokud ne mrkněte.

Nastavíme v routes novou cestu

Název je zcela na Vás, já ji pojmenoval image.ts.

Vložíme následují kód který si z parametru veme odkaz na obrázek, který budeme volat, tento krok je důležitý, protože bez něj bychom nemohli si zobrazit obrázky, klient by nám vypověděl Cross Origin Policy.

import { HandlerContext } from "$fresh/server.ts";

export const handler = async (_req: Request, _ctx: HandlerContext) => {
  const url = _req.url.substring(_req.url.indexOf("?image=") + "?image=".length);

  if (!url)
    return new Response("Internal server error", {
      status: 500,
    });

  const image = await fetch(url);
  const blob = await image.blob();
  const buffer = await blob.arrayBuffer();

  // Jen na okrasu pro pagespeed.web.dev vložíme webp,
  // aby neprskal, jinak doporučuji dát image/jpeg
  const headers = new Headers({
    "Content-Type": "image/webp",
    "Cache-Control": "public, max-age=3600"
  });
  return new Response(buffer, {
    headers
  });
};

Na libovolné stráce v mém případě index.ts si vložím následující kód:

import { Head } from "$fresh/runtime.ts";
import { Handlers, PageProps } from "$fresh/server.ts";

interface IPostModel {
  url: string;
  displayUrl: string;
  type: string;
  caption: string;
  timestamp: string;
}

interface InstagramProps {
  instagram: IPostModel[];
}

export const handler: Handlers<InstagramProps | null> = {
  async GET(_, ctx) {
    const url =
      "<vase_adresa>";
    const apify = await fetch(url);
    const data: IPostModel[] = await apify.json();

    try {
      // data si otočíme aby byly od nejnovějších po nejstarší
      const res = { instagram: data.reverse()};
      return ctx.render(res);
    } catch (error) {
      return ctx.render({ instagram: [] });
    }
  },
};

export default function Home({ data }: PageProps<InstagramProps | null>) {
  return (
    <>
      <Head>
        <title>Image Post Scraper</title>
      </Head>
      <div class="p-4 mx-auto max-w-screen-md">
        {data && data.instagram &&
          (
            <ul class="container grid grid-cols-3 gap-2 mx-auto">
              {data.instagram.map((post) => {
                return <Post {...post} />;
              })}
            </ul>
          )}
      </div>
    </>
  );
}

function Post(post: IPostModel) {
  return (
    <li class="w-full rounded">
      <img src={`api/image?image=${post.displayUrl}`} alt={post.caption} />
    </li>
  );
}

HURÁ FUNGUJE TO!

Stránka Instagram Post Scraper

Jak proces automatizovat?

V sekci, kde jsme získavali endpoint u Apify si rozklikneme dropdown a klikneme na Schedule, potom už je na vás jaký interval budete upřednostňovat, výhoda u Apify je že máte na free tier $5 zdarma, které se každý měsíc obnovují, takže na osobní potřeby pecka.

Já si nastavil každé pondělí a pátek, aby nevypršela signature u displayUrl.

Výhoda je, že po automatizaci nemusíme měnit link na klientu (v tomto případě je klient server, na dynamickým klientu nedoporučuji dávat veřejný API klíč), takže se nám vždy obnoví.

Automatizace Instagram Post Scraper