我有一个MySQL表,该表记录访问者的统计信息及其在每个页面上的停留时间。我想做的是计算出选择的时间戳之间的频率,以确定它是人类游客还是坏机器人。
僵尸程序显然可以比人类访客更快地在页面之间移动,因此时间戳每1-2秒左右进行一次页面访问,并且每次可以持续大约2个小时(而且许多此类僵尸程序都会增加服务器的访问量)也加载)。
然后计划使用PHP并对结果进行处理,或者通过一次SQL查询使其全部完成,以查看特定IP在最近2分钟内访问的频率,以及其频率或时差量到两次浏览之间只有几秒钟的时间,然后将该IP列入漫游器列表。
我已经尝试过TIMESTAMPDIFF
,如果与多个SQL语句结合使用以获得MAX
和MIN
,则可能会工作,然后在PHP中提取并重新构建为新查询,但是我正在尝试解决这个问题以最有效的方式去做。
我首先尝试使用LIMIT
和OFFSET
以及MIN
和MAX
进行子查询,但是这太令人困惑了!
所以现在我一直在尝试INTERVAL
,但不确定它是否在执行我期望或需要的操作。
SELECT
`id`, `ip_addr`, `time_viewed`, UNIX_TIMESTAMP(`time_viewed`) AS unix,
UNIX_TIMESTAMP(NOW()) as NOWWW, (UNIX_TIMESTAMP(NOW()) - 120) as one20
FROM `page_counter`
WHERE `ip_addr` = '127.0.0.1' AND DATE_ADD(curdate(),INTERVAL 10 SECOND)
ORDER BY `time_viewed` DESC
LIMIT 0, 9
这是我在使自己对所有内容感到困惑之前所获得的一切!
任何帮助都是极好的。
编辑/更新信息
好的,所以昨晚我匆忙写了很多这样的文章,所以现在我将尽力澄清我希望达到的目标。
某些不良的bot出现在我的网站上,并且在大约2个小时的时间内获得了将近200页的点击量。查看统计数据,我可以看到几乎每个页面都经过相同的IP,每次匹配之间只有几秒钟的时间。
在某些情况下,他们在30秒内访问了将近10页,从统计数据的角度来看,这不太可能是人类的行为。
因此,我的目标是尝试检测这种行为(如果可能),然后将漫游器重定向到特定页面,或者至少从统计信息中阻止其IP。
我的第一个想法是使用
TIMESTAMPDIFF
,但我认为这需要多个查询才能实现(因此该问题的PHP方面用于过滤结果)。例如:
SELECT
`id`, `ip_addr`, `time_viewed`
FROM `page_counter`
WHERE `ip_addr` = '109.86.72.137'
ORDER BY `time_viewed` DESC
LIMIT 0, 9
然后返回此IP命中的最后9页以及查看的时间:
id ip_addr time_viewed
1587039 109.86.72.137 2016-03-15 15:20:50
1587038 109.86.72.137 2016-03-15 15:20:45
1587037 109.86.72.137 2016-03-15 15:20:41
1587036 109.86.72.137 2016-03-15 15:20:38
1587035 109.86.72.137 2016-03-15 15:20:29
1587034 109.86.72.137 2016-03-15 15:20:27
1587033 109.86.72.137 2016-03-15 15:20:22
1587032 109.86.72.137 2016-03-15 15:20:15
1587031 109.86.72.137 2016-03-15 15:20:14
然后使用此信息,或者是否可以将其限制为1分钟内的所有页面,是否可以获取第一个和最后一个时间戳,然后将其用于
TIMESTAMPDIFF
查询中,如下所示:SELECT
`id`, `ip_addr`, `time_viewed`, TIMESTAMPDIFF(SECOND,'2016-03-15 15:20:14', '2016-03-15 15:20:50') AS diff
FROM `page_counter`
WHERE `ip_addr` = '109.86.72.137'
GROUP BY `ip_addr`
ORDER BY `time_viewed` DESC
然后返回:
id ip_addr time_viewed diff
1586571 109.86.72.137 2016-03-15 13:02:34 36
因此,该特定IP在36秒内访问了9页,这很可能是漫游器行为。
我的问题是能够从
LIMIT
查询中动态获取这些第一个和最后一个时间戳,然后将其提供给TIMESTAMPDIFF
查询。我不知道是否有更好的方法来尝试获取此信息或确定访问者是否可能通过此类行为成为机器人,因此我对实现此目标的想法和更好的方法持开放态度(当然在MySQL或PHP组合中)。编辑#2
我忘了提及的事情,实际上可能对此有更多帮助-我也在跟踪每个访问者的会话ID,所以也许可以将其纳入过滤过程中?
编辑#3-会话ID
考虑更多,会话跟踪可能是实现此目的的最佳方法:
SELECT
`id`, `ip_addr`, `time_viewed`, COUNT(`sessionID`) as sesh
FROM `page_counter`
WHERE `ip_addr` = '109.86.72.137' AND DATE(time_viewed) = '2016-03-15'
ORDER BY `time_viewed` DESC
返回值:
id ip_addr time_viewed sesh
1586571 109.86.72.137 2016-03-15 13:02:34 172
这意味着在一天的时间里,单个IP拥有172个唯一的会话。这本身使它比人类访客更可能成为机器人,这可能是更简单的跟踪方式(显然,这取决于站点流量,但是我不希望一个IP地址一天之内就能获得如此多的会话??)
再次编辑
将
DISTINCT
添加到COUNT
仅会为此IP返回15个唯一会话,这可能更接近人类行为(?)使用Trincot的示例进行更新:
SELECT ip_addr,
DATE_FORMAT(time_viewed, '%Y-%m-%d %h') AS hour,
COUNT(*) AS page_visits,
(MAX(UNIX_TIMESTAMP(time_viewed)) - MIN(UNIX_TIMESTAMP(time_viewed)))
/ COUNT(*) AS avg_seconds_between
FROM page_counter
GROUP BY ip_addr, DATE_FORMAT(time_viewed, '%Y-%m-%d %h')
HAVING page_visits > 9
ORDER BY 4
LIMIT 9
结果是:
ip_addr hour page_visits avg_seconds_between
8.37.231.185 2016-01-01 02 35 0.2286
185.5.52.121 2016-03-15 01 324 0.3117
199.15.233.180 2014-03-11 04 22 0.3636
199.15.233.139 2014-03-10 08 22 0.4091
199.15.233.137 2014-01-29 08 12 0.4167
199.15.233.139 2014-02-13 06 12 0.4167
最佳答案
这可能足以获得您想要的:
SELECT ip_addr, count(*)
FROM page_counter
WHERE time_viewed >= DATE_ADD(curdate(), INTERVAL -10 SECOND)
GROUP BY ip_addr
ORDER BY 2 DESC
LIMIT 9
它计算每个IP地址在最近10秒钟内查询了多少页。浏览量最大的网页将列在顶部。
要获得更长时间的视图,可以将每小时的统计信息分组,然后在顶部选择访问率最高的统计信息。我没有对此进行测试:
SELECT ip_addr,
DATE_FORMAT(time_viewed, '%Y-%m-%d %h') AS hour,
COUNT(*) AS page_visits,
(MAX(UNIX_TIMESTAMP(time_viewed)) - MIN(UNIX_TIMESTAMP(time_viewed)))
/ COUNT(*) AS avg_seconds_between
FROM page_counter
GROUP BY ip_addr, DATE_FORMAT(time_viewed, '%Y-%m-%d %h')
HAVING page_visits > 9
ORDER BY 4
LIMIT 9
HAVING
子句可能需要进行修改以使用更好地反映您的需求的限制。它检查一小时内记录的页面访问样本是否足以得出任何结论。因此,如果漫游器在14:55开始工作,并且在15:00之前仅进行了4次页面访问,则在14:xx时段不会检测到该机器人,但如果继续运行,则会在下一个小时段中检测到该机器人例如接下来的30分钟。
关于mysql - MySQL/PHP从表时间戳中找出访问者的频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36018466/