2012-01-19 29 views
5

Tôi đang làm việc trên một ứng dụng cần phân tích URL (chủ yếu là URL HTTP) trong các trang HTML - Tôi không kiểm soát được đầu vào và một số một chút lộn xộn.Phân tích cú pháp URL trong Python - bình thường hóa dấu gạch chéo kép trong đường dẫn

Một vấn đề tôi đang gặp phải thường xuyên là urlparse là rất nghiêm ngặt khi nói đến các URL phân tích cú pháp và tham gia có hai dấu gạch chéo ở phần đường, ví dụ (và thậm chí có thể có lỗi?):

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

Thay vì kết quả mong đợi http://www.example.com//path (hoặc thậm chí tốt hơn, với dấu gạch chéo đơn chuẩn hóa), tôi kết thúc bằng http://path.

BTW lý do tôi đang chạy mã như vậy là vì đó là cách duy nhất tôi tìm thấy cho đến nay để tách phần truy vấn/phân đoạn khỏi URL. Có lẽ có một cách tốt hơn để làm điều đó, nhưng tôi không thể tìm thấy một.

Bất kỳ ai có thể đề xuất cách để tránh điều này hay tôi nên bình thường hóa đường dẫn của mình bằng cách sử dụng regex (tương đối đơn giản, tôi biết)?

+0

Ý anh là gì bởi "đó là cách duy nhất để tước phần truy vấn/đoạn"? Dấu gạch chéo phải làm gì với truy vấn? – jknupp

+0

Nó không liên quan gì đến truy vấn - lý do tôi phân tích cú pháp một URL và sau đó tham gia đường dẫn riêng của nó vào đó là vì tôi muốn loại bỏ truy vấn và đoạn. Nếu có một cách tốt hơn để làm điều đó, tôi sẽ không cần phải giải quyết vấn đề này – shevron

+2

Tôi nghĩ rằng urlparse chỉ là thực hiện RFC của URL một cách chính xác - chỉ định rằng sau khi phần : có vẻ chỉ là một dấu gạch chéo (http: //tools.ietf.org/html/rfc1738) - vì vậy trong trường hợp của bạn, tôi sẽ cố gắng tách dấu gạch chéo thêm trước khi chuyển nó sang urlparse. – BergmannF

Trả lời

4

Nếu bạn chỉ muốn để có được các url mà không cần phần truy vấn, tôi sẽ bỏ qua các mô-đun urlparse và chỉ cần làm:

testUrl.rsplit('?') 

Url sẽ ở chỉ mục 0 của danh sách được trả lại và truy vấn tại chỉ mục 1.

Không thể có hai '?' trong url để nó hoạt động cho tất cả các url.

+0

Điều này không trả lời bất kỳ vấn đề urlparse nào, nhưng nó chắc chắn giải quyết trường hợp sử dụng của tôi theo một cách rất đơn giản. Cảm ơn! – shevron

1

Nó được đề cập trong official urlparse docs rằng:

Nếu url là một URL tuyệt đối (có nghĩa là, bắt đầu với // hoặc chương trình: //), tên máy chủ của url và/hoặc chương trình sẽ có mặt trong kết quả. Ví dụ

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

Nếu bạn không muốn hành vi đó, preprocess các url với urlsplit() và urlunsplit(), loại bỏ khả năng chương trình và các bộ phận netloc.

Vì vậy, bạn có thể làm:

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

Output = 'http://www.example.com/path'

0

Đó không phải là giải pháp sao?

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

Đường dẫn (//path) không thôi là không hợp lệ, trong đó lẫn lộn chức năng và được hiểu như là một hostname

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

Nếu một URI không chứa một thành phần chính quyền, sau đó các đường dẫn không thể bắt đầu bằng hai ký tự gạch chéo ("//").

tôi không đặc biệt như một trong những giải pháp, nhưng họ làm việc:

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 

Tùy thuộc vào những gì bạn đang làm, bạn có thể thực hiện khi tham gia bằng tay:

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 thực tế hợp lệ, bởi vì ** nó có ** chứa phần quyền hạn - vì vậy URL có thể bắt đầu bằng '//'. Trong mọi trường hợp, ngay cả khi không thể phân tích cú pháp các URL không hợp lệ nhưng các URL "thế giới thực" có thể hữu ích. – shevron

+0

@ShaharEvron điểm tốt - câu trả lời đã chỉnh sửa – dbr

0

Thử Điều này:

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 mẫu:

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')) 

Sẽ trả lại:

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 

Hy vọng nó giúp .. :)

Các vấn đề liên quan