Ok, quindi penso che questo potrebbe essere (con alcune modifiche) quello che ti serve.
Avvertenze:
- Questo è PHP, C# non è (ma hai detto che eri interessato a qualsiasi linguaggio lato server).
- Questo codice si collega a endpoint di ricerca Pinterest (non ufficiali). Dovrai modificare $ data e $ search_res per riflettere gli endpoint appropriati (ad esempio BoardFeedResouce) per le tue attività. Nota: almeno per la ricerca, Pinterest utilizza attualmente due endpoint, uno per il caricamento iniziale della pagina e un altro per le azioni di scorrimento infinite. Ognuno ha la propria struttura param prevista.
- Pinterest non ha API pubbliche ufficiali, si aspettano che si interrompano ogni volta che cambiano qualcosa e senza preavviso.
- Potresti trovare pinterestapi.it più facile da implementare e accettabile per quello che stai facendo.
- Ho un codice demo/debug sotto la classe che non dovrebbe essere presente una volta ottenuti i dati desiderati e un limite di recupero della pagina predefinito che è possibile modificare.
Punti di interesse:
- La sottolineatura
_
parametro assume un timestamp in formato JavaScript, vale a dire. come il tempo Unix ma ha aggiunto millisecondi. Non è effettivamente utilizzato per l'impaginazione.
- L'impaginazione utilizza la proprietà
bookmarks
, in modo da effettuare la prima richiesta al 'nuovo' endpoint che non lo richiede, quindi prendere il bookmarks
dal risultato e utilizzarlo nella richiesta per ottenere la 'pagina' successiva di risultati, prendi lo bookmarks
da quei risultati per recuperare la pagina successiva, e così via fino a quando non finisci i risultati o raggiungi il tuo limite preimpostato (o raggiungi il limite massimo di server per il tempo di esecuzione dello script). Sarei curioso di sapere esattamente cosa codifica il campo bookmarks
. Mi piacerebbe pensare che ci sia un po 'di salsa segreta divertente oltre a un ID pin o un altro indicatore di pagina.
- Sto saltando l'html, invece di trattare con JSON, perché è più facile (per me) che usare una soluzione di manipolazione DOM, o un po 'di regex.
<?php
if(!class_exists('Skrivener_Pins')) {
class Skrivener_Pins {
/**
* Constructor
*/
public function __construct() {
}
/**
* Pinterest search function. Uses Pinterest's "internal" page APIs, so likely to break if they change.
* @author [@skrivener] Philip Tillsley
* @param $search_str The string used to search for matching pins.
* @param $limit Max number of pages to get, defaults to 2 to avoid excessively large queries. Use care when passing in a value.
* @param $bookmarks_str Used internally for recursive fetches.
* @param $pages Used internally to limit recursion.
* @return array() int['id'], obj['image'], str['pin_link'], str['orig_link'], bool['video_flag']
*
* TODO:
*
*
*/
public function get_tagged_pins($search_str, $limit = 1, $bookmarks_str = null, $page = 1) {
// limit depth of recursion, ie. number of pages of 25 returned, otherwise we can hang on huge queries
if($page > $limit) return false;
// are we getting a next page of pins or not
$next_page = false;
if(isset($bookmarks_str)) $next_page = true;
// build url components
if(!$next_page) {
// 1st time
$search_res = 'BaseSearchResource'; // end point
$path = '&module_path=' . urlencode('SearchInfoBar(query=' . $search_str . ', scope=boards)');
$data = preg_replace("'[\n\r\s\t]'","",'{
"options":{
"scope":"pins",
"show_scope_selector":true,
"query":"' . $search_str . '"
},
"context":{
"app_version":"2f83a7e"
},
"module":{
"name":"SearchPage",
"options":{
"scope":"pins",
"query":"' . $search_str . '"
}
},
"append":false,
"error_strategy":0
}');
} else {
// this is a fetch for 'scrolling', what changes is the bookmarks reference,
// so pass the previous bookmarks value to this function and it is included
// in query
$search_res = 'SearchResource'; // different end point from 1st time search
$path = '';
$data = preg_replace("'[\n\r\s\t]'","",'{
"options":{
"query":"' . $search_str . '",
"bookmarks":["' . $bookmarks_str . '"],
"show_scope_selector":null,
"scope":"pins"
},
"context":{
"app_version":"2f83a7e"
},
"module":{
"name":"GridItems",
"options":{
"scrollable":true,
"show_grid_footer":true,
"centered":true,
"reflow_all":true,
"virtualize":true,
"item_options":{
"show_pinner":true,
"show_pinned_from":false,
"show_board":true
},
"layout":"variable_height"
}
},
"append":true,
"error_strategy":2
}');
}
$data = urlencode($data);
$timestamp = time() * 1000; // unix time but in JS format (ie. has ms vs normal server time in secs), * 1000 to add ms (ie. 0ms)
// build url
$url = 'http://pinterest.com/resource/' . $search_res . '/get/?source_url=/search/pins/?q=' . $search_str
. '&data=' . $data
. $path
. '&_=' . $timestamp;//'1378150472669';
// setup curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Requested-With: XMLHttpRequest"));
// get result
$curl_result = curl_exec ($ch); // this echoes the output
$curl_result = json_decode($curl_result);
curl_close ($ch);
// clear html to make var_dumps easier to see when debugging
// $curl_result->module->html = '';
// isolate the pin data, different end points have different data structures
if(!$next_page) $pin_array = $curl_result->module->tree->children[1]->children[0]->children[0]->children;
else $pin_array = $curl_result->module->tree->children;
// map the pin data into desired format
$pin_data_array = array();
$bookmarks = null;
if(is_array($pin_array)) {
if(count($pin_array)) {
foreach ($pin_array as $pin) {
//setup data
$image_id = $pin->options->pin_id;
$image_data = (isset($pin->data->images->originals)) ? $pin->data->images->originals : $pin->data->images->orig;
$pin_url = 'http://pinterest.com/pin/' . $image_id . '/';
$original_url = $pin->data->link;
$video = $pin->data->is_video;
array_push($pin_data_array, array(
"id" => $image_id,
"image" => $image_data,
"pin_link" => $pin_url,
"orig_link" => $original_url,
"video_flag" => $video,
));
}
$bookmarks = reset($curl_result->module->tree->resource->options->bookmarks);
} else {
$pin_data_array = false;
}
}
// recurse until we're done
if(!($pin_data_array === false) && !is_null($bookmarks)) {
// more pins to get
$more_pins = $this->get_tagged_pins($search_str, $limit, $bookmarks, ++$page);
if(!($more_pins === false)) $pin_data_array = array_merge($pin_data_array, $more_pins);
return $pin_data_array;
}
// end of recursion
return false;
}
} // end class Skrivener_Pins
} // end if
/**
* Debug/Demo Code
* delete or comment this section for production
*/
// output headers to control how the content displays
// header("Content-Type: application/json");
header("Content-Type: text/plain");
// header("Content-Type: text/html");
// define search term
// $tag = "vader";
$tag = "haemolytic";
// $tag = "qjkjgjerbjjkrekhjk";
if(class_exists('Skrivener_Pins')) {
// instantiate the class
$pin_handler = new Skrivener_Pins();
// get pins, pinterest returns 25 per batch, function pages through this recursively, pass in limit to
// override default limit on number of pages to retrieve, avoid high limits (eg. limit of 20 * 25 pins/page = 500 pins to pull
// and 20 separate calls to Pinterest)
$pins1 = $pin_handler->get_tagged_pins($tag, 2);
// display the pins for demo purposes
echo '<h1>Images on Pinterest mentioning "' . $tag . '"</h1>' . "\n";
if($pins1 != false) {
echo '<p><em>' . count($pins1) . ' images found.</em></p>' . "\n";
skrivener_dump_images($pins1, 5);
} else {
echo '<p><em>No images found.</em></p>' . "\n";
}
}
// demo function, dumps images in array to html img tags, can pass limit to only display part of array
function skrivener_dump_images($pin_array, $limit = false) {
if(is_array($pin_array)) {
if($limit) $pin_array = array_slice($pin_array, -($limit));
foreach ($pin_array as $pin) {
echo '<img src="' . $pin['image']->url . '" width="' . $pin['image']->width . '" height="' . $pin['image']->height . '" >' . "\n";
}
}
}
?>
Fatemi sapere se si esegue in problemi ottenere questo adattato alle vostre particolari punti finali. Apols per qualsiasi negligenza nel codice, non è stato originariamente prodotto in produzione.
Carica solo 25 perché carica il resto su richiesta tramite ajax quando si scorre verso il basso, ovvero "Scorrimento infinito". Immagino che dovresti emulare lo scrolling. O se hanno tirato fuori il dito, avrebbero già rilasciato la loro API. – mattytommo
Non c'è modo di poter gestire ciò che viene esattamente quando viene chiamato l'evento AJAX? È un vero peccato per l'API –
Hmm, non credo. Potrebbe essere meglio provare a farlo in JavaScript/Jquery, in questo modo è possibile ottenere tutti i collegamenti, quindi emulare lo scorrimento fino alla fine, quindi, dopo averlo ripetuto fino allo scorrimento, è possibile inviare un array di stringhe al server. – mattytommo