PHPackages                             tsmedia/laravel-instagram-scraper - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tsmedia/laravel-instagram-scraper

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tsmedia/laravel-instagram-scraper
=================================

Laravel package voor het scrapen van publieke Instagram-profielen (eigen namespace, Guzzle 7 / PSR-18).

013PHP

Since May 15Pushed 2mo agoCompare

[ Source](https://github.com/TS-MediaNL/laravel-instagram-scraper)[ Packagist](https://packagist.org/packages/tsmedia/laravel-instagram-scraper)[ RSS](/packages/tsmedia-laravel-instagram-scraper/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Instagram Scraper
=========================

[](#laravel-instagram-scraper)

Een Laravel package om **publieke** Instagram-profielen te scrapen via HTTP.
Gebouwd op **Laravel's eigen HTTP client** (PSR-18 adapter), met automatische retry, proxy-ondersteuning en volledige integratie in het Laravel service-container systeem.

---

Vereisten
---------

[](#vereisten)

VereisteVersiePHP^8.2Laravel^11.0 | ^12.0ext-json\*ext-curl\*---

Installatie
-----------

[](#installatie)

```
composer require tsmedia/laravel-instagram-scraper
```

Laravel registreert de service provider en de `InstagramProfile` facade automatisch via package auto-discovery.

### Config publiceren (optioneel)

[](#config-publiceren-optioneel)

```
php artisan vendor:publish --tag=instagram-scraper-config
```

Dit plaatst `config/instagram-scraper.php` in je project zodat je alle opties kunt aanpassen.

---

Configuratie
------------

[](#configuratie)

Voeg de gewenste waarden toe aan je `.env`:

```
# Timeouts (seconden)
INSTAGRAM_SCRAPER_TIMEOUT=60
INSTAGRAM_SCRAPER_CONNECT_TIMEOUT=15

# Automatische retry bij fouten
INSTAGRAM_SCRAPER_RETRY_MAX=3          # Totaal aantal pogingen (1 = geen retry)
INSTAGRAM_SCRAPER_RETRY_DELAY_MS=1000  # Basisvertraging in ms (wordt verdubbeld per poging)

# Optioneel: vaste user-agent
INSTAGRAM_SCRAPER_USER_AGENT=

# Optioneel: HTTP proxy
INSTAGRAM_SCRAPER_PROXY=http://user:pass@proxy.example.com:8080

# Optioneel: authenticatie (zie sectie hieronder)
INSTAGRAM_SCRAPER_SESSION_ID=
INSTAGRAM_SCRAPER_USERNAME=
INSTAGRAM_SCRAPER_PASSWORD=
```

---

Authenticatie (optioneel maar aanbevolen)
-----------------------------------------

[](#authenticatie-optioneel-maar-aanbevolen)

Zonder authenticatie werkt de package publiek via de `web_profile_info` endpoint. Dit geeft:

- Profiel-informatie (volgers, bio, etc.)
- Maximaal ~12 recentste grid-posts

Met een ingelogde sessie zijn ook beschikbaar:

- Meer dan 12 posts (paginering)
- Reels en trial reels
- Privé-profielen (als je ze volgt)

### Methode 1 — Session ID (aanbevolen)

[](#methode-1--session-id-aanbevolen)

Dit is de stabielste aanpak: geen wachtwoord in je `.env`, werkt met 2FA-accounts en is moeilijker te detecteren door Instagram.

**Hoe haal je de session ID op:**

1. Open [instagram.com](https://www.instagram.com) in je browser en log in
2. Open DevTools (`F12`) → **Application** → **Cookies** → `https://www.instagram.com`
3. Zoek de cookie met de naam **`sessionid`**
4. Kopieer de waarde en zet hem in je `.env`:

```
INSTAGRAM_SCRAPER_SESSION_ID=54524509719%3AaBcDeFgHiJkLmN%3A12%3AAbCdEfGhIjKlMnOpQrStUvWxYz
```

De sessie is geldig totdat je uitlogt of na ±90 dagen. Gebruik een apart scraper-account, niet je persoonlijke account.

### Methode 2 — Username + Password

[](#methode-2--username--password)

De package logt automatisch in bij de eerste request en cachet de sessie.

```
INSTAGRAM_SCRAPER_USERNAME=mijn_scraper_account
INSTAGRAM_SCRAPER_PASSWORD=mijn_wachtwoord
```

> **Let op**: Werkt niet bij accounts met twee-factor-authenticatie (2FA). Instagram kan inlogpogingen ook blokkeren bij verdacht gebruik.

### Handmatig inloggen (runtime)

[](#handmatig-inloggen-runtime)

Je kunt ook buiten de config om inloggen, bijvoorbeeld als je meerdere accounts wilt rouleren:

```
use TsMedia\LaravelInstagramScraper\Facades\InstagramProfile;

// Met session ID
InstagramProfile::loginWithSessionId('jouw_session_id');

// Of met username + password
InstagramProfile::login();

// Check of je ingelogd bent
if (InstagramProfile::isLoggedIn()) {
    // ...
}
```

---

### Retry-gedrag

[](#retry-gedrag)

De retry gebruikt **exponentiële backoff**: bij 3 pogingen en 1000ms basisvertraging zijn de wachttijden 1s → 2s → 4s.
Standaard wordt opnieuw geprobeerd bij statuscodes: `429`, `500`, `502`, `503`, `504` en bij verbindingsfouten.

---

Package testen (smoke / live)
-----------------------------

[](#package-testen-smoke--live)

In de **root van deze repository** (na `composer install`):

```
# Alleen unit-tests (geen live Instagram)
composer test

# Live smoke-test (HTTP naar instagram.com; kan skippen bij 400/429 enz.)
composer test:network
```

Of met een andere publieke gebruikersnaam:

```
php scripts/smoke-test.php nasa
```

De variabele `INSTAGRAM_SMOKE_USERNAME` (via tweede argument in `smoke-test.php`) bepaalt welk account wordt opgevraagd; standaard is `instagram`.

### In een Laravel-app (na `composer require`)

[](#in-een-laravel-app-na-composer-require)

```
php artisan instagram-scraper:test
php artisan instagram-scraper:test --username=nasa --timeline
```

---

Gebruik
-------

[](#gebruik)

### Via de `InstagramProfile` facade

[](#via-de-instagramprofile-facade)

De makkelijkste manier — gebruik dit in controllers, jobs en commands:

```
use TsMedia\LaravelInstagramScraper\Facades\InstagramProfile;

// Accountinformatie ophalen
$account = InstagramProfile::accountByUsername('nasa');

echo $account->getUsername();       // nasa
echo $account->getFullName();       // NASA
echo $account->getBiography();      // Explore the universe...
echo $account->getFollowersCount(); // 97000000
echo $account->getMediaCount();     // 4200
echo $account->getProfilePicUrl();  // https://...
echo $account->isPrivate();         // false
echo $account->isVerified();        // true
```

### Via dependency injection

[](#via-dependency-injection)

Aanbevolen in services en repositories — beter testbaar:

```
use TsMedia\LaravelInstagramScraper\InstagramProfileClient;

class InstagramService
{
    public function __construct(
        private readonly InstagramProfileClient $instagram,
    ) {}

    public function getProfile(string $username): array
    {
        $account = $this->instagram->accountByUsername($username);

        return [
            'username'   => $account->getUsername(),
            'followers'  => $account->getFollowersCount(),
            'is_private' => $account->isPrivate(),
        ];
    }
}
```

---

Alle beschikbare methoden
-------------------------

[](#alle-beschikbare-methoden)

### `accountByUsername(string $username): Account`

[](#accountbyusernamestring-username-account)

Haal volledig account op via gebruikersnaam. Gooit `InstagramNotFoundException` als het account niet bestaat.

```
$account = InstagramProfile::accountByUsername('natgeo');

$account->getId();               // numerieke user-ID (string)
$account->getUsername();
$account->getFullName();
$account->getBiography();
$account->getWebsite();
$account->getFollowersCount();
$account->getFollowsCount();
$account->getMediaCount();
$account->getProfilePicUrl();
$account->getProfilePicUrlHd();
$account->isPrivate();
$account->isVerified();
```

---

### `accountOrNull(string $username): ?Account`

[](#accountornullstring-username-account)

Zoals `accountByUsername`, maar geeft `null` terug als het account niet bestaat — handig voor bulk-checks:

```
$account = InstagramProfile::accountOrNull('might_not_exist');

if ($account === null) {
    // account bestaat niet of is privé
}
```

---

### `timelineByUserId(int $userId, int $count = 24, string $maxId = ''): array`

[](#timelinebyuseridint-userid-int-count--24-string-maxid---array)

Haal de tijdlijn op van een specifiek account via de numerieke user-ID.
Gebruik `$maxId` (de `id` van de laatste `Media`) voor paginering.

```
$medias = InstagramProfile::timelineByUserId(528817151, count: 12);

foreach ($medias as $media) {
    echo $media->getShortCode();              // Bxy123abc
    echo $media->getType();                   // image | video | sidecar
    echo $media->getCaption();                // onderschrift
    echo $media->getLikesCount();
    echo $media->getCommentsCount();
    echo $media->getCreatedTime();            // Unix timestamp
    echo $media->getImageHighResolutionUrl(); // thumbnail URL
    echo $media->getLink();                   // https://www.instagram.com/p/Bxy123abc/
}

// Tweede pagina laden
$lastId = end($medias)->getId();
$page2  = InstagramProfile::timelineByUserId(528817151, count: 12, maxId: $lastId);
```

---

### `timelineByUsername(string $username, int $count = 24): array`

[](#timelinebyusernamestring-username-int-count--24-array)

Korte variant als je alleen de gebruikersnaam weet (haalt userId intern op):

```
$medias = InstagramProfile::timelineByUsername('nasa', count: 9);
```

---

### `mediasByTag(string $tag, int $count = 24): array`

[](#mediasbytagstring-tag-int-count--24-array)

Recente posts voor een hashtag:

```
$medias = InstagramProfile::mediasByTag('amsterdam', count: 15);

foreach ($medias as $media) {
    echo $media->getShortCode();
    echo $media->getCaption();
}
```

---

### `mediaByShortCode(string $shortCode): Media`

[](#mediabyshortcodestring-shortcode-media)

Één post ophalen via de shortcode (het stuk in de URL na `/p/`):

```
// URL: https://www.instagram.com/p/Bxy123abc/
$media = InstagramProfile::mediaByShortCode('Bxy123abc');

echo $media->getId();
echo $media->getCaption();
echo $media->getType();    // image | video | sidecar
echo $media->getVideoUrl(); // bij type video
```

---

### `commentsByShortCode(string $shortCode, int $count = 20, string $maxId = ''): array`

[](#commentsbyshortcodestring-shortcode-int-count--20-string-maxid---array)

Comments van een post ophalen:

```
$comments = InstagramProfile::commentsByShortCode('Bxy123abc', count: 50);

foreach ($comments as $comment) {
    echo $comment->getText();
    echo $comment->getCreatedAt();
    echo $comment->getOwner()->getUsername();
}
```

---

### `highlightsByUserId(int $userId): array`

[](#highlightsbyuseridint-userid-array)

Story highlights van een account:

```
$highlights = InstagramProfile::highlightsByUserId(528817151);

foreach ($highlights as $highlight) {
    echo $highlight->getTitle();     // 'Behind the scenes'
    echo $highlight->getCoverUrl();  // thumbnail
}
```

---

### `locationById(int $locationId): Location`

[](#locationbyidint-locationid-location)

Locatie-informatie op basis van een Facebook locatie-ID:

```
$location = InstagramProfile::locationById(213385402);

echo $location->getName();
echo $location->getLat();
echo $location->getLng();
```

---

### `mediasByLocationId(int $locationId, int $count = 12): array`

[](#mediasbylocationidint-locationid-int-count--12-array)

Recente posts bij een locatie:

```
$medias = InstagramProfile::mediasByLocationId(213385402, count: 9);
```

---

### `engine(): Instagram`

[](#engine-instagram)

Directe toegang tot de volledige scraper-engine voor geavanceerde operaties:

```
$engine = InstagramProfile::engine();

// Volgers ophalen (vereist login)
$followers = $engine->getFollowers($userId, $count = 100);

// Zoeken op tag
$tags = $engine->searchTagsByTagName('amsterdam');

// Inloggen met sessie
$engine->login();
```

---

MediaPayloadFactory
-------------------

[](#mediapayloadfactory)

Transformeer `Media`-objecten naar een genormaliseerd array-formaat (compatibel met RocketAPI-structuur):

```
use TsMedia\LaravelInstagramScraper\Support\MediaPayloadFactory;

$medias = InstagramProfile::timelineByUserId(528817151, count: 24);

// Alle video's als clip-payload
$clips = MediaPayloadFactory::videoClipItemsFromMedias($medias);

foreach ($clips as $clip) {
    $clip['media']['pk'];          // ID
    $clip['media']['code'];        // shortcode
    $clip['media']['play_count'];  // views
    $clip['media']['like_count'];
    $clip['media']['comment_count'];
    $clip['media']['caption']['text'];
    $clip['media']['image_versions2']['candidates'][0]['url']; // thumbnail
}

// Opzoektabel: pk → true (voor snelle deduplicatie)
$seen = MediaPayloadFactory::feedPkLookupFromMedias($medias);

if (isset($seen[$someMediaId])) {
    // al verwerkt
}

// Eén media naar clip-formaat
$clip = MediaPayloadFactory::mediaToClipItem($medias[0]);
```

---

Foutafhandeling
---------------

[](#foutafhandeling)

Alle exceptions staan in `TsMedia\LaravelInstagramScraper\InstagramScraper\Exception\`:

```
use TsMedia\LaravelInstagramScraper\Facades\InstagramProfile;
use TsMedia\LaravelInstagramScraper\InstagramScraper\Exception\InstagramAuthException;
use TsMedia\LaravelInstagramScraper\InstagramScraper\Exception\InstagramNotFoundException;
use TsMedia\LaravelInstagramScraper\InstagramScraper\Exception\InstagramAgeRestrictedException;
use TsMedia\LaravelInstagramScraper\InstagramScraper\Exception\InstagramException;
use TsMedia\LaravelInstagramScraper\InstagramScraper\Http\NetworkException;

try {
    $account = InstagramProfile::accountByUsername($username);

} catch (InstagramNotFoundException $e) {
    // Account bestaat niet
    Log::warning("Instagram account niet gevonden: {$username}");

} catch (InstagramAgeRestrictedException $e) {
    // Account is leeftijdsbeperkt (403)
    Log::info("Leeftijdsbeperkt account: {$username}");

} catch (InstagramAuthException $e) {
    // Authenticatie vereist of sessie verlopen (401)
    Log::error('Instagram auth fout: ' . $e->getMessage());

} catch (NetworkException $e) {
    // Geen verbinding (DNS, timeout, proxy)
    Log::error('Netwerkfout: ' . $e->getMessage());

} catch (InstagramException $e) {
    // Algemene Instagram fout — bevat HTTP-code en response body
    Log::error("Instagram fout [{$e->getHttpCode()}]: {$e->getMessage()}");
    Log::debug('Response body: ' . $e->getResponseBody());
}
```

---

Gebruik in een Laravel Job
--------------------------

[](#gebruik-in-een-laravel-job)

```
