2009-07-01 17 views
39

Wie würden Sie den Domain-Namen aus einer URL extrahieren, mit Ausnahme von Sub-Domains?So extrahieren Sie den Top-Level-Domain-Namen (TLD) aus der URL

Mein erster Versuch war simpel:

'.'.join(urlparse.urlparse(url).netloc.split('.')[-2:]) 

Dies funktioniert für http://www.foo.com, aber nicht http://www.foo.com.au. Gibt es eine Möglichkeit, dies richtig zu tun, ohne spezielle Kenntnisse über gültige TLDs (Top Level Domains) oder Ländercodes (weil sie sich ändern) zu verwenden.

dank

+2

Eine verwandte Frage zuvor auf Stack-Überlauf: http://stackoverflow.com/questions/569137/how-to-get-domain-name-from-url –

+1

+1: Der "verein Versuch" in diesem Frage funktioniert gut für mich, auch wenn es ironischerweise nicht für den Autor funktioniert. – ArtOfWarfare

+0

Ähnliche Fragen: http://stackoverflow.com/questions/14406300/python-urlparse-extract-domain-name-without-subdomain – user2314737

Antwort

40

Nein, gibt es keine „intrinsische“ Art und Weise, dass (zB) des Wissens zap.co.it ist eine Sub-Domain (weil Italiens Registrar-Domains wie co.it verkaufen TUT), während zap.co.uknicht ist (weil die britischen Registrar verkauft keine Domains wie co.uk, sondern nur wie zap.co.uk).

Sie müssen nur eine Hilfstabelle (oder Online-Quelle) verwenden, um Ihnen zu sagen, welche TLDs sich besonders verhalten wie Großbritanniens und Australiens - es gibt keine Möglichkeit, das zu erraten, ohne das zusätzliche semantische Wissen (natürlich kann es sich irgendwann ändern, aber wenn du eine gute online quelle findest, die sich auch entsprechend ändern wird, hofft man! -).

40

Mit this file of effective tlds die someone else auf Mozilla-Website zu finden:

from __future__ import with_statement 
from urlparse import urlparse 

# load tlds, ignore comments and empty lines: 
with open("effective_tld_names.dat.txt") as tld_file: 
    tlds = [line.strip() for line in tld_file if line[0] not in "/\n"] 

def get_domain(url, tlds): 
    url_elements = urlparse(url)[1].split('.') 
    # url_elements = ["abcde","co","uk"] 

    for i in range(-len(url_elements), 0): 
     last_i_elements = url_elements[i:] 
     # i=-3: ["abcde","co","uk"] 
     # i=-2: ["co","uk"] 
     # i=-1: ["uk"] etc 

     candidate = ".".join(last_i_elements) # abcde.co.uk, co.uk, uk 
     wildcard_candidate = ".".join(["*"] + last_i_elements[1:]) # *.co.uk, *.uk, * 
     exception_candidate = "!" + candidate 

     # match tlds: 
     if (exception_candidate in tlds): 
      return ".".join(url_elements[i:]) 
     if (candidate in tlds or wildcard_candidate in tlds): 
      return ".".join(url_elements[i-1:]) 
      # returns "abcde.co.uk" 

    raise ValueError("Domain not in global list of TLDs") 

print get_domain("http://abcde.co.uk", tlds) 

Ergebnisse in:

abcde.co.uk 

würde ich es begrüßen, wenn jemand mich wissen lassen, welche Bits der oben in einer pythonic Weise neu geschrieben werden können. Zum Beispiel muss es eine bessere Möglichkeit geben, über die last_i_elements Liste zu iterieren, aber mir fällt keine ein. Ich weiß auch nicht, ob ValueError die beste Sache ist, um zu erhöhen. Bemerkungen?

+10

