pgrimaud / instagram-user-feed

This is a scrapper to easily fetch any feed and interact with Instagram (like, follow, etc.) without OAuth for PHP.
MIT License
882 stars 138 forks source link

Trying login but always return response "Unable to extract JSON data" #342

Open sportakal opened 2 years ago

sportakal commented 2 years ago

Version(s) affected: 6.16

Description
When I try to login with Instagram::withCredentials() and ->login() method with username and password, I keep getting this error "Unable to extract JSON data". Everything was working fine yesterday, today it suddenly started giving this error constantly.

How to reproduce

$instagram = Instagram::withCredentials(
            new \GuzzleHttp\Client(array_merge([
                'verify' => false,
            ])), $this->account->username, $this->account->password, $this->cache_manager
        );

        $instagram = $instagram->login();

Possible Solution
The error occurs at here, Instagram\Auth\Login.php içerisinde, preg_match('/<script type="text\/javascript">window\._sharedData\s?=(.+);<\/script>/', $html, $matches);

This function, makes a request to https://instagram.com to get initial cookies. When i make a request to https://instagram.com via postman, i didn't find any tag that is . From here we need to extract the json containing the csrf_token.

nalindev commented 2 years ago

I also checked the code and I found out that the following code is not able to open the base URL of Instagram... Instagram throws the error link is broken

And the Tag is also missing that @sportakal mentioned

$baseRequest = $this->client->request('GET', InstagramHelper::URL_BASE, [
            'headers' => [
                'user-agent' => OptionHelper::$USER_AGENT,
            ],
        ]);

