如何在url open中处理重定向

2024-06-01 06:05:43 发布

您现在位置:Python中文网/ 问答频道 /正文

抱歉问新手的问题。我想知道python中是否有一个高效的url开启器类来处理重定向。我现在使用的是simpleurllib.urlopen()但不起作用。这是一个例子:

http://thetechshowdown.com/Redirect4.php

对于此url,我使用的类不遵循重定向到:

http://www.bhphotovideo.com/

只显示:

“您将被自动重定向到B&H

页面卡住了?单击此处。”

提前谢谢。在


Tags: comhttpurlwww页面重定向例子urlopen
3条回答

使用模块requests-它默认折叠重定向。在

但是页面可以被javascript重定向,所以没有任何模块会遵循这种重定向。在

在浏览器中关闭javascript并转到http://thetechshowdown.com/Redirect4.php查看它是否将您重定向到其他页面

我检查了这个页面-有javascript重定向和HTML重定向(带有“refresh”参数的标记)。两者都不是服务器发送的正常重定向-因此任何模块都不会遵循此重定向。你必须阅读网页,在代码中找到网址,并与该网址连接。在

import requests
import lxml, lxml.html

# started page

r = requests.get('http://thetechshowdown.com/Redirect4.php')

#print r.url
#print r.history
#print r.text

# first redirection

html = lxml.html.fromstring(r.text)

refresh = html.cssselect('meta[http-equiv="refresh"]')

if refresh:
    print 'refresh:', refresh[0].attrib['content']
    x = refresh[0].attrib['content'].find('http')
    url = refresh[0].attrib['content'][x:]
    print 'url:', url

r = requests.get(url)

#print r.text

# second redirection

html = lxml.html.fromstring(r.text)

refresh = html.cssselect('meta[http-equiv="refresh"]')

if refresh:
    print 'refresh:', refresh[0].attrib['content']
    x = refresh[0].attrib['content'].find('http')
    url = refresh[0].attrib['content'][x:]
    print 'url:', url

r = requests.get(url)

# final page

print r.text

这是因为软重定向urllib没有跟踪重定向,因为它无法识别这些重定向。事实上,会发出一个HTTP响应代码200(找到页面),浏览器中的某些副作用会导致重定向发生。在

第一页包含HTTP响应代码200,但包含以下内容:

<meta http-equiv="refresh" content="1; url=http://fave.co/1idiTuz">

它指示浏览器跟踪链接。第二个资源向另一个资源发出HTTP响应代码301或302(重定向),在那里发生第二个软重定向,这次使用Javascript:

^{pr2}$

不幸的是,您将不得不提取URL来手动跟踪。不过,这并不难。代码如下:

from lxml.html import parse
from urllib import urlopen
from contextlib import closing

def follow(url):
    """Follow both true and soft redirects."""
    while True:
        with closing(urlopen(url)) as stream:
            next = parse(stream).xpath("//meta[@http-equiv = 'refresh']/@content")
            if next:
                url = next[0].split(";")[1].strip().replace("url=", "")
            else:
                return stream.geturl()

print follow("http://thetechshowdown.com/Redirect4.php")

我将把错误处理留给您:)还请注意,如果目标页面也包含一个<meta>标记,这可能会导致无休止的循环。这不是您的情况,但是您可以添加一些检查来防止这种情况:在n重定向之后停止,查看页面是否重定向到它自己,无论您认为哪个更好。在

您可能需要安装lxml库。在

来自html的元刷新重定向URL可能类似于以下任何一个:

相对URL:

<meta http-equiv="refresh" content="0; url=legal_notices_en.htm#disclaimer">

引号内有引号:

^{pr2}$

标记的content中的大写字母:

<meta http-equiv="refresh" content="0; URL=legal_notices_en.htm#disclaimer">

小结:

  • 使用lxml.xml文件要解析html
  • 使用一个lower()和两个split()来获取url部分
  • 去掉最后的引号和空格
  • 获取绝对url
  • 使用shelves将结果的缓存存储在本地文件中(如果有大量的url要测试,则非常有用)。在

用法:

print get_redirections('https://www.google.com')

返回如下内容:

{'final': u'https://www.google.be/?gfe_rd=fd&ei=FDDASaSADFASd', 'history': [<Response [302]>]}

代码:

from urlparse import urljoin, urlparse
import urllib, shelve, lxml, requests
from lxml import html

def get_redirections(initial_url, url_id = None):
    if not url_id:
        url_id = initial_url
    documents_checked = shelve.open('tested_urls.log')
    if url_id in documents_checked:
        print 'cached'
        output = documents_checked[url_id]
    else:
        print 'not cached'
        redirecting = True
        history = []
        try:
            current_url = initial_url
            while redirecting:
                r = requests.get(current_url)
                final = r.url
                history += r.history
                status = {'final':final,'history':history}

                html = lxml.html.fromstring(r.text.encode('utf8'))
                refresh = html.cssselect('meta[http-equiv="refresh"]')
                if refresh:
                    refresh_content = refresh[0].attrib['content']

                    current_url = refresh_content.lower().split('url=')[1].split(';')[0]
                    before_stripping = ''
                    after_stripping = current_url

                    while before_stripping != after_stripping:
                        before_stripping = after_stripping
                        after_stripping = before_stripping.strip('"').strip("'").strip()

                    current_url = urljoin(final, after_stripping)
                    history += [current_url]

                else:
                    redirecting = False

        except requests.exceptions.RequestException as e:
            status = {'final':str(e),'history':[],'error':e}

        documents_checked[url_id] = status
        output = status

    documents_checked.close()
    return output

url = 'http://google.com'
print get_redirections(url)

相关问题 更多 >