2011-08-22 41 views
5

我已经看到这个线程了 - How can I unshorten a URL?如何使用python取消缩短网址?

我解决的问题(使用unshort.me API)的问题是我正在关注未修改youtube链接。由于unshort.me很容易使用,所以我用无法解决的验证码返回几乎90%的结果。

到目前为止,我坚持使用:

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 

注:一切都在评论是我尝试使用其返回验证码环节unshort.me服务时做的。

有没有人知道更有效的方式来完成这项操作,而不使用开放(因为它是一个浪费带宽)?

+0

您遇到什么麻烦URL缩短用?无论如何,你为什么使用unshort.me?你的代码应该已经可以工作了,它应该通过跟踪重定向到真实的URL来取消隐藏URL。 – zeekay

+0

我不明白你的意思是“没有使用开放”。短链接是其他人数据库的关键;如果不查询数据库,则无法展开链接。 –

+0

当我读到我引用的帖子时(http://stackoverflow.com/questions/4201062/how-can-i-unshorten-a-url-using-python)它看起来像那个命令urlopen GET请求整个页面所以当我所寻找的是链接时,就会浪费带宽。建议的方法不适合我(unshort.me),所以我决定看看是否有其他选择。 – brandonmat

回答

14

使用在这个问题最好的额定答案(不接受的答案):

# 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

工作就像一个魅力 - 我昨天试了这个无济于事,因为我收到约70%的回报错误。可能只是一次性的事情,这就是我解雇它的原因。感谢您的回复,并对我多余的问题感到抱歉。 – brandonmat

+2

作为后续工作,我只记得为什么这种方式对我不起作用。我正在开发一个twitter应用程序,并且有些情况下URL缩短了两次(发生了很多次)。例如,它会得到这个视频[u't.co/LszdhNP']并返回这个URL etsy.me/r6JBGq - 我实际上需要这个链接到的最终的YouTube地址。你知道有什么方法可以解决这个问题吗? – brandonmat

+2

在我的回答中做出了一个简单的改变 –

2

你必须打开它,否则你将不知道它将重定向到什么URL。正如Greg所说的那样:

短链接是进入别人数据库的关键;你不能在没有查询数据库的情况下扩展链接

现在你的问题。

有没有人知道更有效的方式来完成这项操作 没有使用开放(因为它是一个浪费带宽)?

更有效的方式是不关闭连接,保持开放的背景下,通过使用HTTP的Connection: keep-alive

小试后,unshorten.me似乎采取HEAD方法考虑,做一个重定向到本身:

> 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 

因此,如果您使用HEAD HTTP方法,而不是GET你会实际上最终做了两次相同的工作

相反,你应该保持正确的连接,这将节省你只有一点点带宽,但它肯定节省,是建立每当一个新的连接的延迟。建立一个TCP/IP连接是昂贵的

您应该避免与unshorten服务的多个保持活动的连接数等于您自己的服务收到的并发连接数。

您可以管理池中的这些连接。这是你能得到的最接近的。在tweaking your kernel的TCP/IP堆栈旁边。

+0

真棒谢谢你的信息。我目前正在使用Pedro Loureiro的答案,因为它暂时工作。但是如果我遇到任何问题,我会回顾一下。非常感激。 – brandonmat

0

我在这里可以复制它,但它可能会更好,你指向从深入Python的页面时,所有关于handling redirects ,这正是你想在这里做的。

10

单行功能,使用请求库和是的,它支持递归。

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

一起使用我认为这个答案比最投票答案还要好。尝试使用来自fb.net的网址,它会返回正确的网址,而另一个则不会。 – lenhhoxung

+0

这是一个单线,完美的作品。可能是最好的答案。 – Aventinus

1

这里一个src代码,考虑到近的有用极端案例:

  • 设置自定义超时。
  • 设置自定义用户代理。
  • 检查我们是否必须使用http或https连接。
  • 递归解析输入url并防止在循环内结束。

的SRC代码在GitHub上@https://github.com/amirkrifa/UnShortenUrl

意见,欢迎...

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