13

次のような URL を取得する組み込み関数はありますか:../images.html次のようなベース URLhttp://www.example.com/faq/index.htmlと、次のようなターゲット URL を指定すると、http://www.example.com/images.html

urlparse モジュールを確認しました。私が欲しいのは、urljoin() 関数に対応するものです。

4

3 に答える 3

10

urlparse.urlparseを使用してパスを見つけ、posixpath バージョンのos.path.relnameを使用して相対パスを見つけることができます。

(警告: これは Linux では機能しますが、Windows では機能しない可能性があります):

import urlparse
import sys
import posixpath

def relurl(target,base):
    base=urlparse.urlparse(base)
    target=urlparse.urlparse(target)
    if base.netloc != target.netloc:
        raise ValueError('target and base netlocs do not match')
    base_dir='.'+posixpath.dirname(base.path)
    target='.'+target.path
    return posixpath.relpath(target,start=base_dir)

tests=[
    ('http://www.example.com/images.html','http://www.example.com/faq/index.html','../images.html'),
    ('http://google.com','http://google.com','.'),
    ('http://google.com','http://google.com/','.'),
    ('http://google.com/','http://google.com','.'),
    ('http://google.com/','http://google.com/','.'), 
    ('http://google.com/index.html','http://google.com/','index.html'),
    ('http://google.com/index.html','http://google.com/index.html','index.html'), 
    ]

for target,base,answer in tests:
    try:
        result=relurl(target,base)
    except ValueError as err:
        print('{t!r},{b!r} --> {e}'.format(t=target,b=base,e=err))
    else:
        if result==answer:
            print('{t!r},{b!r} --> PASS'.format(t=target,b=base))
        else:
            print('{t!r},{b!r} --> {r!r} != {a!r}'.format(
                t=target,b=base,r=result,a=answer))
于 2011-09-19T10:48:00.573 に答える
5

頭に浮かぶ最初の解決策は次のとおりです。

>>> os.path.relpath('/images.html', os.path.dirname('/faq/index.html'))
'../images.html'

もちろん、これには URL の解析 -> ドメイン名の比較 (!!) -> その場合はパスの書き換え -> クエリとフラグメントの再追加が必要です。

編集:より完全なバージョン

import urlparse
import posixpath

def relative_url(destination, source):
    u_dest = urlparse.urlsplit(destination)
    u_src = urlparse.urlsplit(source)

    _uc1 = urlparse.urlunsplit(u_dest[:2]+tuple('' for i in range(3)))
    _uc2 = urlparse.urlunsplit(u_src[:2]+tuple('' for i in range(3)))

    if _uc1 != _uc2:
        ## This is a different domain
        return destination

    _relpath = posixpath.relpath(u_dest.path, posixpath.dirname(u_src.path))

    return urlparse.urlunsplit(('', '', _relpath, u_dest.query, u_dest.fragment)

それで

>>> relative_url('http://www.example.com/images.html', 'http://www.example.com/faq/index.html')
'../images.html'
>>> relative_url('http://www.example.com/images.html?my=query&string=here#fragment', 'http://www.example.com/faq/index.html')
'../images.html?my=query&string=here#fragment'
>>> relative_url('http://www.example.com/images.html', 'http://www2.example.com/faq/index.html')
'http://www.example.com/images.html'
>>> relative_url('https://www.example.com/images.html', 'http://www.example.com/faq/index.html')
'https://www.example.com/images.html'

編集: のposixpath実装を使用して、os.pathウィンドウでも機能するようになりました。

于 2011-09-19T10:43:33.837 に答える