简体   繁体   English

如何检测页面上已访问和未访问的链接?

[英]How can I detect visited and unvisited links on a page?

My aim is to detect the unvisited links on a webpage and then create a greasemonkey script to click on those links. 我的目的是检测网页上未访问的链接,然后创建一个acobsmonkey脚本来单击那些链接。 By unvisited links here I mean the links which are not opened by me. 这里的未访问链接是指我没有打开的链接。 Since I can see all the browser provide capability to change the color of visited and unvisited link is it possible to detect these links in any manner. 由于我可以看到所有浏览器都提供了更改已访问和未访问链接的颜色的功能,因此有可能以任何方式检测到这些链接。 While searching I came upon this link: http://www.mozdev.org/pipermail/greasemonkey/2005-November/006821.html but someone here told me that this is no longer possible. 在搜索时,我遇到了以下链接: http : //www.mozdev.org/pipermail/greasemonkey/2005-November/006821.html,但是这里有人告诉我这不再可能。 Please help. 请帮忙。

Correct, it is not possible for javascript to detect if a link is visited in either Firefox or Chrome -- which are the only 2 browsers applicable in this Greasemonkey context. 正确,JavaScript无法检测是在Firefox还是Chrome中访问了链接-这是在此Greasemonkey上下文中仅适用的两种浏览器。

That is because Firefox and Chrome take security and privacy seriously. 这是因为Firefox和Chrome十分重视安全性和隐私性。 From the CSS2 spec : 根据CSS2规范

Note. 注意。 It is possible for style sheet authors to abuse the :link and :visited pseudo-classes to determine which sites a user has visited without the user's consent. 样式表作者可能会滥用:link和:visited伪类来确定用户未经用户同意访问了哪些站点。

UAs may therefore treat all links as unvisited links, or implement other measures to preserve the user's privacy while rendering visited and unvisited links differently. 因此,UA可以将所有链接视为未访问的链接,或实施其他措施来保护用户的隐私,同时以不同的方式呈现已访问和未访问的链接。 See [P3P] for more information about handling privacy. 有关处理隐私的更多信息,请参见[P3P]。

See also, "Privacy and the :visited selector" 另请参见“隐私和:visited选择器”
You can see a demo showing that secure-ish browsers will not let you sniff visited links at jsfiddle.net/n8F9U . 您可以在jsfiddle.net/n8F9U上看到一个演示,该演示显示安全的浏览器不允许您嗅探访问的链接。




For your specific situation , because you are visiting a page and keeping it open, you can help a script keep track of what links were visited. 对于您的特定情况 ,因为您正在访问页面并保持打开状态,所以可以帮助脚本跟踪访问了哪些链接。 It's not fool-proof, but I believe it will do what you've asked for. 它不是万无一失的,但我相信它会满足您的要求。

First, see the script in action by doing the following: 首先,执行以下操作查看正在使用的脚本

  1. Install the script, as is. 按原样安装脚本。
  2. Browse to the test page, jsbin.com/eledog . 浏览到测试页面jsbin.com/eledog
    The test page adds a new link, every time it is reloaded or refreshed. 每次重新加载或刷新时,测试页都会添加一个新链接。
  3. The GM script adds 2 buttons to the pages it runs on. GM脚本在其运行的页面上添加了2个按钮。 A "start/Stop" button in the upper left and a "Clear" button in the lower right. 左上方的“开始/停止”按钮和右下方的“清除”按钮。

    When you press the "Start" button, it does the following: 当您按下“开始”按钮时,它将执行以下操作:

    1. All existing links on the page are logged as "visited". 页面上所有现有的链接都记录为“已访问”。
    2. It starts a timer (default setting: 3 seconds), when the timer goes off, it reloads the page. 它启动一个计时器(默认设置:3秒),当计时器关闭时,它将重新加载页面。
    3. Each time the page reloads, it opens any new links and kicks off a new reload-timer. 每次页面重新加载时,它都会打开所有新链接并启动新的重新加载计时器。
    4. Press the "Stop" button to stop the reloads, the list of visited links is preserved. 按下“停止”按钮停止重新加载,已访问链接的列表被保留。

    The "Clear" button, erases the list of visited pages. “清除”按钮清除已访问页面的列表。
    WARNING: If you press "Clear" while the refresh loop is active, then the next time the page reloads, all links will be opened in new tabs. 警告:如果在刷新循环处于活动状态时按“清除”,则下次重新加载页面时, 所有链接都将在新选项卡中打开。


Next, to use the script on your site ... 接下来, 使用您网站上的脚本 ...

Carefully read the comments in the script, you will have to change the @include , @exclude , and selectorStr values to match the site you are using. 仔细阅读脚本中的注释,您将必须更改@include @exclude@include @excludeselectorStr值以匹配您正在使用的站点。

For best results, disable any "Reload Every" add-ons, or "Autoupdate" options. 为了获得最佳结果,请禁用所有“重新加载所有”加载项或“自动更新”选项。


