隐藏邮件地址以免被机器人获取 - 保留mailto:

109

简述

  • 无需使用脚本或联系表单即可隐藏电子邮件地址。同时保持 mailto: 功能。方法还必须支持屏幕阅读器。


期望效果:

  • 请不要使用任何脚本。项目中没有使用脚本,希望保持这种状态。

  • 电子邮件地址可以在页面上显示,或者通过某种用户交互方式轻松显示,例如打开模式框。

  • 用户可以单击电子邮件地址,从而触发 mailto: 功能。

  • 单击邮件会打开用户的电子邮件应用程序。

    换句话说,mailto: 功能必须正常工作。

  • 电子邮件地址对于机器人不可见,也不会被识别为电子邮件地址(包括页面源代码)。

  • 我不想收到垃圾邮件。


可能有效的方法:

  • 巧妙使用 CSS 中的伪元素

  • 利用base64编码的解决方案

  • 将电子邮件地址拆分并在文档中分散各个部分,然后在用户单击按钮时将它们重新组合到模态框中(这可能涉及多个CSS类和使用anchor tags

  • 通过CSS更改html属性

@MortezaAsadi 在下面评论中优雅地提出了可能性。这是完整文章的链接-文章发布于2012年:

如果我们能使用CSS来更改HTML属性会怎样?

  • 其他我所不知道的创造性解决方案。

类似的问题/修复方法

(这是Joe Maller提出的一个很好的解决方法,它运作良好,但它是基于脚本的。这是它的样子;

<SCRIPT TYPE="text/javascript">

  emailE = 'example.com'

  emailE = ('yourname' + '@' + emailE)

  document.write('<A href="mailto:' + emailE + '">' + emailE + '</a>')

</script>

<NOSCRIPT>

  Email address protected by JavaScript

</NOSCRIPT>

(JavaScript修复)

所选答案有效。它实际上非常有效。它涉及将电子邮件编码为html实体。它能否得到改进?

这是它的样子;

<A HREF="mailto:

&#121;&#111;&#117;&#114;&#110;&#097;&#109;&#101;&#064;&#100;&#111;&#109;&#097;&#105;&#110;&#046;&#099;&#111;&#109;">

&#121;&#111;&#117;&#114;&#110;&#097;&#109;&#101;&#064;&#100;&#111;&#109;&#097;&#105;&#110;&#046;&#099;&#111;&#109;

</A>

这个问题在SuperUser上的答案很好,它提供了一项利用不同混淆方法接收垃圾邮件数量的研究。

似乎使用 CSS 操纵电子邮件地址以使其 rtl 确实有效。这是我在本节中链接到的第一个问题中使用的相同方法。

我不确定将 mailto: 功能添加到修复程序中会对结果产生什么影响。

  • 还有许多其他与电子邮件地址混淆相关的问题,它们都有类似的答案。 我没有找到符合我的预期效果的任何内容。

问题:

通过结合两个或多个修复程序(甚至添加新的修复程序),同时满足以下条件,是否可以增加电子邮件混淆方法的效率(即尽可能少的垃圾邮件):

A- 保持mailto:功能;和

B- 支持屏幕阅读器


许多下面的答案和评论提出了一个很好的问题,同时指出没有某种形式的js就做不到这一点。

所问/暗示的问题是:

为什么不使用js

答案是我对js过敏。

开玩笑了,

我提出这个问题的三个主要原因是:

  • 联系表格越来越被接受作为提供电子邮件地址的替代品 - 但它们不应该这样做。

  • 如果可以在没有编写脚本的情况下完成,则应该在没有编写脚本的情况下完成。

  • 好奇心:(事实上我当前正在使用其中之一的js修复程序)我想看看是否讨论这个问题会带来更好的解决方法。


28
我认为,如果你想要保持“mailto:”功能,又不愿意使用JavaScript,那么这是不可能的。 - xrisk
@i-love-css请看一下这篇文章:http://andydavies.me/blog/2012/08/13/what-if-we-could-use-css-to-manipulate-html-attributes/ - Morteza Asadi
你可以创建自己的标签:<mail-to href="[BASE64 ENCRYPTED MAIL]" subject="联系我">联系我</mail-to>。建议:http://blog.teamtreehouse.com/create-custom-html-elements-2,注意:您的标签需要带有破折号,例如:some-tag。基本上,该标签必须包括减号符号。 - user7106750
1
您无法在不使用脚本的情况下解决这个问题,您要求避免使用它们是没有意义的。我有一种方法来处理这个问题,但需要使用脚本。 - vsync
@tiffon 因为这个ID对于机器人来说是可读的。 - user7106750
显示剩余13条评论
12个回答

43
挫败电子邮件机器人是一项艰巨的任务。您可能想查看维基百科上的 电子邮件地址收集对策部分
我的背景故事是,我写了一个搜索机器人。多年前,它在初始运行中爬取了 105,000 多个 URL。从那时起,我学到的是网络爬虫机器人实际上可以看到网页上出现的所有文本内容。机器人会读取除图像以外的所有内容。
由于以下原因,垃圾邮件不能轻松地通过代码停止:
CSS和JS在使用mailto标签时无关紧要。机器人专门查看HTML页面中的“mailto:”关键字。从冒号到下一个单引号或双引号(以先出现的为准)的所有内容都被视为电子邮件地址。像上面的示例一样的HTML实体电子邮件地址可以使用反向ASCII方法/函数快速转换。运行上面的JavaScript代码片段,可以快速将以“your...”开头的字符串转换为“yourname@example.com”。(我的搜索机器人放弃了带有mailto:电子邮件地址的href,因为我想要网页的URL而不是电子邮件地址。)
如果一个页面崩溃了,机器人作者会调整机器人以修复与该页面有关的崩溃,以便机器人在未来不会再次在该页面崩溃。这样可以使他们的机器人更加智能。
机器人作者可以编写生成所有已知电子邮件地址变体的机器人,而无需爬行页面或使用任何起始电子邮件地址。虽然这可能不可行,但随着今天高核心数CPU(它们是超线程的,并以4+ GHz运行)的可用性,以及使用分布式云计算甚至超级计算机的可用性,这并非不可想象。可以构建一个机器人农场来向每个人发送垃圾邮件,而无需知道任何人的电子邮件地址。20年前,这是无法想象的。
免费电子邮件提供商曾经将他们的免费用户帐户出售给广告商。过去,仅仅注册一个免费电子邮件帐户就自动保证了他们可以开始向该电子邮件地址发送垃圾邮件...而不必在线使用该电子邮件地址。我已经多次看到这种情况发生,涉及一些著名公司名称。(我不会提及任何名称。)
mailto关键字是IETF RFC的一部分,在其中构建浏览器以自动启动默认电子邮件客户端,从中包含该关键字的链接。当它发生时,必须使用JavaScript来中断该应用程序启动过程。
我认为在传统的电子邮件服务器中不使用过滤器以及可能使用图像的情况下,无法完全停止垃圾邮件的发送。
有一个替代方案...您也可以构建类似聊天的电子邮件客户端,在网站上内部运行。就像Facebook的聊天客户端一样。这是“有点像电子邮件”,但并不真正是电子邮件。它只是一对一的即时消息,并具有存档功能......登录后会自动加载。由于它具有文档附件+链接功能,因此它有点像电子邮件......但没有垃圾邮件。只要不构建外部可访问的API,那么它就是一个封闭的系统,人们无法将垃圾邮件发送到其中。
如果您计划坚持使用传统的电子邮件,则最好在公司的电子邮件服务器上运行类似Apache SpamAssassin的东西。
您还可以尝试结合多个策略,使网络爬虫难以从您的网页中获取电子邮件地址。它们不会100%地停止垃圾邮件发送,同时还允许盲人访客使用100%的屏幕阅读器。

你提供了一个非常好的起点,来说明传统电子邮件存在的问题!对此我向你致敬!

一个好的屏幕阅读器是JAWS,它来自Freedom Scientific。我曾经使用过它来听盲人用户如何阅读我的网页。(如果你听到一个男性声音同时读出动作[比如点击链接]和文字,请尝试将一个声音更改为女性,这样一个声音就可以读出动作,另一个声音就可以读出文字。这样可以更容易地听到视障人士如何阅读网页。)

祝你在电子邮件地址收集反制方面好运!


2
非常感谢您提供如此详尽的答案。您分享了大量的信息。这些信息有助于更进一步地锁定问题,并可能最终找到解决方法。 - user7234396
不客气!帮助您获取额外的经验洞察是一件愉快的事情。我很感激这个奖项,它让我很惊喜。谢谢您! - Clomp

43

您的请求问题在于"支持屏幕阅读器",因为按照定义,屏幕阅读器是某种类型的"机器人"。如果屏幕阅读器需要能够解释电子邮件地址,那么页面爬虫也将能够解释它。

mailto属性的用途是成为网络上处理电子邮件地址的标准。问是否有第二种方法做到这一点,就等于在问是否有第二个标准。

通过脚本来实现仍然存在同样的问题,因为一旦页面加载完成,脚本就已经运行并且把电子邮件地址渲染在DOM中了(除非您在on click事件之后再填充电子邮件地址)。无论哪种方式,屏幕阅读器都会遇到问题,因为它没有被预先加载。

老实说,只要使用一个有合理垃圾邮件过滤功能的电子邮件服务,并指定一个易于在收件箱中分类的默认主题即可。

<a href="mailto:no-one@example.com?subject=Something to filter on">Email me</a>
你所询问的是,如果标准有两种做事情的方式,一种是用于机器人,另一种是用于非机器人,答案是没有这样的标准,你只能尽力打败机器人。

12
与机器人作战很糟糕,但总有一天我们会赢得这场战争……或者灭绝。 - k2snowman69
抱歉,当机器人工作时,它会查找所有带有“@”的字符串,然后通过“?”拆分此文本,并检查第一部分是否与正则表达式匹配。最后保存2个版本。 - Adrian Bobrowski
1
我不确定你的意思。我的添加主题行的意图是希望最终用户不要更改它。这样,您可以创建一个电子邮件过滤器,将所有那些特定主题的电子邮件放入一个特定的文件夹中。重点不是为了防止机器人,而是为了帮助电子邮件规则。正如我之前所说,防止机器人是一场永无止境的战斗。 - k2snowman69
2
“这个想法是保持电子邮件的隐藏,直到用户采取某种行动,比如按下按钮打开模态框。如果用户的操作不改变DOM(这是屏幕阅读器实际读取的内容),那么屏幕阅读器仍然能够看到它。通过JavaScript由于用户的操作来更改DOM是最好的方法。网页松散地遵循MVC模式,其中HTML、CSS和JavaScript分别类比于Model、View和Controller。这意味着任何修改都要通过JavaScript进行,而在其他地方进行修改则有点困难甚至不可能。” - k2snowman69
此外,我相当确定mailto属性是专门创建的,以产生激活电子邮件消息的超链接,您可以在维基百科页面引用的RFC中阅读到它:https://en.wikipedia.org/wiki/Mailto - k2snowman69
显示剩余2条评论

40
以下是一种利用JavaScript的方法,但占用空间较小。它非常“低劣”,通常不建议在HTML中使用内联JS的方法,除非您完全不愿意使用JS。

<a
  href="#"
  data-contact="bGUtZW1haWxAdGhlLWRvbWFpbi5jb20="
  data-subj="QW4gQW1hemluZyBTdWJqZWN0"
  onfocus="this.href = 'mailto:' + atob(this.dataset.contact) + '?subject=' + atob(this.dataset.subj || '')"
  >
  Send an email
</a>

data-contact是基于base64编码的电子邮件地址。而data-subj则是一个可选的经过base64编码的主题。

不使用JavaScript实现这一点的主要挑战在于CSS无法更改HTML属性。(你链接的那篇文章是一种“空想”,与今天或不久的将来可能实现的内容无关)

你提到的HTML实体方法或其某些变体可能是最简单的选项,但它们都容易受到网络爬虫的攻击。此外,利用iframe方法也可以实现,而服务器重定向方法也很棒。但是,所有三种方法都容易受到网络爬虫的攻击:

  • HTML实体只需要被转换(检测到此操作很简单)
  • iframe引用的文档可能被简单地跟踪
  • 服务器重定向也可能会被简单地跟踪

使用上述方法,在data-contact属性中使用基于base64编码的电子邮件地址是非常“一次性”的——只要网络爬虫不是专门针对您的网站设计的,它就应该可以正常工作。


4
我很喜欢这个。如果他们没有启用 JavaScript,他们可以去给别人发邮件。 - Michael Rogers

29

简单易懂+功能齐全+无需工具即可进行编辑。

<a href="mailto:user@domain@@com"
   onmouseover="this.href=this.href.replace('@@','.')">
   Send email
</a>


1
我喜欢这个整洁小巧的代码片段! - Marlon Creative
5
喜欢这个小东西,@AndyHolmes 我用了 onclick="...",在移动设备上也可以工作(已在Android / 移动版 Chrome 上测试),不知道这样会不会更加无用,因为机器人可能比 onmouseover 更多地检查 onclick。 - goleon
6
@goleon,onclick 可以在移动设备上使用,但是 onmouseover 不行,因为移动设备没有悬停状态。 - Andy Holmes

10

你考虑过使用谷歌的reCAPTCHA mailhide吗?https://www.google.com/recaptcha/admin#mailhide

这个想法是当用户点击复选框(见下面的无验证码)时,完整的电子邮件地址将显示出来。

尽管reCAPTCHA传统上不仅难以为屏幕阅读器服务,也难以为人类所理解,但随着谷歌无验证码reCAPTCHA的推出(您可以在这里了解),它似乎对于屏幕阅读器服务有帮助,因为对于他们而言,它呈现为传统复选框。 Nocaptcha reCAPTCHA

示例1 - 不安全,但易于说明思想

这里有一些代码示例,不使用mailhide但自己实现了一个基于reCAPTCHA的示例:https://jsfiddle.net/43fad8pf/36/

<div class="container">
    <div id="recaptcha"></div>
</div>
<div id="email">
    Verify captcha to get e-mail
</div>

function createRecaptcha() {
    grecaptcha.render("recaptcha", {sitekey: "6LcgSAMTAAAAACc2C7rc6HB9ZmEX4SyB0bbAJvTG", theme: "light", callback: showEmail});
}
 createRecaptcha();

function showEmail() {
    // ideally you would do server side verification of the captcha and then the server would return the e-mail
  document.getElementById("email").innerHTML = "email@example.com";
}

注意:在我的示例中,电子邮件位于JavaScript函数中。理想情况下,您应该在服务器端验证recaptcha并返回电子邮件,否则机器人可以直接在代码中获取它。

示例#2-服务器端验证和返回电子邮件

如果我们使用类似这样的示例,我们会得到额外的安全保障:https://designracy.com/recaptcha-using-ajax-php-and-jquery/

function showEmail() {
    /* Check if the captcha is complete */
    if ($("#g-recaptcha-response").val()) {
        $.ajax({
            type: ‘POST’,
            url: "verify.php", // The file we’re making the request to
            dataType: ‘html’,
            async: true,
            data: {
                captchaResponse: $("#g-recaptcha-response").val() // The generated response from the widget sent as a POST parameter
        },
        success: function (data) {
            alert("everything looks ok. Here is where we would take 'data' which contains the e-mail and put it somewhere in the document");
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            alert("You’re a bot");
        }
    });
} else {
    alert("Please fill the captcha!");
}
});

其中verify.php所在的位置:

$captcha = filter_input(INPUT_POST, ‘captchaResponse’); // get the captchaResponse parameter sent from our ajax

/* Check if captcha is filled */
if (!$captcha) {
    http_response_code(401); // Return error code if there is no captcha
}
$response =     file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=YOUR-SECRET-KEY-HERE&amp;amp;response=" . $captcha);
if ($response . success == false) {
echo ‘SPAM’;
http_response_code(401); // It’s SPAM! RETURN SOME KIND OF ERROR
} else {
// Everything is ok, should output this in json or something better, but this is an example
    echo 'email@example.com';
}

1
如果您对使用谷歌产品感到不安,您可以使用hCaptcha获得更多或更少相同的功能。 - shaedrich

4

编写网络爬虫的人都希望使其尽可能高效,因此他们不会下载样式、脚本和其他外部资源。据我所知,没有一种方法可以使用CSS设置mailto链接。此外,您明确表示不想使用Javascript来设置链接。

如果您考虑其他类型的资源,还有外部文档(即使用iframe的HTML文档)。几乎没有爬虫会费心下载iframe的内容。因此,您可以简单地执行:

index.html:

<iframe src="frame.html" style="height: 1em; width: 100%; border: 0;"></iframe>

frame.html:

My email is <a href="mailto:me@example.com" target="_top">me@example.com</a>

对于人类用户来说,iframe 看起来就像普通的文本。Iframe 默认是内联和透明的,所以我们只需要设置它的边框和尺寸即可。如果不使用 Javascript,你无法让 iframe 的大小与其内容的大小匹配,因此我们最好将其指定为预定义的尺寸。


5
我同意你的第一段,但是你关于iframe内容的第二段是错误的。机器人希望尽可能多的HTML内容。他们会下载iframe的内容,因为他们正在寻找链接、文本等等... 机器人并不在乎这是否是一个iframe标签。他们只是简单地爬取页面。如果URL在iframe或JavaScript标记的src部分中,它将被爬取。 - Clomp

3

首先,我认为使用CSS不会起作用。除了Google的爬虫之外,所有机器人都会忽略网站上的所有样式。任何解决方案都必须使用JS或服务器端。

一种服务器端的解决方案是创建一个链接到新标签页的 <a>,然后简单地重定向到所需的mailto

这就是我现在想到的所有想法。希望能有所帮助。


2
虽然我大约一年前测试时,所有主流浏览器都支持它,但我发现由于“安全”原因,将mailto:作为302重定向的位置已经不再可行,就像你不能再使用file:一样。(话虽如此,当JavaScript被禁用时,我们仍然使用此重定向作为备选方案。) - Ulrich Schwarz
那是真的。想得不错。 - Pablo K

2
为了满足您的所有要求,简短的回答是不可能的。这里提供的一些基于脚本的选项可能对某些机器人有效,但是由于您要求无脚本,所以不能实现。

他们可以在电子邮件上使用某种加密方式,并在JavaScript中进行动态解密。即使是简单的+1密码也可以达到目的。理论上是可以被破解的,但没有机器人会破解它。 - john k

2
基于MaanooAk的代码,这是我的版本:

<a href="mailto: Mike Myers"
onclick="this.href=this.href.replace(' Mike ','MikeMy'); this.href=this.href.replace('Myers','ers@vwx.yz')">&#9993; Send Email</a>

与MaanookAks版本的区别在于,鼠标悬停时不会看到mailto:和一个错误的电子邮件地址,而是看到mailto:和联系人的姓名。当您点击它时,姓名将被电子邮件地址替换。
在代码中,电子邮件地址被分成两个部分。在代码中没有完整的电子邮件地址可见。

有人建议我应该在代码中将“Mike”改为“%20Mike%20”。但是在我的浏览器中,这只有在我也将“mailto:Mike Myers”更改为“mailto:%20Mike%20Myers”时才起作用。我不知道是否真的有必要将所有空格都更改为%20。 - Hglwll
不幸的是,一些浏览器在执行 onclick 之前会执行 href,因此这不是一个好的解决方案。更好的解决方案是将电子邮件地址的修正和 mailto: 放在正确的顺序中,放入一个函数中,例如通过 "onclick" 调用。我会发布这个解决方案。 - Hglwll

0

这是我对此问题的新解决方案。我首先通过添加小片段来构建电子邮件地址字符串,然后将该字符串同时用作标题:

adress = 'mailt' + 'o:MikeM' + 'yers@v' + 'wx.yz';
document.getElementsByClassName('Email')[0].title = adress;
function mail(){window.location.href = adress;}
<a class='Email' onclick='mail()'>&#9993; Send Email</a>

我在网站的页脚中使用它。许多页面都有同样的页脚。

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