Okej, więc myślę, że to może być (z kilkoma zmianami) to, czego potrzebujesz.
Ostrzeżenia:
- To jest PHP, C# nie (ale mówiłeś, że byli zainteresowani w każdym języku po stronie serwera).
- Ten kod jest podpięty do (nieoficjalnych) punktów końcowych wyszukiwania Pinterest. Będziesz musiał zmienić $ dane i $ search_res, aby odzwierciedlić odpowiednie punkty końcowe (np. BoardFeedResouce) dla twoich zadań. Uwaga: co najmniej do wyszukiwania, Pinterest obecnie używa dwóch punktów końcowych, jeden do początkowego załadowania strony, a drugi do nieskończonego przewijania. Każdy ma swoją oczekiwaną strukturę param.
- Pinterest nie ma oficjalnego publicznego interfejsu API, spodziewaj się, że ulegnie on awarii, gdy tylko coś zmieni, i bez ostrzeżenia.
- Możesz znaleźć pinterestapi.co.uk łatwiejsze do wdrożenia i akceptowalne dla tego, co robisz.
- Mam kod demo/debugowania pod klasą, którego nie powinno tam być, gdy otrzymujesz żądane dane, oraz domyślny limit pobierania strony, który możesz chcieć zmienić.
Ciekawostki:
- podkreślenia
_
parametr bierze znacznik czasu w formacie JavaScript, tj. podobnie jak czas Unix, ale ma dodane milisekundy. W rzeczywistości nie jest on używany do stronicowania.
- Paginacja korzysta z właściwości
bookmarks
, więc najpierw wysyłasz żądanie do "nowego" punktu końcowego, który tego nie wymaga, a następnie odbierz bookmarks
od wyniku i użyj go w żądaniu, aby uzyskać następną stronę " wyników, pobierz bookmarks
z tych wyników, aby pobrać następną stronę i tak dalej, aż skończy się wyniki lub osiągnie ustawiony limit (lub osiągniesz maksymalny czas serwera dla czasu wykonania skryptu). Chciałbym wiedzieć, co dokładnie koduje pole bookmarks
. Chciałbym myśleć, że jest jakiś zabawny sekretny sos poza zwykłym identyfikatorem PIN lub jakimś innym znacznikiem strony.
- Opuszczam html, zamiast zajmować się JSON-em, ponieważ jest to łatwiejsze (dla mnie) niż przy użyciu rozwiązania do manipulacji DOM lub wiązki wyrażeń regularnych.
<?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";
}
}
}
?>
Daj mi znać, jeśli napotkasz problemy coraz to dostosowane do poszczególnych punktów końcowych. Apole za wszelkie niechlujstwa w kodzie, początkowo nie doszło do produkcji.
Załaduje się tylko 25, ponieważ ładuje resztę na żądanie za pośrednictwem ajax, kiedy przewiń do dołu, znany również jako "Infinite Scroll". Sądzę, że musiałbyś naśladować to przewijanie. A jeśli wyciągnęliby palec, dostali już swoje API. – mattytommo
Czy nie ma sposobu, abym sobie poradził z tym, co dokładnie dzieje się podczas wywoływania zdarzenia AJAX? To wstyd o API –
Hmm, nie sądzę. Lepiej możesz spróbować zrobić to w JavaScript/Jquery, w ten sposób możesz uzyskać wszystkie łącza, a następnie emulować przewijanie do końca, a następnie po powtórzeniu aż do zakończenia przewijania możesz wysłać tablicę ciągów na serwer. – mattytommo