2010-02-23 12 views

Respuesta

1

bien, parece que no hay biblioteca es compatible con él, así que he estado utilizando este código:

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 
+1

Este funciona muy bien, gracias por publicarlo. – Yehonatan

-1

Utilice BeautifulSoup o lxml para analizar el código HTML.

+0

usando un analizador de HTML que acaba de extraer la etiqueta meta de actualización es un exceso , al menos para mis propósitos. Esperaba que hubiera una biblioteca de Python HTTP que hiciera esto automáticamente. – hoju

+0

Bien 'meta' it * es * una etiqueta html, por lo que es poco probable que encuentre esta funcionalidad en una biblioteca http. –

8

que aquí hay una solución utilizando httplib2 (y la autenticación de certificados basados) BeautifulSoup y:

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 
3

Una similares solución utilizando las solicitudes y las bibliotecas lxml. También hace una simple comprobación de que lo que se prueba es en realidad HTML (un requisito en mi implementación). También es capaz de capturar y usar cookies mediante el uso de las sesiones de la biblioteca de solicitudes (algunas veces es necesario si se usa la redirección + cookies como un mecanismo anti raspado).

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 

Uso:

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

Algunas veces los redireccionamientos de actualización de meta apuntan a URL relativas. Por ejemplo, Facebook tiene ''. Sería bueno detectar URL relativas y anteponer el esquema y el host. –

+0

@JosephMornin: Adaptado. Me di cuenta de que aún no admite redirecciones circulares, aunque ... siempre algo. – mlissner

0

Si no desea utilizar bs4, puede utilizar lxml así:

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 
Cuestiones relacionadas