如何在 Python 中关注元刷新

Posted

技术标签:

【中文标题】如何在 Python 中关注元刷新【英文标题】:how to follow meta refreshes in Python 【发布时间】:2011-01-20 01:54:42 【问题描述】:

Python 的 urllib2 遵循 3xx 重定向来获取最终内容。有没有办法让 urllib2(或其他一些库,如httplib2)也跟随meta refreshes?还是我需要手动解析 html 以获取刷新元标记?

【问题讨论】:

【参考方案1】:

这是一个使用 BeautifulSoup 和 httplib2(以及基于证书的身份验证)的解决方案:

import BeautifulSoup
import httplib2

def meta_redirect(content):
    soup  = BeautifulSoup.BeautifulSoup(content)

    result=soup.find("meta",attrs="http-equiv":"Refresh")
    if result:
        wait,text=result["content"].split(";")
        if text.strip().lower().startswith("url="):
            url=text[4:]
            return url
    return None

def get_content(url, key, cert):

    h=httplib2.Http(".cache")
    h.add_certificate(key,cert,"")

    resp, content = h.request(url,"GET")

    # follow the chain of redirects
    while meta_redirect(content):
        resp, content = h.request(meta_redirect(content),"GET") 

    return content  

【讨论】:

【参考方案2】:

使用 requests 和 lxml 库的类似解决方案。还做一个简单的检查,即被测试的东西实际上是 HTML(我的实现中的一个要求)。还能够通过使用请求库的会话来捕获和使用 cookie(如果重定向 + cookie 被用作反抓取机制,则有时是必要的)。

import magic
import mimetypes
import requests
from lxml import html 
from urlparse import urljoin

def test_for_meta_redirections(r):
    mime = magic.from_buffer(r.content, mime=True)
    extension = mimetypes.guess_extension(mime)
    if extension == '.html':
        html_tree = html.fromstring(r.text)
        attr = html_tree.xpath("//meta[translate(@http-equiv, 'REFSH', 'refsh') = 'refresh']/@content")[0]
        wait, text = attr.split(";")
        if text.lower().startswith("url="):
            url = text[4:]
            if not url.startswith('http'):
                # Relative URL, adapt
                url = urljoin(r.url, url)
            return True, url
    return False, None


def follow_redirections(r, s):
    """
    Recursive function that follows meta refresh redirections if they exist.
    """
    redirected, url = test_for_meta_redirections(r)
    if redirected:
        r = follow_redirections(s.get(url), s)
    return r

用法:

s = requests.session()
r = s.get(url)
# test for and follow meta redirects
r = follow_redirections(r, s)

【讨论】:

有时元刷新重定向指向相对 URL。例如,Facebook 提供<noscript><meta http-equiv="refresh" content="0; URL=/?_fb_noscript=1" /></noscript>。最好检测相对 URL 并预先添加方案和主机。 @JosephMornin:改编。我意识到它仍然不支持循环重定向......总是这样。【参考方案3】:

好的,好像没有库支持它所以我一直在使用这个代码:

import urllib2
import urlparse
import re

def get_hops(url):
    redirect_re = re.compile('<meta[^>]*?url=(.*?)["\']', re.IGNORECASE)
    hops = []
    while url:
        if url in hops:
            url = None
        else:
            hops.insert(0, url)
            response = urllib2.urlopen(url)
            if response.geturl() != url:
                hops.insert(0, response.geturl())
            # check for redirect meta tag
            match = redirect_re.search(response.read())
            if match:
                url = urlparse.urljoin(url, match.groups()[0].strip())
            else:
                url = None
    return hops

【讨论】:

【参考方案4】:

如果你不想使用 bs4,你可以像这样使用 lxml:

from lxml.html import soupparser

def meta_redirect(content):
    root = soupparser.fromstring(content)
    result_url = root.xpath('//meta[@http-equiv="refresh"]/@content')
    if result_url:
        result_url = str(result_url[0])
        urls = result_url.split('URL=') if len(result_url.split('url=')) < 2    else result_url.split('url=')
        url = urls[1] if len(urls) >= 2 else None
    else:
        return None
    return url

【讨论】:

【参考方案5】:

使用 BeautifulSoup 或 lxml 解析 HTML。

【讨论】:

使用 HTML 解析器来提取元刷新标签是多余的,至少对我来说是这样。希望有一个 Python HTTP 库可以自动执行此操作。 好吧meta一个html标签,所以你不太可能在http库中找到这个功能。

以上是关于如何在 Python 中关注元刷新的主要内容,如果未能解决你的问题,请参考以下文章

如何在对话框中关闭 jQuery 对话框?

如何在 Google Chrome 中关闭 Preserve JavaScript console perseverance

如何在 Python 中关联两个音频事件(检测它们是不是相似)

如何在 macOS 中关闭 OpenCV 窗口(Python 3)?

如何在 Python / Selenium 中关闭麦克风/相机弹出窗口?

如何在 python 程序中关闭 Ctrl-C 上的套接字连接