2

I have been trying to make cURL login into pinterest.com for the last 17 hours straight, have tried countless and countless different ways just with cURL but it does not work at all.

My current code only goes to the page but the data is not posted, so it does not login just takes me to the login page.

This first code is using USERPWD which is where it takes me to the login page but it does not login.

error_reporting(E_ALL); 
ini_set("display_errors", 1); 

$url = "https://www.pinterest.com/login/";

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // allow https verification if true
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // check common name and verify with host name
curl_setopt($ch, CURLOPT_SSLVERSION,3); // 
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "pin.pem"); // allow ssl cert direct comparison
curl_setopt($ch, CURLOPT_COOKIESESSION, TRUE); // set new cookie session
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookies.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE, "cookies.txt");
curl_setopt($ch, CURLOPT_USERPWD, "email:password");

curl_setopt($ch, CURLOPT_SSLVERSION,3);

// grab URL and pass it to the browser
curl_exec($ch);

// close cURL connection, save cookie file, free up system resources
curl_close($ch);

and if I switch it from CURLOPT_USERPWD to

curl_setopt($ch, CURLOPT_POSTFIELDS, 'username_or_email=$email&password=$password');

it just displays a blank page.

The pin.pem is the X.509 Certificate (PEM) file.

Any direction to make this work would be greatly appreciated it.

Edit

new code but leaves blank page and I got the output with a few arrays and displays this:

Array ( [url] => https://www.pinterest.com/login/ [content_type] => [http_code] => 0 [header_size] => 0 [request_size] => 0 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.036169 [namelookup_time] => 3.3E-5 [connect_time] => 0.036186 [pretransfer_time] => 0 [size_upload] => 0 [size_download] => 0 [speed_download] => 0 [speed_upload] => 0 [download_content_length] => -1 [upload_content_length] => -1 [starttransfer_time] => 0 [redirect_time] => 0 [certinfo] => Array ( ) [redirect_url] => ) 

error_reporting(E_ALL); 
ini_set("display_errors", 1); 

$email = 'email';
$password = 'password';

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://www.pinterest.com/login/');
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSLVERSION,3); // 
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . 'pin.pem');
curl_setopt($ch, CURLOPT_COOKIESESSION, TRUE); 
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_POSTFIELDS, 'username_or_email=$email&password=$password');
curl_setopt($ch, CURLOPT_SSLVERSION,3);

curl_exec($ch);

$output=@curl_exec($ch);
$info = @curl_getinfo($ch);

echo $output;
print_r($info);

curl_close($ch);
drew010
  • 68,777
  • 11
  • 134
  • 162
iBrazilian2
  • 2,204
  • 6
  • 23
  • 45

2 Answers2

6

The Pinterest login process isn't quite that simple. They use a CSRF token which you must extract and send with your login, along with the username and password in the POST body.

Here is what an actual login request to Pinterest looks like, so you will need to emulate this with cURL.

POST /resource/UserSessionResource/create/ HTTP/1.1
Host: www.pinterest.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-CSRFToken: 2rjgN4Qv67pN4wX91kTr4eIkgF54CzJH
X-NEW-APP: 1
X-APP-VERSION: 737af79
X-Requested-With: XMLHttpRequest
Referer: https://www.pinterest.com/login/
Content-Length: 300
Cookie: csrftoken=2rjgN4Qv67pN4wX91kTr4eIkgF54CzJH; _pinterest_sess="aPgJnrIBzvSKLUY/4H5UocshliA47GkkGtHLQwo1H4IcQv58vrdazclonByOb4fWCzb3a3nycKjQzDc6SkCB9eBKoejaLiCjkKLk/QAFRn2x1pvHFlFM+1EoD01/yFxmeQKlvULYU9+qf4D6Mkj8A=="; _track_cm=1;
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

source_url=%2Flogin%2F&data=%7B%22options%22%3A%7B%22username_or_email%22%3A%22YOU%40YOUROMAIN.COM%22%2C%22password%22%3A%22YOURPASSWORD%22%7D%2C%22context%22%3A%7B%7D%7D&module_path=App()%3ELoginPage()%3ELogin()%3EButton(class_name%3Dprimary%2C+text%3DLog+In%2C+type%3Dsubmit%2C+size%3Dlarge)

The source_url data in the request is the POST body (urlencoded). Take note that username_or_email is your login (I put YOU%40YOURDOMAIN.COM) and password is the password.

What you will have to do is make a GET request to /login/ to establish a session and cookies in the cURL session. Then using the same cURL handle, you can switch to a POST request, set CURLOPT_POSTFIELDS with the data from the source_url...... line.

You will probably also need to set the headers X-CSRFToken, X-NEW-APP, X-APP-VERSION, and X-Requested-With to match the above (except you will need to figure out how to get the correct CSRF Token value).

