- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这道题听上去很简单,其实并不像听起来那么简单。
问题的简要总结
例如,使用这个板; http://pinterest.com/dodo/web-designui-and-mobile/
检查页面顶部板本身的 HTML(在 div
中,类 GridItems
)产生:
<div class="variableHeightLayout padItems GridItems Module centeredWithinWrapper" style="..">
<!-- First div with a displayed board image -->
<div class="item" style="top: 0px; left: 0px; visibility: visible;">..</div>
...
<!-- Last div with a displayed board image -->
<div class="item" style="top: 3343px; left: 1000px; visibility: visible;">..</div>
</div>
然而在页面底部,在激活无限滚动几次之后,我们得到了 HTML:
<div class="variableHeightLayout padItems GridItems Module centeredWithinWrapper" style="..">
<!-- First div with a displayed board image -->
<div class="item" style="top: 12431px; left: 750px; visibility: visible;">..</div>
...
<!-- Last div with a displayed board image -->
<div class="item" style="top: 19944px; left: 750px; visibility: visible;">..</div>
</div>
如您所见,页面上方的一些图像容器已经消失,并且并非所有图像容器都在首次加载页面时加载。
我想做什么
我希望能够创建一个 C# 脚本(或目前任何服务器端语言)来下载页面的完整 HTML(即检索页面上的每个图像),然后图像将从他们的网站下载网址。下载网页并使用适当的 XPath 很容易,但真正的挑战是为每个图像下载完整的 HTML。
有没有一种方法可以模拟滚动到页面底部,或者是否有一种更简单的方法可以检索每张图片?我想象 Pinterest 使用 AJAX 来更改 HTML,有没有办法以编程方式触发事件以接收所有 HTML?预先感谢您提供建议和解决方案,如果您没有任何建议和解决方案,甚至阅读这个非常长的问题,我将感到荣幸!
伪代码
using System;
using System.Net;
using HtmlAgilityPack;
private void Main() {
string pinterestURL = "http://www.pinterest.com/...";
string XPath = ".../img";
HtmlDocument doc = new HtmlDocument();
// Currently only downloads the first 25 images.
doc.Load(strPinterestUrl);
foreach(HtmlNode link in doc.DocumentElement.SelectNodes(strXPath))
{
image_links[] = link["src"];
// Use image links
}
}
最佳答案
好的,所以我认为这可能是(稍作改动)您所需要的。
注意事项:
兴趣点:
_
参数采用 JavaScript 格式的时间戳,即。像 Unix 时间,但它增加了毫秒。它实际上并不用于分页。bookmarks
属性,因此您向不需要它的"new"端点发出第一个请求,然后从结果中获取 bookmarks
并在您的请求中使用它来获取下一个“页面”结果,从这些结果中获取 bookmarks
以获取之后的下一页,依此类推,直到您用完结果或达到您的预-设置限制(或者你达到脚本执行时间的服务器最大值)。我很想知道 bookmarks
字段编码的确切内容。我想除了 pin ID 或其他一些页面标记之外,还有一些有趣的秘方。<?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";
}
}
}
?>
如果您在使它适应您的特定终点时遇到问题,请告诉我。 Apols 对于代码中的任何草率,它最初并没有投入生产。
关于c# - 从 Pinterest 网址获取图板中的所有图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18312479/
就像添加一类“data-pin-pin”而不是“data-pin-nopin”? slider 中有图像,但它们都是背景图像,因此当前 pin 按钮不起作用。 谢谢! 最佳答案 Pinterest 无
通常,要获取 Pinterest 版 block 的 RSS 提要,只需将“.rss”添加到 URL 末尾即可。 例如,对于 http://www.pinterest.com/philchairez/
我正在搜索 Pinterest 的提要移动应用程序 API。 我可以知道如何从 Pinterest 获取搜索提要吗? API。 最佳答案 这里有文档 https://developers.pinter
Pinterest Widget Builder允许灵活地创建小部件以放置在您的网站上。我在 this page 上加了一个,但您可以为小部件设置的宽度似乎有限制。例如,我将宽度设置为 1170,但它
自今年年初(整整 7 个月!)以来,关于 Pinterest API 中的搜索功能出现了几个问题。 示例:我在这里得到与我们的 friend leonardo 相同的回复:Pinterest API
我们希望将网站设置为 oEmbed 提供商。 官方文档 ( http://oembed.com/ ) 说: Configuration for oEmbed is very simple. Provi
有没有办法在 React Native 中使用 flexbox 来实现 Masonry/Pinterest 风格的列? 最佳答案 在 React Native 中,远程图像不会在加载时调整大小(参见“
我想知道是否有相应的方法可以打开 pinterest 链接,如果安装了 pinterest 应用程序,或者如果它不在 Facebook 等设备中,则使用浏览器。对于 Facebook,我使用以下代码
对于 iOS 8,Pinterest 有一个共享扩展。如何设置图片来源网址和描述属性?我正在使用 UIActivityViewController。我是否使用 UIImage、NSURL 用于 sou
目前,我正在尝试重新创建类似 Instagram/Pinterest iOS 个人资料页面的内容,您可以在具有不同数据和布局的部分之间滑动,同时标题不会水平滚动,而是与每个部分垂直滚动。与当前 Ins
在页面 https://developers.pinterest.com/tools/access_token/您可以生成访问 token 。有谁知道那个 token 的生命周期是多少?它会在固定时间
我们的 prod pinterest 应用程序有问题。 获得 token 后: "{"access_token": "AabcYgRUKiaBI45HYM72teXO6fZaFQoEhVxkxaREo
我正在寻找一种从给定用户名获取板名称列表的方法。我知道 pinterest 已经为给定用户的所有 pin 和给定 pinboard 的所有 pin 提供了 rss。 来自给定用户的所有 Pin 图:p
这个文档很清楚:http://developers.pinterest.com/api_docs/oauth_code_exchange/ 我需要 code用访问 token 交换它。但是访问此代码的
任何人都可以对(未受过教育的)猜测如何使用未发布的Pinterest API进行分页吗? 例如,此链接:https://api.pinterest.com/v3/pidgets/boards/grai
我正在通过使用此url访问Pinterest API以获取用户信息,但是我找不到如何为Pinterest生成访问 token 的方法。 根据这个blog post,它说 Pinterest uses
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。
尝试实现“固定它”按钮,但它会为每张图片返回以下问题。我们在整个网站上使用 SSL,我想知道这是否相关。 有什么想法吗? {"route_pattern": "^/resource/:name/:me
我集成了“Pin It”按钮以在 pinterest.com 上分享我的产品图片。但它不会在我网站上的 pin it 按钮前显示 pin 计数。我写了下面的代码。 这是我网站上的固定按钮 &这个
我有一个 AngularJS 应用程序,它是一个单页应用程序。在每个单独的页面上都会加载 Pinterest 板,这是通过 Pinterest 的小部件构建器完成的: This can be foun
我是一名优秀的程序员,十分优秀!