2012-01-19 5 views
5

HTMLページでURL(主にHTTP URL)を解析する必要のあるアプリケーションで作業しています。入力を制御できず、ちょっと混乱します。私は頻繁に遭遇していPythonでのURL解析 - パス内のダブルスラッシュの正規化

一つの問題は、非常に厳しいurlparseであるということです、それは例えば、パス部にダブルスラッシュを持ったURLを解析し、参加することになると(でも、バギー、おそらく?):

testUrl = 'http://www.example.com//path?foo=bar' 
urlparse.urljoin(testUrl, 
       urlparse.urlparse(testUrl).path) 

期待される結果の代わりにhttp://www.example.com//path(またはさらに良いものに正規化された単一のスラッシュで)、私はhttp://pathで終わります。

私がこのようなコードを実行している理由は、URLのクエリ/フラグメント部分を取り除くために今まで見つかった唯一の方法だからです。たぶんもっと良い方法がありますが、見つけられませんでした。

これを避ける方法をお勧めする人はいないでしょうか、(私は知っている)正規表現を使って自分自身でパスを正規化すべきですか?

+0

あなたは "それは、クエリ/フラグメントの一部を除去する唯一の方法だ" とはどういう意味ですか?スラッシュとクエリとは何が関係していますか? – jknupp

+0

これはクエリとは関係がありません。なぜなら、URLを解析してから、自分自身のパスに戻ってくる理由は、クエリとフラグメントを除外したいからです。より良い方法があれば、私はこの問題を解決する必要はありません – shevron

+2

urlparseはURLのRFCを正しく実装していると思います - の部分がスラッシュ(http: //tools.ietf.org/html/rfc1738) - あなたの場合、余分なスラッシュを削除してからurlparseに渡します。 – BergmannF

答えて

4

testUrl.rsplit('?') 

URLは返されたリストのインデックス0にあり、クエリはインデックス1になります。

2つの '?'を使用することはできません。それはすべてのURLのために動作するはずです。

+0

これはurlparseの問題には答えませんが、非常に簡単な方法で私のユースケースを間違いなく解決します。ありがとう! – shevron

1

そのofficial urlparse docsに記載されている:URLは絶対URL(つまり、//またはスキームで始まる、である://)の場合

、URLのホスト名および/またはスキームがなります結果に存在する。

urljoin('http://www.cwi.nl/%7Eguido/Python.html', 
...   '//www.python.org/%7Eguido') 
'http://www.python.org/%7Eguido' 

たとえば

のためには、その振る舞いをしたくない場合は可能なスキームとnetloc部品を取り外すurlsplit()とurlunsplit()とURL、前処理。

だから、あなたが行うことができます:あなたが唯一のクエリ部分なしでURLを取得したい場合は、私はurlparseモジュールをスキップして、ちょうどどうなる

urlparse.urljoin(testUrl, 
      urlparse.urlparse(testUrl).path.replace('//','/')) 

出力= 'http://www.example.com/path'

0

解決策はありませんか?

urlparse.urlparse(testUrl).path.replace('//', '/') 
5

パス(//path)は、単独で機能を混乱させるとURIが権限コンポーネントが含まれていない場合、ホスト名

http://tools.ietf.org/html/rfc3986.html#section-3.3

として解釈されますれ、有効ではありませんパスは2つのスラッシュ文字( "//")で始めることはできません。

私は特にこれらのソリューションのどちらか好きではないが、彼らは仕事:

import re 
import urlparse 

testurl = 'http://www.example.com//path?foo=bar' 
parsed = list(urlparse.urlparse(testurl)) 

newurl = ["" for i in range(6)] # could urlparse another address instead 

# Copy first 3 values from 
# ['http', 'www.example.com', '//path', '', 'foo=bar', ''] 
for i in range(3): 
    newurl[i] = parsed[i] 

# Rest are blank 
for i in range(4, 6): 
    newurl[i] = '' 

print urlparse.urlunparse(newurl) 
# http://www.example.com//path 
+0

URLには権限セクションが含まれているため、実際には有効です。したがって、URLは「//」で始まる可能性があります。いずれにしても、無効ではあるが「現実の」URLを解析できない場合でも役立ちます。 – shevron

+0

@ShaharEvron良い点 - 編集された答え – dbr

0

試してみてください。

import re 
import urlparse 

testurl = 'http://www.example.com//path?foo=bar' 

parsed = list(urlparse.urlparse(testurl)) 
parsed[2] = re.sub("/{2,}", "/", parsed[2]) # replace two or more/with one 
cleaned = urlparse.urlunparse(parsed) 

print cleaned 
# http://www.example.com/path?foo=bar 

print urlparse.urljoin(
    testurl, 
    urlparse.urlparse(cleaned).path) 

# http://www.example.com//path 

あなたは何をしているかに応じて、参加を手動で行うことができますこれは:

def http_normalize_slashes(url): 
    url = str(url) 
    segments = url.split('/') 
    correct_segments = [] 
    for segment in segments: 
     if segment != '': 
      correct_segments.append(segment) 
    first_segment = str(correct_segments[0]) 
    if first_segment.find('http') == -1: 
     correct_segments = ['http:'] + correct_segments 
    correct_segments[0] = correct_segments[0] + '/' 
    normalized_url = '/'.join(correct_segments) 
    return normalized_url 

URLの例:

print(http_normalize_slashes('http://www.example.com//path?foo=bar')) 
print(http_normalize_slashes('http:/www.example.com//path?foo=bar')) 
print(http_normalize_slashes('www.example.com//x///c//v///path?foo=bar')) 
print(http_normalize_slashes('http://////www.example.com//x///c//v///path?foo=bar')) 

が返されます:

http://www.example.com/path?foo=bar 
http://www.example.com/path?foo=bar 
http://www.example.com/x/c/v/path?foo=bar 
http://www.example.com/x/c/v/path?foo=bar 

はそれが役に立てば幸い.. :)