Unfortunately I don't have the time right now to make a working example, the next paragraph may help. You will need to use your browser to help you debug some of the HTTP requests to figure out all the requests you may need to make to get all the relevant data for your request.

If you check out this answer it shows curl login with PHP and links to a number of useful other related answers with examples.

EDIT:

Here is a working example of using PHP and cURL to log in to Pinterest.

This code is a Pinterest PHP login example (works as of 2014-05-11]. You may ask yourself, can what I want to do be done with the API instead of this hackish code which could break at any time???

As you can see I parse the CSRF_Token out of the headers, you should probably do this for the APP-VERSION as well since it can update almost daily. Right now it's hard coded.

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

$username   = 'you@yoursite.com';  // your username
$password   = 'yourpassword';      // your password

// this is the http post data for logging in - username & password are substituted in later
$login_post     = array(
        'source_url' => '/login/',
        'data' => '{"options":{"username_or_email":"%s","password":"%s"},"context":{}}',
        'module_path' => 'App()>LoginPage()>Login()>Button(class_name=primary, text=Log In, type=submit, size=large',
);
$pinterest_url  = 'https://www.pinterest.com/';  // pinterest home url
$login_url      = $pinterest_url . 'login/';     // pinterest login page url
$login_post_url = $pinterest_url . 'resource/UserSessionResource/create/'; // pinterest login post url

// http headers to send with requests
$httpheaders    = array(
       'Connection: keep-alive',
       'Pragma: no-cache',
       'Cache-Control: no-cache',
       'Accept-Language: en-US,en;q=0.5',
);

// http headers to send when logging in
$login_header   = array(
        'X-NEW-APP: 1',
        'X-APP-VERSION: d2bb370',  // THIS WILL UPDATE FREQUENTLY, CHANGE IT!!!
        'X-Requested-With: XMLHttpRequest',
        'Accept: application/json, text/javascript, */*; q=0.01');

// ----------------------------------------------------------------------------
// request home page to establish cookies and a session, set curl options

$ch = curl_init($pinterest_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Iron/31.0.1700.0 Chrome/31.0.1700.0');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, fopen('/tmp/debug.txt', 'w+'));
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheaders);

$data = curl_exec($ch);

// ----------------------------------------------------------------------------

// parse the csrf token out of the cookies to set later when logging in
list($headers, $body) = explode("\r\n\r\n", $data, 2);

preg_match('/csrftoken=(.*?)[\b;\s]/i', $headers, $csrf_token);

// next request the login page
curl_setopt($ch, CURLOPT_URL, $login_url);
$data = curl_exec($ch);

// ----------------------------------------------------------------------------
// perform login post    

$login_header[] = 'X-CSRFToken: ' . $csrf_token[1];

$login_post['data'] = sprintf($login_post['data'], $username, $password);
$post               = http_build_query($login_post);

curl_setopt($ch, CURLOPT_URL, $login_post_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($httpheaders, $login_header));
curl_setopt($ch, CURLOPT_REFERER, $login_url);
curl_setopt($ch, CURLOPT_HEADER, 0);

$data = curl_exec($ch);

// check response and output status

if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
    echo "Error logging in.<br />";
    var_dump(curl_getinfo($ch));
} else {
    $response = json_decode($data, true);

    if ($response === null) {
        echo "Failed to decode JSON response.<br /><br />";
        var_dump($response);
    } else if ($response['resource_response']['error'] === null) {
        echo "Login successful, " . $response['resource_response']['data']['username'] . "<br /><br />";
        echo "You have {$response['resource_response']['data']['follower_count']} followers, are following {$response['resource_response']['data']['following_count']} users.  You have liked {$response['resource_response']['data']['like_count']} pins.";
    }
}

My output:

Login successful, drew010

You have 0 followers, are following 0 users. You have liked 0 pins.

Community
  • 1
  • 1
