【问题标题】:How can I unshorten a URL?如何取消缩短 URL?
【发布时间】:2011-05-11 04:57:04
【问题描述】:

我希望能够采用缩短或未缩短的 URL 并返回其未缩短的形式。我怎样才能制作一个python程序来做到这一点?

补充说明:

  • 案例 1:缩短 --> 未缩短
  • 案例 2:未缩短 --> 未缩短

例如输入数组中的bit.ly/silly 应该是输出数组中的google.com
例如输入数组中的google.com 应该是输出数组中的google.com

【问题讨论】:

标签: python url url-shortener


【解决方案1】:

向 URL 发送 HTTP HEAD 请求并查看响应代码。如果代码是 30x,请查看 Location 标头以获取未缩短的 URL。否则,如果code是20x,则不重定向URL;您可能还想以某种方式处理错误代码(4xx 和 5xx)。例如:

# 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)
    h.request('HEAD', parsed.path)
    response = h.getresponse()
    if response.status/100 == 3 and response.getheader('Location'):
        return response.getheader('Location')
    else:
        return url

【讨论】:

  • 忽略 url 查询,这里有更好的版本:stackoverflow.com/a/7153185/818634
  • 请注意,当您想要获取实际 URL 时,使用上述代码不会递归地取消缩短。试试http://t.co/hAplNMmSTg。您需要为递归执行return unshorten_url(response.getheader('Location'))
  • 可能还跟踪一组中以前的 url 以防止循环递归。
【解决方案2】:

使用请求:

import requests

session = requests.Session()  # so connections are recycled
resp = session.head(url, allow_redirects=True)
print(resp.url)

【讨论】:

  • 我喜欢这个解决方案,它会自动跟随多个重定向
【解决方案3】:

Unshorten.me 有一个 API,可让您发送 JSON 或 XML 请求并获取返回的完整 URL。

【讨论】:

    【解决方案4】:

    打开 url 看看它解析成什么:

    >>> import urllib2
    >>> a = urllib2.urlopen('http://bit.ly/cXEInp')
    >>> print a.url
    http://www.flickr.com/photos/26432908@N00/346615997/sizes/l/
    >>> a = urllib2.urlopen('http://google.com')
    >>> print a.url
    http://www.google.com/
    

    【讨论】:

    • 这会获取整个页面。如果页面不是重定向并且恰好非常大,那么您只是在浪费大量带宽来确定它不是重定向。改用 HEAD 请求要好得多。
    • @Adam Rosenfeld:对于刚开始使用 python 的人来说,这可能是一个适合的副项目的答案。我不建议像这样的谷歌或雅虎蜘蛛页面来找到真正的 URL。
    • 这样做是一个不好的主意。你浪费了很多带宽。正如@user387049 建议的那样,仅使用unshort.me api 会更好更快
    【解决方案5】:

    要取消短,您可以使用请求。这是一个适合我的简单解决方案。

    import requests
    url = "http://foo.com"
    
    site = requests.get(url)
    print(site.url)
    

    【讨论】:

      【解决方案6】:

      如果您使用的是 Python 3.5+,则可以使用 Unshortenit 模块,这让这一切变得非常简单:

      from unshortenit import UnshortenIt
      unshortener = UnshortenIt()
      uri = unshortener.unshorten('https://href.li/?https://example.com')
      

      【讨论】:

        【解决方案7】:

        http://github.com/stef/urlclean

        sudo pip install urlclean
        urlclean.unshorten(url)
        

        【讨论】:

        • 不幸的是,这只是 python 2,为什么要在 2012 年在 python 代码中编写不带括号的打印:(
        【解决方案8】:

        这里的 src 代码几乎考虑了有用的极端情况:

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

        src代码在github上@https://github.com/amirkrifa/UnShortenUrl

        欢迎 cmets ...

        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
        

        【讨论】:

        • 如果我正确理解了您的流程,您可能希望限制可以容忍的重定向次数
        • @Foon 在某些情况下,重定向指向相同的前一个 url,因此,为了防止陷入无限循环,我在 recusive 调用中传播前一个 url,如果我最终得到 red_url == previous_url,我停止并返回该 url。否则,在正常情况下,在某些迭代中,response.status 将不再等于重定向状态,因此,我们返回检索到的 url。
        • @AmirKrifa 是否处理指向 link.bar 的 link.foo 又指向 link.foo? (我不知道 httplib 是否知道是否有跟踪重定向的选项,在这种情况下,这种链接会在您调用递归调用之前引发异常)
        【解决方案9】:

        您可以使用geturl()

        from urllib.request import urlopen
        url = "bit.ly/silly"
        unshortened_url = urlopen(url).geturl()
        print(unshortened_url)
        # google.com
        

        【讨论】:

          【解决方案10】:

          这是一个非常简单的任务,你只需要添加 4 行代码就可以了 :)

          import requests
          url = input('Enter url : ')
          site = requests.get(url)
          print(site.url)
          

          只需运行此代码,您将成功解短 url。

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-01
          • 2020-05-12
          • 2020-06-10
          • 2014-12-01
          • 2011-07-28
          • 2014-04-04
          • 1970-01-01
          • 2013-06-22
          相关资源
          最近更新 更多