Instagram has done some major changes and now the CSRF token is present in <script>requireLazy(["JSScheduler","ServerJS","ScheduledApplyEach"] ....... </script>

image

sportakal commented 2 years ago

How we can get csrf again? Do you have any idea?

sportakal commented 2 years ago

I found a way;

Use this preg_match('/\\\"csrf_token\\\":\\\"(.*?)\\\"/', $html, $matches); instead of preg_match('/<script type="text\/javascript">window\._sharedData\s?=(.+);<\/script>/', $html, $matches); at Login.php:73

This gets csrf_token as variable $matches[1] $csrf_token = $matches[1] Then use in try/catch block

$query = $this->client->request('POST', InstagramHelper::URL_AUTH, [
                'form_params' => [
                    'username' => $this->login,
                    'enc_password' => '#PWD_INSTAGRAM_BROWSER:0:' . time() . ':' . $this->password,
                ],
                'headers' => [
                    'cookie' => 'ig_cb=1; csrftoken=' . $csrf_cookie,
                    'referer' => InstagramHelper::URL_BASE,
                    'x-csrftoken' => $csrf_cookie,
                    'user-agent' => OptionHelper::$USER_AGENT,
                    'accept-language' => OptionHelper::$LOCALE,
                ],
                'cookies' => $cookieJar,
            ]);

It worked for me.

nalindev commented 2 years ago

@sportakal Nice it solves the issues.

- can you mark it as a bug instead of need investigations

nalindev commented 2 years ago

For those who are facing error during like unlike then

open your AbstractDataFeed.php file and change your code on lines 125 & 131

image

Rapid0s commented 2 years ago

I've tried both combinations suggested for AbstractDataFeed.php and Login.php But keep getting error:

Unknown error, please report it with a GitHub issue. Client error: POST https://www.instagram.com/accounts/login/ajax/ resulted in a 403 Forbidden

And a not login html page response.

m33ts4k0z commented 2 years ago

I've tried both combinations suggested for AbstractDataFeed.php and Login.php But keep getting error:

Unknown error, please report it with a GitHub issue. Client error: POST https://www.instagram.com/accounts/login/ajax/ resulted in a 403 Forbidden

And a not login html page response.

What you need to do, is to logout from the web browser and request a password reset. That will tell you that they noticed some unusual activity and they will need you to verify your account. You wont need to change your password but the account will then be unblocked. However you can still not use the password to login using this package since the account will get blocked immediately. Maybe using a proxy will temporarily solve this issue but it will ultimately come back.

What I do now, after using the fixes in the posts above, is to login from the web browser and use that cookie to login using the loginWithCookies method from this package. You can use Chrome dev console to see the sessionid and the expires date. Here is an example that works:

$api = new Api();
    $cookie = new \GuzzleHttp\Cookie\SetCookie([
   "Name"     => "sessionid",
   "Value"    => "your_sessionid",
   "Domain"   => ".instagram.com",
   "Path"     => "/",
   "Expires"  => "your_expires_date_in_utc_format",
   "Max-Age"  => "31536000",
   "Secure"   => true,
   "Discard"  => false,
   "HttpOnly" => true,
]);
$cookieJar = new CookieJar(false, [$cookie]);           
$api->loginWithCookies($cookieJar);

However this method is also unreliable. It might work for some hours but then I receive a syntax error.

About that error, using a proxy solves it but comes back again after some hours. Generally I dont think that this package works anymore at its current state. Some modifications are needed. I will look into it when I have time and maybe I can come up with a solution.

kivancagaogluu commented 2 years ago

I believe real reason you need to post password some kind of encryipted. Haven't found what kind of is

m33ts4k0z commented 2 years ago

I believe real reason you need to post password some kind of encryipted. Haven't found what kind of is

in Login.php on line 87:

'enc_password' => '#PWD_INSTAGRAM_BROWSER:0:' . time() . ':' . $this->password,

However, I think I figured out a way to use the existing set of cookies from a web browser with this package and keep you logged in without getting syntax error. You just put all the cookies from the web browser in the cookieJar as well as set the user agent. Mind the single quotes on some of the values. Also, for the sake of validity, change my "Expires" dates to your own:

$api = new Api();
            $api->setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.57 Safari/537.36');
            $cookie = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "csrftoken",
                "Value"    => "your_csrftoken",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2023-11-04T21:42:50.882Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie2 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "sessionid",
                "Value"    => "your_sessionid",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2023-11-05T21:42:43.699Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie3 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "shbts",
                "Value"    => '"your_shbts"',
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2022-11-12T21:42:12.314Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie4 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "shbid",
                "Value"    => '"your_shbid"',
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2022-11-12T21:42:12.314Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie5 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "datr",
                "Value"    => "your_datr",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2024-07-31T10:12:04.896Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie6 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "ds_user_id",
                "Value"    => "your_ds_user_id",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2023-02-03T21:42:50.882Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie7 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "ig_did",
                "Value"    => "your_ig_did",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2024-05-11T13:09:22.194Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookie8 = new \GuzzleHttp\Cookie\SetCookie([
                "Name"     => "dpr",
                "Value"    => "your_dpr",
                "Domain"   => ".instagram.com",
                "Path"     => "/",
                "Expires"  => "2022-11-12T21:42:46.000Z",
                "Max-Age"  => "31536000",
                "Secure"   => true,
                "Discard"  => false,
                "HttpOnly" => true,
            ]);

            $cookieJar = new CookieJar(false, [$cookie, $cookie2, $cookie3, $cookie4, $cookie5, $cookie6, $cookie7, $cookie8]);           
            $api->loginWithCookies($cookieJar);       
            $profile = $api->getProfile(env('INSTAGRAM_PROFILE'));

Then thing is that I don't know what really fixed the issue:

Sending the user agent or Setting the cookies

But this will now work for a year before need changing.

JasonBenett commented 9 months ago

Hello, I can confirm the same happens to me. "Unknown error, please report it with a GitHub issue" and then when using @m33ts4k0z method I receive "Please login with instagram credentials."

Could it be related to MFA? For me, the lib is unusable now

m33ts4k0z commented 9 months ago

@JasonBenett I personally stopped using this package because it was too much of a hassle and a maintenance nightmare. Since I had control over the account I wanted to display, I used the API way and I have forgotten about it. I refresh the token once every 2 months with a crontjob and everything just works on its own.