2011-08-22 4 views
5

Ho visto questa discussione già - How can I unshorten a URL?Come posso non abbreviare un URL usando python?

Il mio problema con la risposta risolto (che utilizza l'API unshort.me) è che mi sto concentrando sulla unshortening link di YouTube. Poiché unshort.me viene utilizzato prontamente, questo restituisce quasi il 90% dei risultati con captcha che non riesco a risolvere.

Finora mi sono bloccato con l'utilizzo di:

def unshorten_url(url): 
    resolvedURL = urllib2.urlopen(url) 
    print resolvedURL.url 

    #t = Test() 
    #c = pycurl.Curl() 
    #c.setopt(c.URL, 'http://api.unshort.me/?r=%s&t=xml' % (url)) 
    #c.setopt(c.WRITEFUNCTION, t.body_callback) 
    #c.perform() 
    #c.close() 
    #dom = xml.dom.minidom.parseString(t.contents) 
    #resolvedURL = dom.getElementsByTagName("resolvedURL")[0].firstChild.nodeValue 
    return resolvedURL.url 

Nota: tutto nei commenti è quello che ho cercato di fare quando si utilizza il servizio di unshort.me, che stava tornando link captcha.

Qualcuno sa di un modo più efficiente per completare questa operazione senza utilizzare open (dal momento che è uno spreco di larghezza di banda)?

+0

Cosa URL shortener stai avendo problemi con? Perché stai usando unshort.me comunque? Il tuo codice dovrebbe già funzionare, dovrebbe rimuovere gli URL seguendo il reindirizzamento all'URL reale. – zeekay

+0

Non capisco cosa intendi con "senza usare aperto". Un link breve è una chiave nel database di qualcun altro; non è possibile espandere il collegamento senza interrogare il database. –

+0

Mentre stavo leggendo il post a cui facevo riferimento (http://stackoverflow.com/questions/4201062/how-can-i-unshorten-a-url-using-python) sembrava che il comando urlopen GET richiedesse l'intera pagina quindi è uno spreco di larghezza di banda quando tutto quello che sto cercando è il collegamento. Il metodo suggerito non funzionava per me (unshort.me) quindi ho deciso di vedere se c'erano altre alternative. – brandonmat

risposta

14

Utilizzare la migliore risposta nominale (non la risposta accettata) in quella domanda:

# This is for Py2k. For Py3k, use http.client and urllib.parse instead, and 
# use // instead of/for the division 
import httplib 
import urlparse 

def unshorten_url(url): 
    parsed = urlparse.urlparse(url) 
    h = httplib.HTTPConnection(parsed.netloc) 
    resource = parsed.path 
    if parsed.query != "": 
     resource += "?" + parsed.query 
    h.request('HEAD', resource) 
    response = h.getresponse() 
    if response.status/100 == 3 and response.getheader('Location'): 
     return unshorten_url(response.getheader('Location')) # changed to process chains of short urls 
    else: 
     return url 
+0

Ha funzionato come un incantesimo - l'ho provato ieri inutilmente da quando ricevevo errori su circa il 70% dei rendimenti. Potrebbe essere stata una cosa una tantum ed è per questo che l'ho respinto. Grazie per la risposta e scusa per la mia domanda superflua. – brandonmat

+2

Come follow-up, mi ricordo solo perché in questo modo non ha funzionato per me. Sto lavorando su un'applicazione twitter e ci sono casi in cui un url viene abbreviato due volte (il che accade un numero significativo di volte). Ad esempio otterrà questo video [u't.co/LszdhNP '] e restituirà questo url etsy.me/r6JBGq - dove effettivamente ho bisogno dell'indirizzo finale di youtube a cui questo si collega. Conosci qualche modo per aggirare questo? – brandonmat

+2

nella mia risposta è stata apportata una semplice modifica –

2

È necessario aprirlo, altrimenti non si saprà a quale URL verrà reindirizzato. Come ha detto Greg:

Un collegamento breve è una chiave nel database di qualcun altro; non è possibile espandere il collegamento senza interrogare il database

Ora alla tua domanda.

Qualcuno sa di un modo più efficiente per completare questa operazione senza utilizzare open (dal momento che è uno spreco di larghezza di banda)?

Il modo più efficiente è quello di non chiudere la connessione, tenerla aperta in background, utilizzando il protocollo HTTP Connection: keep-alive.

Dopo un piccolo test, unshorten.me sembra prendere il metodo HEAD in considerazione e fare un redirect a se stesso:

> telnet unshorten.me 80 
Trying 64.202.189.170... 
Connected to unshorten.me. 
Escape character is '^]'. 
HEAD http://unshort.me/index.php?r=http%3A%2F%2Fbit.ly%2FcXEInp HTTP/1.1 
Host: unshorten.me 

HTTP/1.1 301 Moved Permanently 
Date: Mon, 22 Aug 2011 20:42:46 GMT 
Server: Microsoft-IIS/6.0 
X-Powered-By: ASP.NET 
X-AspNet-Version: 2.0.50727 
Location: http://resolves.me/index.php?r=http%3A%2F%2Fbit.ly%2FcXEInp 
Cache-Control: private 
Content-Length: 0 

Quindi, se si utilizza il metodo HEAD HTTP, invece di GET, si vuole in realtà finiscono per fare lo stesso lavoro due volte.

Invece, si dovrebbe tenere la connessione attiva, che vi farà risparmiare solo un po 'di larghezza di banda, ma ciò che sarà sicuramente risparmiare è il latenza di stabilire una nuova connessione ogni volta. Stabilire una connessione TCP/IP è costoso.

Si dovrebbe ottenere un numero di connessioni mantenute-attive con il servizio non ridotto pari al numero di connessioni simultanee ricevute dal proprio servizio.

È possibile gestire queste connessioni in un pool. Questo è il più vicino che puoi ottenere. Accanto allo stack TCP/IP di tweaking your kernel.

+0

Impressionante grazie per l'informazione. Al momento userò la risposta di Pedro Loureiro sopra poiché sta funzionando per il momento. Ma mi riferirò a questo se mi imbatterò in qualche problema. Molto apprezzato. – brandonmat

0

ho potuto replicare qui, ma probabilmente è meglio puntare a una pagina da Dive Into Python, tutto su handling redirects , che è esattamente quello che vuoi fare qui.

10

una riga funziona, utilizzando la libreria di richieste e sì, supporta la ricorsione.

def unshorten_url(url): 
    return requests.head(url, allow_redirects=True).url 
+0

Penso che questa risposta sia persino migliore della risposta più votata. Prova con urls da fb.net e restituisce l'url corretto mentre l'altro non fa nulla. – lenhhoxung

+0

Questo è un unico rivestimento e funziona perfettamente. Probabilmente la migliore risposta – Aventinus

1

Ecco un codice src che tiene conto quasi dei casi d'angolo utili:

  • impostare un timeout personalizzato.
  • impostare un agente utente personalizzato.
  • verificare se è necessario utilizzare una connessione http o https.
  • risolve in modo ricorsivo l'url di input e impedisce la fine all'interno di un ciclo.

Il codice src è su GitHub @https://github.com/amirkrifa/UnShortenUrl

commenti sono benvenuti ...

import logging 
logging.basicConfig(level=logging.DEBUG) 

TIMEOUT = 10 
class UnShortenUrl: 
    def process(self, url, previous_url=None): 
     logging.info('Init url: %s'%url) 
     import urlparse 
     import httplib 
     try: 
      parsed = urlparse.urlparse(url) 
      if parsed.scheme == 'https': 
       h = httplib.HTTPSConnection(parsed.netloc, timeout=TIMEOUT) 
      else: 
       h = httplib.HTTPConnection(parsed.netloc, timeout=TIMEOUT) 
      resource = parsed.path 
      if parsed.query != "": 
       resource += "?" + parsed.query 
      try: 
       h.request('HEAD', 
          resource, 
          headers={'User-Agent': 'curl/7.38.0'} 

         ) 
       response = h.getresponse() 
      except: 
       import traceback 
       traceback.print_exec() 
       return url 
      logging.info('Response status: %d'%response.status) 
      if response.status/100 == 3 and response.getheader('Location'): 
       red_url = response.getheader('Location') 
       logging.info('Red, previous: %s, %s'%(red_url, previous_url)) 
       if red_url == previous_url: 
        return red_url 
       return self.process(red_url, previous_url=url) 
      else: 
       return url 
     except: 
      import traceback 
      traceback.print_exc() 
      return None