如何在Python中关注元刷新

hoj*_*oju 10 python redirect refresh urllib2 httplib2

Python的urllib2遵循3xx重定向来获取最终内容.有没有办法使urllib2(或其他一些库,如httplib2)也遵循元刷新?或者我是否需要手动为刷新元标记解析HTML?

asm*_*ier 10

以下是使用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  
Run Code Online (Sandbox Code Playgroud)


mli*_*ner 5

使用 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
Run Code Online (Sandbox Code Playgroud)

用法:

s = requests.session()
r = s.get(url)
# test for and follow meta redirects
r = follow_redirections(r, s)
Run Code Online (Sandbox Code Playgroud)


hoj*_*oju 1

好吧,似乎没有库支持它,所以我一直在使用以下代码:

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
Run Code Online (Sandbox Code Playgroud)