Urllib2 của Python theo sau chuyển hướng 3xx để nhận nội dung cuối cùng. Có cách nào để tạo urllib2 (hoặc một số thư viện khác chẳng hạn như httplib2) cũng theo dõi meta refreshes? Hoặc tôi có cần phải phân tích cú pháp HTML theo cách thủ công cho các thẻ meta làm mới không?cách theo dõi làm mới meta trong Python
Trả lời
OK, dường như không có thư viện hỗ trợ nó vì vậy tôi đã được sử dụng mã này:
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
Sử dụng BeautifulSoup hoặc lxml để phân tích cú pháp HTML.
sử dụng một phân tích cú pháp HTML để chỉ trích xuất các thẻ meta refresh là overkill , ít nhất là vì mục đích của tôi. Đã hy vọng có một thư viện HTTP Python đã thực hiện điều này một cách tự động. – hoju
Vâng 'meta' it * là * một thẻ html, do đó bạn không thể tìm thấy chức năng này trong thư viện http. –
Dưới đây là một giải pháp sử dụng BeautifulSoup và httplib2 (và giấy chứng nhận xác thực dựa):
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
Một tương tự giải pháp bằng cách sử dụng các yêu cầu và thư viện lxml. Cũng thực hiện một kiểm tra đơn giản rằng điều đang được thử nghiệm thực sự là HTML (một yêu cầu trong việc thực hiện của tôi). Cũng có thể nắm bắt và sử dụng cookie bằng cách sử dụng các phiên của thư viện yêu cầu (đôi khi cần thiết nếu chuyển hướng + cookie đang được sử dụng như một cơ chế chống cào).
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
Cách sử dụng:
s = requests.session()
r = s.get(url)
# test for and follow meta redirects
r = follow_redirections(r, s)
Đôi khi chuyển hướng làm mới meta trỏ đến URL tương đối. Ví dụ: Facebook thực hiện ' '. Nó sẽ là tốt để phát hiện các URL tương đối và thêm vào kế hoạch và máy chủ. –
@JosephMornin: Được chỉnh sửa. Tôi nhận ra nó vẫn không hỗ trợ chuyển hướng vòng tròn mặc dù ... luôn luôn một cái gì đó. – mlissner
Nếu bạn không muốn sử dụng BS4, bạn có thể sử dụng lxml như thế này:
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
Điều này hoạt động thực sự tốt, cảm ơn bạn đã đăng nó. – Yehonatan