最近遇到了这个问题。目前的方案是,提取 url 的 请求方法|协议|域名|一级目录|目录深度|尾部特征|QUERY|DATA 作为特征,md5(特征) 作为返回值。
可以判断如下这种:
http://www.yigeshop.cn/index.php/home/shop_list/9
http://www.yigeshop.cn/index.php/home/shop_list/16
但对于 http://www.yigeshop.cn/index.php/home/shop_details/24,算法认为它与上面两个相同。
各位有什么好的解决方案么?
贴上渣渣算法:
```
def hash(self):
"""
URL 去重
:return: hash
:rtype: int
"""
# 请求方法|协议|域名|一级目录|目录深度|尾部特征|QUERY|DATA
# http://a.com/p1/p2/p3/f.php?a=1&b=2&c
# GET|http|a.com|p1|4|php|abc|
first_dir = self.__parsed.path.split("/")[1] \
if len(self.__parsed.path.split("/")) > 1 else ""
depth = str(self.__parsed.path.count("/")) \
if self.__parsed.path.count("/") else "1"
suffix = self.__parsed.path.split("/")[-1].split(".")[-1] \
if "." in self.__parsed.path.split("/")[-1] else ""
query = "".join(sorted(self.query.keys()))
data = "".join(sorted(self.__data.keys()))
feather = "|".join((
self.__method,
self.__parsed.scheme,
self.__parsed.netloc,
first_dir,
depth,
suffix,
query,
data
))
hash_ = int(md5(feather.encode()).hexdigest(), 16)
return hash_
1
ruoyu0088 2015-03-01 16:25:44 +08:00
把你的程序提取的特征贴出来看看。
|
2
ruoyu0088 2015-03-01 16:28:01 +08:00
难道不应该用urlparse模块吗?
|
3
binux 2015-03-01 16:28:10 +08:00
url 本身有什么问题吗?
|
4
chuhades OP @ruoyu0088 http://www.yigeshop.cn/index.php/home/shop_list/9 => GET|http|www.yigeshop.cn|index.php|4|||
http://www.yigeshop.cn/index.php/home/shop_details/24 => GET|http|www.yigeshop.cn|index.php|4||| 因为算法不够好,两者的特征是一样的。有什么建议么? |
5
chuhades OP @ruoyu0088 urlparse 不够强啊,http://a.com/1.php?a=1&b=2 http://a.com/1.php?b=2&a=1 这两个其实是一样的,或者http://a.com/a/b/c/1,http://a.com/a/b/c/2 这两个也是一样的。目标正式去重这些
|
7
sumhat 2015-03-01 16:37:31 +08:00 via Android 1
抽象化必然损失信息,不用原始URL做比较一定会有冲突,没什么解决方案
|
8
lk09364 2015-03-01 16:37:56 +08:00
|
9
chuhades OP @lk09364 就个人的项目而言,如果我爬虫爬到了http://a.com/a/b/c/1-10000 1w个链接,我希望只输出一个就好,因为他们后端调用的应该是一样的,不同的知识参数
|
11
binux 2015-03-01 16:41:31 +08:00
@chuhades 你这是和网站相关的
http://a.com/1.php?a=1&b=2 http://a.com/1.php?b=2&a=1 对于标准来说,它就是不一样的 如果你非说它是一样的,把这个『一样』的规则写出来,用机器能懂的语言。 如果不行,那就是你写错了。 |
12
ruoyu0088 2015-03-01 16:43:28 +08:00 1
这样看你的URL相同的定义,例如如果忽略路径中最后一个是数字和所有的参数的话,那么这样也许可以:
import urlparse from os import path url = "http://www.yigeshop.cn/index.php/home/shop_list/9?a=1&b=2&c" r = urlparse.urlparse(url) url_path = r.path if path.basename(url_path).isdigit(): url_path = path.dirname(url_path) url = urlparse.urlunparse([r.scheme, r.netloc, url_path, "", "", ""]) print url |
13
lk09364 2015-03-01 16:51:06 +08:00
@chuhades 就你给出的例子而言, http://a.com/a/b/c/1 可以无视的部分是最后的数字,那就直接把最后的数字删除掉就可以做比对了啊?
而就第二个例子,即 - http://a.com/1.php?a=1&b=2 - http://a.com/1.php?b=2&a=1 这个而言,你认为他们是一样的,所以可以把参数部分提出来, ?b=2&a=1 按field name 排序一下就可以了吧。 |
14
chuhades OP @ruoyu0088 感谢,但是和我的需求还是不大一致。其实转换个说法,相当于怎么从一个url(rewrite)中提取出参数名称?
例如 http://www.yigeshop.cn/index.php/home/shop_list/9,参数就应该是9这部分,不知道能不能理解我的意思。。 |
15
chuhades OP @lk09364 是的 我的代码也是这么写的,但是需求如题目,按已有的规则:
http://www.yigeshop.cn/index.php/home/shop_list/16、 http://www.yigeshop.cn/index.php/home/shop_details/24 会被判断成相同的url |
16
lk09364 2015-03-01 17:07:01 +08:00 1
@chuhades
> 请求方法|协议|域名|一级目录|目录深度|尾部特征|QUERY|DATA 不,根据这个解释,hash中二/三/四级目录的名称不见了。 我认为你可以先把url 分作2个部分…… - http://www.yigeshop.cn/index.php/home/shop_list/9 - ?a=1&b=2&c 之后再作处理。 |
17
chuhades OP @lk09364 是的,我就是讲参数和path 分离的,但是很多url做了rewrite 或者pathinfo,如下:
http://a.com/p1/p2/a/1/b/2 ,这样的就很蛋疼,对于这种,只想出用一级目录,目录深度,尾部特征来做判断。但是可能会有漏报,比如题目中描述的 http://www.yigeshop.cn/index.php/home/shop_list/16、 http://www.yigeshop.cn/index.php/home/shop_details/24会被判断成相同的url |
18
lk09364 2015-03-01 17:24:50 +08:00
@chuhades 不只是一个站台吗?『很多url』
电脑不知道什么url 在你的定义里是『一样』,也不知道什么才叫『不一样』。 我也不知道。对此,我提出如下几个办法: - 人手写case,对应不同网站/页面的rewrite rules。 - 机器学习[?],按网页内容判断url 是否『一样』,再分析网站url 的异同。 - 黑进对方伺服器,直接把网站资料拖下来。 |
20
akira 2015-03-02 15:01:27 +08:00 1
@chuhades 有个大概的思路,不保证一定可行,
针对你的需求,可以假设参数一定是数字. 先全部url地址抓下来,如果某url最后参数是数字且生成对应的正则可以匹配多个url,则可视为这些url是一样的。 |
21
chuhades OP @akira 是的,如果已知url量足够大的话,完全可以分析出哪里是参数。就个人的需求而言,做这个去重就是为了减少爬行的url数目。。所以感觉是个死结 : (
依旧感谢。 |