使用curl下载Flurry事件日志

4
我开始使用Flurry Analytics并发现它的分析工具不足且过于缓慢。简单的3步漏斗处理了3天,而通常带有3个左连接的查询在100,000行表上只需要0.001秒。
Flurry允许在事件日志页面上以csv格式下载原始事件数据,因此我决定将所有事件导入并在家中进行分析。
Flurry仅允许下载100,000条记录,并建议经常下载以适应此限制。他们曾经提供原始事件下载API,但出于某种原因放弃了。因此,唯一的方法是进入事件日志页面并手动下载事件数据。但正如你所想象的那样,这非常烦人。
因此,我决定使用php中的curl获取此数据。我复制了带有标头的下载链接的GET HTTP请求并获得了数据。 但整个魔法在于会话/cookie,我可以从现有会话中复制它们。因此,为了使curl查询成功,我必须:
  1. 在浏览器中打开Flurry网站并登录
  2. 进入事件日志页面,选择时间范围参数并点击下载
  3. 复制嗅探器中的请求头
  4. 将它们粘贴到我的PHP代码中
  5. 从现在开始,我可以在PHP中进行此查询,直到会话Cookie过期

我不确定,但假设Cookie将在第二天过期,因此整个努力是无用的。

据我所知,我应该尝试使用curl进行POST登录,并保持此连接以执行GET以下载数据。然而,即使复制整个POST登录请求正文,我也无法登录-它仍会回答相同的登录页面,尽管应该302重定向到https://dev.flurry.com/fullPageTakeover.do?originalTarget=&isFirstPostLogin=true&defaultTarget=%2Fhome.do

看起来Flurry在某种程度上受到了curl读取的保护。或者可能有人成功了吗?

以下是代码:

    $cookie_file_path = "cookies.txt";
    $LOGINURL         = "https://dev.flurry.com/secure/login.do";
    $MY_EMAIL ="my email";
    $MY_PASS="password";
    $MY_GAME_ID="gameid";

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER,  0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    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_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_path);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_path);
    curl_setopt ($ch, CURLOPT_REFERER, $LOGINURL);


    curl_setopt($ch, CURLOPT_URL, $LOGINURL);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, "loginEmail=$MY_EMAIL&loginPassword=$MY_PASS&__checkbox_rememberMe=true&struts.token.name=struts.token&struts.token=7NB9NWLOYZ8SD8TWR8LGS63REVDI8SQS");

    $result = curl_exec($ch);


    $remotePageUrl = "https://dev.flurry.com/eventsLogCsv.do?projectID=$MY_GAME_ID&versionCut=versionsAll&intervalCut=7Days&stream=true&direction=1&offset=0";
    curl_setopt($ch, CURLOPT_POST, 0);
    curl_setopt($ch, CURLOPT_URL, $remotePageUrl);
    $result = curl_exec($ch);

    echo $result;

我也尝试传递cookies(就像浏览器一样),但没有帮助:

Cookie: _ga=GA1.2.100867533.1424333566; S0hZTkM0RFRXRjJNSlg2TVdXSEs_fit=1424333594147; fid=SG1162A8DEFC14B8428E7C2AFC71D3AEA00C1872F5; JSESSIONID=w34~mvbdvftm9x9dez9dg9b2pmhs; _map_zoomLevel=0;
_map_zoneId=0; __utmt=1; __utmt_~1=1; S0hZTkM0RFRXRjJNSlg2TVdXSEs_fs=eyJiYSI6MTQyNDMzNzkzMzU2OCwicGF1c2VUaW1lc3RhbXAiOjAsImJjIjotMSwiZXZlbnRDb3VudGVyIjowLCJwdXJjaGFzZUNvdW50ZXIiOjAsImVycm9yQ291bnRlciI6MCwidGltZWRFdmVudHMiOltdfQ==;
__utma=83277827.100867533.1424333566.1424333594.1424336847.2; __utmb=83277827.8.10.1424336847; __utmc=83277827; __utmz=83277827.1424333594.1.1.utmcsr=flurry.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utma=34058230.100867533.1424333566.1424333566.1424336847.2; __utmb=34058230.8.10.1424336847; __utmc=34058230; __utmz=34058230.1424333566.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _mkto_trk=id:802-TBR-126&token:_mch-flurry.com-1424333577360-64839; S0hZTkM0RFRXRjJNSlg2TVdXSEs_flp=1424338032448

多亏了 silkfire,Flurry 问题得到解决!


你登录有问题吗?你发布的链接仍然需要输入电子邮件和密码。请向我们展示您使用cURL执行此登录请求的代码。 - silkfire
@silkfire 我添加了一种测试代码变体。理论上一切都应该正常工作,但是 Flurry 返回相同的登录页面。 - Tertium
我认为你的cURL代码没有任何问题。看起来应该可以正常工作。不幸的是,如果没有账户访问,很难进行测试:( - silkfire
注册需要几分钟时间:https://dev.flurry.com/secure/signup.do。该过程涉及电子邮件,因此每个人都应该自行注册。顺便说一下,Flurry是免费的。 - Tertium
这是一个抽象概念,可以在登录后创建。但是为此,您必须先登录。唯一的问题是我无法使用curl登录。其余的事情都很简单并且已经完成了。 - Tertium
显示剩余4条评论
1个回答

3

struts.token是一种CRSF令牌,它绑定到您的会话并在每次页面加载时重新生成。但在您的代码中,它是静态的。您需要在第一个cURL请求后获取它,然后将其注入到POST数组中,以便用于第二个请求。

另外,您需要登录的页面是/loginAction.do而不是/login.do

以下是我成功登录Flurry的方法:

$post = [
         'loginEmail'        => 'E-MAIL',
         'loginPassword'     => 'PASSWORD',
         'struts.token.name' => 'struts.token'
        ];

$ch = curl_init('https://dev.flurry.com/secure/login.do');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_COOKIEFILE, null);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

libxml_use_internal_errors(true);

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadHTML(curl_exec($ch));

$xpath = new DOMXPath($dom);


$post['struts.token'] = $xpath->query('//input[@name="struts.token"]')->item(0)->getAttribute('value');

curl_setopt($ch, CURLOPT_URL, 'https://dev.flurry.com/secure/loginAction.do');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));

$data = curl_exec($ch);


echo $data;

1
@Tertium 将 CURLOPT_COOKIEFILE 设置为 null 即可。这将允许您的 cURL 句柄存储 cookie,但它们仅保存在内存中,不会混乱您的项目文件夹。 - silkfire
嗨,Silkfire和Tertium。我对PHP和这些类型的脚本不是很熟悉。我想知道你们中的一个是否可以基于你们的代码提供完整的解决方案来登录Flurry并获取所有日志事件。目前我不明白这两个脚本如何实现。我期望看到一个for循环或类似的东西。如果你们有时间,能帮忙吗?谢谢。 - Konrad
@silkfire 我已经集成了上面的代码片段,但它会生成致命错误“Fatal error: Call to a member function getAttribute() on a non-object”。 - Rubin Porwal
@silkfire 是的,他们已经修改了认证机制。请参考 http://stackoverflow.com/questions/39159305/perform-authentication-into-flurry-website-using-curl。 - Rubin Porwal
1
现在谁在乎呢,Flurry数据很差,许多事件都被省略了,即使是我的自有日志处理它们也更好。 - Tertium
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接