Important notes: 重要笔记:

  1. The script has to use permanent storage to to track the links. 该脚本必须使用永久性存储来跟踪链接。
    The options are: cookies, sessionStorage , localStorage , globalStorage , GM_setValue() , and IndexedDB . 选项包括:Cookies, sessionStoragelocalStorageglobalStorageGM_setValue()IndexedDB

    These all have drawbacks, and in this case (single site, potentially huge number of links, multiple sessions), localStorage is the best choice ( IndexedDB might be, but it is still too unstable -- causing frequent FF crashes on my machine). 所有这些都有缺点,在这种情况下(单个站点,潜在的大量链接,多个会话), localStorage是最佳选择( IndexedDB可能是,但它仍然太不稳定-导致我的计算机频繁发生FF崩溃)。

    This means that links can only be tracked on a per-site basis, and that "security", "privacy", or "cleaner" utilities can block or erase the list of visited links. 这意味着只能在每个站点上跟踪链接,并且“安全”,“隐私”或“更干净”的实用程序可以阻止或删除已访问链接的列表。 (Just like, clearing the browser's history will reset any CSS styling for visited links.) (就像清除浏览器的历史记录一样,将重置访问链接的所有CSS样式。)

  2. The script is Firefox-only, for now. 目前,该脚本仅适用于Firefox。 It should not work on Chrome, even with Tampermonkey installed, without a little re-engineering. 即使不进行任何重新设计,即使安装了Tampermonkey,它也不能在Chrome上运行。



The script: 剧本:

/*******************************************************************************
**  This script:
**      1)  Keeps track of which links have been clicked.
**      2)  Refreshes the page at regular intervals to check for new links.
**      3)  If new links are found, opens those links in a new tab.
**
**  To Set Up:
**      1)  Carefully choose and specify `selectorStr` based on the particulars
**          of the target page(s).
**          The selector string uses any valid jQuery syntax.
**      2)  Set the @include, and/or, @exclude, and/or @match directives as
**          appropriate for the target site.
**      3)  Turn any "Auto update" features off.  Likewise, do not use any
**          "Reload Every" addons.  This script will handle reloads/refreshes.
**
**  To Use:
**      The script will place 2 buttons on the page: A "Start/Stop" button in
**      the upper left and a "Clear" button in the lower left.
**
**      Press the "Start" button to start the script reloading the page and
**      opening any new links.
**      When the button is pressed, it is assumed that any existing links have
**      been visited.
**
**      Press the "Stop" button to halt the reloading and link opening.
**
**      The "Clear" button erases the list of visited links -- which might
**      otherwise be stored forever.
**
**  Methodology:
**      Uses localStorage to track state-machine state, and to keep a
**      persistent list of visited links.
**
**      Implemented with jQuery and some GM_ functions.
**
**      For now, this script is Firefox-only.  It probably will not work on
**      Chrome, even with Tampermonkey.
*/
// ==UserScript==
// @name        _New link / visited link, tracker and opener
// @include     http://jsbin.com/*
// @exclude     /\/edit\b/
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant       GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

//--- Key control/setup variables:
var refreshDelay    = 3000;    //-- milliseconds.
var selectorStr     = 'ul.topicList a.topicTitle';

//--- Add the control buttons.
$("body")  .append (  '<div id="GM_StartStopBtn" class="GM_ControlWrap">'
                    + '<button>Start checking for new links.</button></div>'
            )
           .append (  '<div id="GM_ClearVisitListBtn" class="GM_ControlWrap">'
                    + '<button>Clear the list of visited links.</button></div>'
            );
$('div.GM_ControlWrap').hover (
    function () { $(this).stop (true, false).fadeTo ( 50, 1); },
    function () { $(this).stop (true, false).fadeTo (900, 0.8); }// Coordinate with CSS.
);

//--- Initialize the link-handler object, but wait until the load event.
var stateMachine;
window.addEventListener ("load", function () {
        stateMachine    = new GM_LinkTrack (    selectorStr,
                                                '#GM_StartStopBtn button',
                                                '#GM_ClearVisitListBtn button',
                                                refreshDelay
                                            );

        /*--- Display the current number of visited links.
            We only update once per page load here.
        */
        var numLinks    = stateMachine.GetVisitedLinkCount ();
        $("body").append ('<p>The page opened with ' + numLinks + ' visited links.</p>');
    },
    false
);


/*--- The link and state tracker object.
    Public methods:
        OpenAllNewLinks ()
        StartStopBtnHandler ()
        ClearVisitedLinkList ()
        StartRefreshTimer ();
        StopRefreshTimer ();
        SetAllCurrentLinksToVisited ()
        GetVisitedLinkCount ()
*/
function GM_LinkTrack (selectorStr, startBtnSel, clearBtnSel, refreshDelay)
{
    var visitedLinkArry = [];
    var numVisitedLinks = 0;
    var refreshTimer    = null;
    var startTxt        = 'Start checking for new links.';
    var stopTxt         = 'Stop checking links and reloading.';

    //--- Get visited link-list from storage.
    for (var J = localStorage.length - 1;  J >= 0;  --J) {
        var itemName    = localStorage.key (J);

        if (/^Visited_\d+$/i.test (itemName) ) {
            visitedLinkArry.push (localStorage[itemName] );
            numVisitedLinks++;
        }
    }

    function LinkIsNew (href) {
        /*--- If the link is new, adds it to the list and returns true.
            Otherwise returns false.
        */
        if (visitedLinkArry.indexOf (href) == -1) {
            visitedLinkArry.push (href);

            var itemName    = 'Visited_' + numVisitedLinks;
            localStorage.setItem (itemName, href);
            numVisitedLinks++;

            return true;
        }
        return false;
    }

    //--- For each new link, open it in a separate tab.
    this.OpenAllNewLinks        = function ()
    {
        $(selectorStr).each ( function () {

            if (LinkIsNew (this.href) ) {
                GM_openInTab (this.href);
            }
        } );
    };

    this.StartRefreshTimer      = function () {
        if (typeof refreshTimer != "number") {
            refreshTimer        = setTimeout ( function() {
                                        window.location.reload ();
                                    },
                                    refreshDelay
                                );
        }
    };

    this.StopRefreshTimer       = function () {
        if (typeof refreshTimer == "number") {
            clearTimeout (refreshTimer);
            refreshTimer        = null;
        }
    };

    this.SetAllCurrentLinksToVisited = function () {
        $(selectorStr).each ( function () {
            LinkIsNew (this.href);
        } );
    };

    this.GetVisitedLinkCount = function () {
        return numVisitedLinks;
    };

    var context = this; //-- This seems clearer than using `.bind(this)`.
    this.StartStopBtnHandler    = function (zEvent) {
        if (inRefreshCycle) {
            //--- "Stop" pressed.  Stop searching for new links.
            $(startBtnSel).text (startTxt);
            context.StopRefreshTimer ();
            localStorage.setItem ('inRefreshCycle', '0'); //Set false.
        }
        else {
            //--- "Start" pressed.  Start searching for new links.
            $(startBtnSel).text (stopTxt);
            localStorage.setItem ('inRefreshCycle', '1'); //Set true.

            context.SetAllCurrentLinksToVisited ();
            context.StartRefreshTimer ();
        }
        inRefreshCycle  ^= true;    //-- Toggle value.
    };

    this.ClearVisitedLinkList   = function (zEvent) {
        numVisitedLinks = 0;

        for (var J = localStorage.length - 1;  J >= 0;  --J) {
            var itemName    = localStorage.key (J);

            if (/^Visited_\d+$/i.test (itemName) ) {
                localStorage.removeItem (itemName);
            }
        }
    };

    //--- Activate the buttons.
    $(startBtnSel).click (this.StartStopBtnHandler);
    $(clearBtnSel).click (this.ClearVisitedLinkList);

    //--- Determine state.  Are we running the refresh cycle now?
    var inRefreshCycle  = parseInt (localStorage.inRefreshCycle, 10)  ||  0;
    if (inRefreshCycle) {
        $(startBtnSel).text (stopTxt); //-- Change the btn lable to "Stop".
        this.OpenAllNewLinks ();
        this.StartRefreshTimer ();
    }
}

//--- Style the control buttons.
GM_addStyle ( "                                                             \
    .GM_ControlWrap {                                                       \
        opacity:            0.8;    /*Coordinate with hover func. */        \
        background:         pink;                                           \
        position:           fixed;                                          \
        padding:            0.6ex;                                          \
        z-index:            666666;                                         \
    }                                                                       \
    .GM_ControlWrap button {                                                \
        padding:            0.2ex 0.5ex;                                    \
        border-radius:      1em;                                            \
        box-shadow:         3px 3px 3px gray;                               \
        cursor:             pointer;                                        \
    }                                                                       \
    .GM_ControlWrap button:hover {                                          \
        color:              red;                                            \
    }                                                                       \
    #GM_StartStopBtn {                                                      \
        top:                0;                                              \
        left:               0;                                              \
    }                                                                       \
    #GM_ClearVisitListBtn {                                                 \
        bottom:             0;                                              \
        right:              0;                                              \
    }                                                                       \
" );

You can parse all links on the page and and get their CSS color property. 您可以解析页面上的所有链接并获取其CSS color属性。 If a color of the link is a match to the color of unvisited link you defined in CSS the this link is unvisited. 如果链接的颜色与您在CSS中定义的未访问链接的颜色相匹配,则此链接不会被访问。

This kind of technique usually used to determine all visited links. 这种技术通常用于确定所有访问的链接。 This is sort of a security breach that allows you to determine if user visited particular web-site. 这是一种安全漏洞,可让您确定用户是否访问了特定网站。 Usually used by sleazy marketers. 通常由卑鄙的商人使用。

This kind of tricks usually classifies as a "browser's history manipulation tricks". 这种技巧通常被归类为“浏览器的历史操作技巧”。

More info with code: http://www.stevenyork.com/tutorial/getting_browser_history_using_javascript 有关代码的更多信息: http : //www.stevenyork.com/tutorial/getting_browser_history_using_javascript

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM