【问题标题】:How to obtain a cookie from a remote domain using Greasemonkey?如何使用 Greasemonkey 从远程域获取 cookie?
【发布时间】:2014-11-16 01:01:10
【问题描述】:

我正在编写一个 Greasemonkey (v2.3) 脚本,该脚本基本上对lema.rae.es/drae/srv/search 提供的内容进行屏幕抓取,因为缺少任何类型的 API。

问题是,我想从另一个域的 Google 翻译中查询该 URL。为此,我可以毫无问题地使用 GM_xmlhttpRequest,但是对特定 URL(例如 lema.rae.es/drae/srv/search?val=test)的 GET 请求会生成一个带有隐藏表单的 HTML 页面,该表单在调用 challenge() javascript 函数后会被发布——该函数会计算某种排序在 POST 请求中传递的令牌。

显然,这是异步发生的,Greasemonkey 对此一无所知。通过反复试验,我意识到如果我的浏览器(Iceweasel 31.2.0)有一个用于 lema.drae.es 的 cookie,那么使用GM_xmlhttpRequest 发出的 GET 请求实际上会返回我想要的,即 HTML作为 URL 中的参数“val”传递的单词的定义。但是,如果我删除 lema.drae.es 的所有 cookie,GET 请求会返回上述隐藏表单。

简而言之,我需要一种方法来从 Greasemonkey 中接收该 POST 请求的响应,并且我相信如果可以从服务器接收 cookie 并将其存储,那么我可以将其作为请求标头包含在进一步的请求,它应该可以按我的预期工作。或者它应该简单地存储在浏览器中,因此当我触发 GM_xmlhttpRequest 时会作为标题发送。

我尝试了一个不同的解决方案来解决我的问题,即using a hidden iframe,但基于同源策略,浏览器阻止了此类 iframe 的创建,即使在将用户脚本配置为在两个域上运行之后也是如此。

希望我已经明确了我想要实现的目标,我希望有人能指出我正确的方向。

附带说明:如果有人能解释challenge() 函数的计算结果,我将不胜感激。我的假设是它生成的令牌被发送到服务器,服务器又使用它来生成 cookie,但这听起来过于复杂......

【问题讨论】:

标签: javascript cookies greasemonkey gm-xmlhttprequest


【解决方案1】:

隐藏的 iframe 路由是可行的方法,但在这种情况下它被 translate.google.com 阻止。

这是确保 Firefox 拥有保持混搭网站 (lema.rae.es) 快乐所需的新鲜 cookie 的另一种方法:

  1. 找到一些源 HTML,当混搭站点需要新鲜的 cookie 时,该源 HTML 存在,否则不存在。
    在这种情况下,JS 源 function challenge 就可以了。

  2. GM_xmlhttpRequest 发送到混搭站点并测试响应。

  3. 如果 GM_xmlhttpRequest 响应具有所需的数据,则根据需要对其进行解析。
    完成!

  4. 如果 GM_xmlhttpRequest 响应具有“需要 cookie”源,则在弹出窗口中打开混搭站点的特殊查询:

    1. 由于该站点是在自己的窗口中打开的,因此不会被跨域保护措施阻止。
    2. 将 GM 脚本设置为也对这个特殊的 URL 进行操作。
    3. 对于特殊 URL,等到关键节点或文本出现,表明页面已完成加载并设置了 cookie。
    4. 弹出窗口完成后,它会向打开页面发送一条消息,然后自行关闭。
    5. 当打开页面得到消息时,它重新GM_xmlhttp请求mashup页面。
    6. 解析并完成!


这是一个完整且经过测试的(在 Firefox 上)Greasemonkey 脚本,它将 lema.rae.es/drae/srv/search 混入 translate.google.com时间>。 :

// ==UserScript==
// @name     _GM_xmlhttpRequest that needs cookie(s)
// @include  https://translate.google.com/*
// @include  http://lema.rae.es/drae/srv/search?val=openedByGM
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_xmlhttpRequest
// ==/UserScript==

//--- Global variables
var mashupURL   = "http://lema.rae.es/drae/srv/search?val=test";
var cookGenURL  = "http://lema.rae.es/drae/srv/search?val=openedByGM";

if (location.href == cookGenURL) {
    //--- May be best we can do until Greasemonkey fixes tab handling flaws.
    document.title = "Close me!";

    if (window.opener) {
        waitForKeyElements ("i:contains(openedByGM)", closePopupIfCan);
    }
}
else {
    attemptMashup ();

    window.addEventListener ("message", receiveCookieMessage, false);
}

//-- Just functions from here on down...

function closePopupIfCan (jNode) {
    window.opener.postMessage ("Cookie(s) should be set!", "*");
    window.close ();
}

function attemptMashup () {
    GM_xmlhttpRequest ( {
        method:     "GET",
        url:        mashupURL,
        onload:     parseDictionaryResponse,
        onabort:    reportAJAX_Error,
        onerror:    reportAJAX_Error,
        ontimeout:  reportAJAX_Error
    } );
}

function receiveCookieMessage (event) {
    if (event.origin != "http://lema.rae.es")     return;

    console.log ("message ==> ", event.data);

    /*--- Now that have cookie(s), re-attempt mashup, but need a little
        settling time.
    */
    setTimeout (attemptMashup, 888);
}

function parseDictionaryResponse (respObject) {
    if (respObject.status != 200  &&  respObject.status != 304) {
        reportAJAX_Error (respObject);
        return;
    }
    /*--- If the required cookie is not present/valid, open the target page
        in a temporary tab to set the cookies, then reload this page.

        The test string is unique to the scraped site and is only present
        when cookie(s) is/are needed.
    */
    if (/function\s+challenge/i.test (respObject.responseText) ) {
        var newTab  = window.open (cookGenURL);
        return;
    }

    //--- Don't use jQuery to parse this!
    var parser      = new DOMParser ();
    var responseDoc = parser.parseFromString (
        respObject.responseText, "text/html" // Firefox only, for now.
    );

    //--- Get site-specific payload and put in site-specific location.
    var payload     = responseDoc.querySelectorAll ("body > div");
    $("#gt-form-c").before (payload);
}

function reportAJAX_Error (respObject) {
    alert (
        'Error ' + respObject.status + '!  "' + respObject.statusText + '"'
    );
}

【讨论】:

  • 啊,我明白了。非常感谢您的回答!除了需要创建和关闭实际选项卡以及随之而来的轻弹之外,这效果很好。我猜没有办法解决这个问题,是吗?你是什​​么意思 iframe 被 translate.google.com 阻止了?您的意思是因为混搭站点位于不同的域中,因此无法创建它?
  • 另外,您知道challenge() javascript 函数在无cookie 场景中的作用吗?
  • 不,对于谷歌翻译,除非您编写自己的浏览器扩展程序,否则无法避免额外的选项卡,这比用户脚本方法要困难得多。 ... ...在您的 Q 中,您说“the creation of such iframe was blocked by the browser on the grounds of the Same Origin policy...”,这是真的。但是这种行为是由各自的服务器控制的。 lema.rae.es 不会阻止它,并且很高兴地让自己在其他几个域上进行 iframe。在这种特殊情况下,Google 会阻止 iframe。
  • challenge() 函数正在从服务器获取自定义数据并生成自定义会话 cookie。从理论上讲,您可以尝试获取这些数据并生成您自己的 cookie 并尝试复制“握手”序列,但这比我的答案中的方法更加混乱,并且 可能 不需要写一个新的FF插件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多