V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
chuhades
V2EX  ›  Python

关于 URL 去重的想法

  •  
  •   chuhades ·
    Q2h1Cg · 2015-03-01 16:23:02 +08:00 · 5395 次点击
    这是一个创建于 3547 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近遇到了这个问题。目前的方案是,提取 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 条附言  ·  2015-03-01 17:29:35 +08:00
    转变下问题,相当于:
    如何从 url rewrite 或pathinfo 语法中提取出参数名
    21 条回复    2015-03-02 19:33:46 +08:00
    ruoyu0088
        1
    ruoyu0088  
       2015-03-01 16:25:44 +08:00
    把你的程序提取的特征贴出来看看。
    ruoyu0088
        2
    ruoyu0088  
       2015-03-01 16:28:01 +08:00
    难道不应该用urlparse模块吗?
    binux
        3
    binux  
       2015-03-01 16:28:10 +08:00
    url 本身有什么问题吗?
    chuhades
        4
    chuhades  
    OP
       2015-03-01 16:30:06 +08:00
    @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|||

    因为算法不够好,两者的特征是一样的。有什么建议么?
    chuhades
        5
    chuhades  
    OP
       2015-03-01 16:31:58 +08:00
    @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 这两个也是一样的。目标正式去重这些
    chuhades
        6
    chuhades  
    OP
       2015-03-01 16:32:27 +08:00
    @binux 如4L,url rewrite
    sumhat
        7
    sumhat  
       2015-03-01 16:37:31 +08:00 via Android   ❤️ 1
    抽象化必然损失信息,不用原始URL做比较一定会有冲突,没什么解决方案
    lk09364
        8
    lk09364  
       2015-03-01 16:37:56 +08:00
    - http://a.com/a/b/c/1
    - http://a.com/a/b/c/2
    一般网站上这两个URL不是一样的吧。
    chuhades
        9
    chuhades  
    OP
       2015-03-01 16:40:35 +08:00
    @lk09364 就个人的项目而言,如果我爬虫爬到了http://a.com/a/b/c/1-10000 1w个链接,我希望只输出一个就好,因为他们后端调用的应该是一样的,不同的知识参数
    chuhades
        10
    chuhades  
    OP
       2015-03-01 16:40:44 +08:00
    @chuhades 只是
    binux
        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

    对于标准来说,它就是不一样的

    如果你非说它是一样的,把这个『一样』的规则写出来,用机器能懂的语言。
    如果不行,那就是你写错了。
    ruoyu0088
        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
    lk09364
        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 排序一下就可以了吧。
    chuhades
        14
    chuhades  
    OP
       2015-03-01 16:52:41 +08:00
    @ruoyu0088 感谢,但是和我的需求还是不大一致。其实转换个说法,相当于怎么从一个url(rewrite)中提取出参数名称?
    例如 http://www.yigeshop.cn/index.php/home/shop_list/9,参数就应该是9这部分,不知道能不能理解我的意思。。
    chuhades
        15
    chuhades  
    OP
       2015-03-01 16:54:03 +08:00
    @lk09364 是的 我的代码也是这么写的,但是需求如题目,按已有的规则:
    http://www.yigeshop.cn/index.php/home/shop_list/16、 http://www.yigeshop.cn/index.php/home/shop_details/24 会被判断成相同的url
    lk09364
        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

    之后再作处理。
    chuhades
        17
    chuhades  
    OP
       2015-03-01 17:15:21 +08:00
    @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
    lk09364
        18
    lk09364  
       2015-03-01 17:24:50 +08:00
    @chuhades 不只是一个站台吗?『很多url』
    电脑不知道什么url 在你的定义里是『一样』,也不知道什么才叫『不一样』。
    我也不知道。对此,我提出如下几个办法:
    - 人手写case,对应不同网站/页面的rewrite rules。
    - 机器学习[?],按网页内容判断url 是否『一样』,再分析网站url 的异同。
    - 黑进对方伺服器,直接把网站资料拖下来。
    chuhades
        19
    chuhades  
    OP
       2015-03-01 17:26:30 +08:00
    @lk09364 目前的项目就是扫描器,所以不可能针对每个站点自己去制定规则 : (
    akira
        20
    akira  
       2015-03-02 15:01:27 +08:00   ❤️ 1
    @chuhades 有个大概的思路,不保证一定可行,
    针对你的需求,可以假设参数一定是数字.
    先全部url地址抓下来,如果某url最后参数是数字且生成对应的正则可以匹配多个url,则可视为这些url是一样的。
    chuhades
        21
    chuhades  
    OP
       2015-03-02 19:33:46 +08:00
    @akira 是的,如果已知url量足够大的话,完全可以分析出哪里是参数。就个人的需求而言,做这个去重就是为了减少爬行的url数目。。所以感觉是个死结 : (
    依旧感谢。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3049 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 10:52 · PVG 18:52 · LAX 02:52 · JFK 05:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.