我有一个MySQL表,用于记录访问者统计信息以及他们在每个页面上的时间。我试图做的是计算出选择的时间戳之间的频率,以确定它是一个人类访问者还是一个糟糕的刮刀机器人。
机器人显然可以比人类访问者更快地在页面之间移动,因此时间戳每1-2秒左右就有一次页面访问,这可以一次持续大约2个小时(很多这些机器人也会增加服务器负载。)
然后计划是使用PHP并对结果做一些事情,或者可能使用单个SQL查询完成所有操作,以查看某个IP在过去2分钟内访问过的频率,以及是否&#39 ;频率或时间差仅相当于页面视图之间的秒数,然后将该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
据我所知,在让自己过于混淆之前就已经有了!
任何帮助都会很棒。
编辑/更新信息
好的,所以我昨晚有点匆匆写了很多,所以我现在试着更好地澄清一下我希望实现的目标。
某些糟糕的机器人遇到了我的网站,并且在大约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
答案 0 :(得分:1)
这足以得到你想要的东西:
@Override
public float getPageWidth(int position) {
return 0.75f;
}
根据IP地址计算在过去10秒内查询了多少页。页面浏览量最多的人将列在顶部。
要在更长的时间段内获得视图,您可以按小时对统计信息进行分组,然后在顶部选择访问率最高的统计信息。我没有测试过这个:
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
可能需要调整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
子句以使用更能反映您需求的限制。它检查在一小时内记录的页面访问样本是否足以得出任何结论。
因此,如果机器人在14:55开始工作,在15:00之前只有4次页面访问,那么小时槽14:xx将无法检测到它,但如果在下一个小时槽中检测到它,在接下来的30分钟(例如)中继续这样。