Wenn Sie getDomain() häufig in der Praxis aufrufen müssen, z. B. das Extrahieren von Domänen aus einer großen Protokolldatei, würde ich empfehlen, dass Sie tlds zu einem Set machen, z. tlds = set ([line.strip() für Zeile in tldFile wenn Zeile [0] nicht in "/ \ n"]). Dadurch erhalten Sie eine konstante Zeitsuche für jede dieser Prüfungen, ob ein Element in Tabellen vorhanden ist. Ich sah eine Beschleunigung von etwa 1500 mal für die Nachschlagevorgänge (set vs. list) und für meine gesamte Operation das Extrahieren von Domains aus einer ~ 20 Millionen Zeilenlogdatei, etwa eine 60fache Beschleunigung (6 Minuten nach 6 Stunden). –

+1

Das ist großartig! Nur noch eine Frage: Wird die 'effective_tld_names.dat' Datei auch für neue Domains wie '.amsterdam',' .vodka' und '.wtf' aktualisiert? – kramer65

+0

Die öffentliche Suffixliste von Mozilla wird regelmäßig gewartet, ja, und hat jetzt mehrere Python-Bibliotheken, die sie enthalten. Siehe http://publicssuffix.org/ und die anderen Antworten auf dieser Seite. – tripleee

38

Ist hier ein großes Python-Modul jemand dieses Problem, nachdem er diese Frage zu lösen, schrieb: https://github.com/john-kurkowski/tldextract

Das Modul sucht TLDs im Public Suffix List, mantained von Mozilla Freiwilligen

Zitat:

tldextract auf der anderen Seite weiß, was alle gTLDs [Generische Top-Level-Domains] und ccTLDs [Ländercode Top-Level-Domänen] aussehen wie durch Nachschlagen der derzeit lebenden diejenigen nach der Public Suffix List. Bei einer URL kennt sie ihre Subdomain von ihrer Domain und ihre Domain von ihrem Ländercode.

+1

Dies funktionierte für mich, wo 'tld' fehlschlug (es markierte eine gültige URL als ungültig). – szeitlin

0

Hier ist, wie ich damit umgehen:

if not url.startswith('http'): 
    url = 'http://'+url 
website = urlparse.urlparse(url)[1] 
domain = ('.').join(website.split('.')[-2:]) 
match = re.search(r'((www\.)?([A-Z0-9.-]+\.[A-Z]{2,4}))', domain, re.I) 
if not match: 
    sys.exit(2) 
elif not match.group(0): 
    sys.exit(2) 
+2

Es gibt eine Domäne namens .travel. Es wird nicht mit dem obigen Code funktionieren. – Sri

19

mit Python TLD

https://pypi.python.org/pypi/tld

pip $ tld installieren

from tld import get_tld 
print get_tld("http://www.google.co.uk") 

google.co.uk

oder ohne Protokoll:

from tld import get_tld 

get_tld("www.google.co.uk", fix_protocol=True) 

google.co.uk

+2

Dies wird mit den neuen gTLDs unzuverlässiger. –

+0

Hey, danke, dass du darauf hingewiesen hast. Ich denke, wenn es darum geht, dass neue gTLDs tatsächlich verwendet werden, könnte eine richtige Lösung in das "tld" -Paket kommen. –

+0

Danke @ArturBarseghyan! Es ist sehr einfach mit Python zu verwenden. Aber ich benutze es jetzt für Enterprise-Produkt, ist es eine gute Idee, es weiterhin zu verwenden, auch wenn gTLDs nicht unterstützt werden? Wenn ja, wann werden die gTLDs unterstützt? Nochmals vielen Dank. –

0

Bis get_tld für alle neuen aktualisiert wird, ziehe ich die TLD der Fehler. Sicher ist es schlechter Code, aber es funktioniert.

def get_tld(): 
    try: 
    return get_tld(self.content_url) 
    except Exception, e: 
    re_domain = re.compile("Domain ([^ ]+) didn't match any existing TLD name!"); 
    matchObj = re_domain.findall(str(e)) 
    if matchObj: 
     for m in matchObj: 
     return m 
    raise e 
Verwandte Themen