drew010
  • 68,777
  • 11
  • 134
  • 162
  • I haven't been able to get this to work but this is what I have so far. http://pastebin.com/PLH8mWmn , I set it up so that it would retrieve the information and it gives me this error: http://pastebin.com/RJiMkvke. Although it is reaching pinterest which is good. Also in the cookie session it has set just fine, also includes the csrftoken but can't seem to get past this, any idea? – iBrazilian2 May 09 '14 at 22:37
  • I found out how to set the header but no idea how to get the cookie from the cookie file. http://pastebin.com/3igDCJMg and here is the cookie.txt file http://pastebin.com/fUs36ejW . No idea how to set it, anybody? – iBrazilian2 May 09 '14 at 23:28
  • any ideas on the issue? – iBrazilian2 May 11 '14 at 16:18
  • added a working example. its somewhat commented but you'll have to carefully read through it to understand what's going on. Also take note of my question as to whether or not you can/should be using the API to do what you want. – drew010 May 11 '14 at 18:08
  • There is currently no API that allows you to accomplish what I'd like to do above. I am simply wanting to schedule pins to be uploaded at specific times which I will schedule by using cronjob to run php functions. Thank you for the example, that is very helpful and will help me with future projects. Although, quick question.. How did you find which headers are needed to login into Pinterest? And can I simply reuse the same cookies but specifying the cookiefile and jar in the bottom curl opts? I ask because if I rerun the script it doesn't load correctly because the cookie isn't set. – iBrazilian2 May 12 '14 at 15:32
  • 1
    I use the Firefox plugins [livehttpheaders](http://livehttpheaders.mozdev.org/) to spy on http requests. Chrome has a built in tool for this too. And yes, you can re-use the same cookies from the cookiefile in the future. Once you've logged in and persisted them using COOKIEFILE and COOKIEJAR, in the future you can bypass the login. Just make a quick request to make sure the cookies are still good. – drew010 May 12 '14 at 15:36
  • 1
    Perfect, thank you for your time and support, I appreciate every second of it. – iBrazilian2 May 12 '14 at 15:38
  • I was wondering where you found that you needed to include "resource/UserSessionResource/create/" in the code, I'm sure I did not see that in the httpheaders. – iBrazilian2 May 14 '14 at 16:30
  • Also, the module_path, where did you find that as well? I'm wondering because as I said I haven't been able to find it anywhere. – iBrazilian2 May 14 '14 at 16:41
  • I found `/resource/UserSessionResource/create/` when clicking the log in button. You will see the request is a `POST /resource/UserSessionResource/create/ HTTP/1.1` request so that is the URL the actual login goes to. And `source_url`, `data`, and `module_path` are parameters in the HTTP POST data. If you URL decode the post data, you will see them more clearly. `data` is actually JSON encoded data within the url-encoded post data. The module_path may or may not be necessary but since its included in their request, I kept it here. – drew010 May 14 '14 at 17:33
  • Thank you for all your help, I got everything that I wanted working perfectly thanks to your help. :) – iBrazilian2 May 15 '14 at 22:49
0

FYI, Pinterest has login rate limit so don't run this before every request.

Here is my Ruby implementation of the Pinterest login/session mechanism. Run this once a day to save the headers (including csrftoken). Then use the saved headers to do requests that are not (yet) supported by the api (like ads reports).

class PinterestHeadersScheduler

  include Sidekiq::Worker
  sidekiq_options queue: :recurring, retry: 0

  HOMEPAGE    = 'https://ads.pinterest.com/'
  LOGIN_URL   = "#{HOMEPAGE}login/"
  SESSION_URL = "#{HOMEPAGE}resource/UserSessionResource/create/"

  LOGIN_DATA = {
      source_url: '/login/',
      data: { options: { username_or_email: ENV['PI_USERNAME'], password: ENV['PI_PASSWORD'] }, context: {} }.to_json
  }

  HEADERS = {
      'Accept':           'application/json,text/html,image/webp,image/apng,*/*;q=0.8',
      'Origin':           'https://ads.pinterest.com',
      'Referer':          'https://ads.pinterest.com/',
      'User-Agent':       'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
      'Connection':       'keep-alive',
      'Cache-Control':    'no-cache',
      'Accept-Charset':   'utf-8;ISO-8859-1q=0.7,*;q=0.7',
      'Accept-Encoding':  'gzip, deflate',
      'Accept-Language':  'en-US,en;q=0.8'
  }

  SESSION_HEADERS = HEADERS.merge({
      'Accept':           'application/json',
      'Content-Type':     'application/x-www-form-urlencoded; charset=UTF-8',
      'X-Requested-With': 'XMLHttpRequest'
  })

  def perform
    login   = HTTParty.get(LOGIN_URL, { headers: HEADERS })
    cjar    = login.get_fields('Set-Cookie').each_with_object(HTTParty::CookieHash.new) { |cookie, jar| jar.add_cookies(cookie) }
    headers = SESSION_HEADERS.merge({ 'Cookie': cjar.to_cookie_string, 'X-CSRFToken': cjar[:csrftoken] })

    res     = HTTParty.post(SESSION_URL, { headers: headers, body: LOGIN_DATA.to_param })
    session = JSON.parse(ActiveSupport::Gzip.decompress(res.body))
    raise "login error #{session['resource_response']['error']}" if session['resource_response']['error']

    cjar = res.headers.get_fields('Set-Cookie').each_with_object(HTTParty::CookieHash.new) { |cookie, jar| jar.add_cookies(cookie) }
    save_session_headers(HEADERS.merge({ 'Cookie' => cjar.to_cookie_string }))
  end

  def save_session_headers(headers)
    # replace this with your cache/db
    Utils::RedisUtil.set(:pinterest_session_headers, headers.to_json)
  end
end
Igor
  • 1,253
  • 1
  • 25
  • 34