如何在 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 中关注元刷新的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Google Chrome 中关闭 Preserve JavaScript console perseverance
如何在 Python 中关联两个音频事件(检测它们是不是相似)
如何在 macOS 中关闭 OpenCV 窗口(Python 3)?