赞
踩
在网络爬虫的开发过程中,重定向是一个常见的现象,尤其是在访问大型网站如百度时。重定向可以是临时的,也可以是永久的,它要求爬虫能够自动跟踪并正确处理这些跳转。本文将探讨如何使用 Python 编写爬虫以自动跟踪并处理百度页面的重定向。
HTTP 重定向是服务器告诉客户端(如浏览器或爬虫)请求的资源现在位于另一个 URL。HTTP 状态码 301(永久移动)和 302(临时移动)是最常见的重定向状态码。
表示资源已被永久移动到新的 URL,爬虫应该更新其索引以使用新的 URL。
表示资源临时移动到新的 URL,爬虫可以继续使用原始 URL。
Python 的 urllib
模块提供了处理 HTTP 请求的工具,包括自动处理重定向。然而,有时候我们需要更细粒度的控制,例如限制重定向次数或记录重定向历史。
urllib
的 urlopen
函数会自动处理重定向,但默认情况下不提供重定向的详细信息。以下是一个示例,展示如何使用 urllib
自动处理重定向:
python
import urllib.request
def fetch_url(url):
try:
response = urllib.request.urlopen(url)
return response.read().decode('utf-8')
except urllib.error.URLError as e:
print(f"Failed to reach a server: {e.reason}")
return None
# 使用示例
content = fetch_url('http://www.baidu.com')
为了更细粒度的控制,我们可以自定义重定向处理逻辑:
python from urllib import request, error class RedirectHandler(request.HTTPRedirectHandler): def __init__(self, max_redirects=10): super().__init__() self.max_redirects = max_redirects self.redirect_count = 0 def http_error_302(self, req, fp, code, msg, headers): self.redirect_count += 1 if self.redirect_count >= self.max_redirects: raise error.HTTPError(req.full_url, code, msg, headers, fp) return super().http_error_302(req, fp, code, msg, headers) def fetch_url_with_redirect_handling(url): opener = request.build_opener(RedirectHandler()) request.install_opener(opener) try: with request.urlopen(url) as response: return response.read().decode('utf-8') except error.HTTPError as e: print(f"HTTP error: {e.code}") return None except error.URLError as e: print(f"URL error: {e.reason}") return None # 使用示例 content = fetch_url_with_redirect_handling('http://www.baidu.com')
持久连接允许在一个 TCP 连接上发送多个 HTTP 请求和响应,减少了连接建立和关闭的开销。urllib
模块在 Python 3.6 之后默认支持 HTTP/1.1 的持久连接。
以下是一个使用 http.client
实现持久连接的示例:
import http.client from urllib.parse import urlparse from http.client import HTTPResponse # 代理服务器设置 proxyHost = "www.16yun.cn" proxyPort = "5445" proxyUser = "16QMSOML" proxyPass = "280651" class PersistentHTTPConnection(http.client.HTTPConnection): def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, proxy_info=None): super().__init__(host, port, timeout) self.proxy_info = proxy_info def connect(self): # 连接到代理服务器 super().connect() if self.proxy_info: # 使用 Basic Auth 认证 username, password = self.proxy_info credentials = f"{username}:{password}" credentials = "Basic " + credentials.encode('utf-8').base64().decode('utf-8') self.sock.sendall(b"Proxy-Authorization: " + credentials.encode('utf-8')) class PersistentHTTPConnectionWithProxy(PersistentHTTPConnection): def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.close() def fetch_with_persistent_connection(url, proxy_info=None): parsed_url = urlparse(url) conn = PersistentHTTPConnectionWithProxy(parsed_url.netloc, proxy_info=proxy_info) conn.connect() # 连接到代理服务器 conn.request("GET", parsed_url.path) response = conn.getresponse() if response.status == 200: return response.read().decode('utf-8') else: print(f"HTTP error: {response.status}") return None # 使用示例 content = fetch_with_persistent_connection('http://www.baidu.com', (proxyUser, proxyPass))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。