如何绕过网站抓取时的速率限制
Web 抓取是从 Internet 收集数据的重要工具。但是,有时,由于速率限制,您在网络抓取时会被阻止。那么速率限制是如何工作的,你的爬虫又如何避免呢?
在本文中,我们将介绍什么是速率限制以及您在网络抓取时如何被阻止。然后我们将看看我们可以做些什么来避免速率限制。
Web 抓取中的速率限制是什么?
那么,限速是什么意思?
速率限制是您可以在特定时间窗口内发送的请求的硬限制。对于 API,它是您可以进行的 API 调用的最大数量。因此,当资源受到速率限制时,您不能发送超过定义限制的请求。如果超出限制,您会收到错误响应,例如:
- 放慢速度,来自此 IP 地址的请求过多
- IP 地址已达到速率限制
Cloudflare、Akamai和Datadome等 WAF 服务提供商使用速率限制主要是为了安全。同时,像亚马逊这样的 API 提供商使用速率限制来控制数据流并防止过度使用。
那么它是怎样工作的?假设您在 Web 服务器上受到速率限制。当您的爬虫超过速率限制时,网络服务器会响应429: Too Many Requests
.
有不同的限速方法。但我们对实践中的速率限制应用感兴趣。所以这里是流行的速率限制类型。
- 速率限制:最流行的速率限制方式。简单地将请求数与用户的 IP 地址相关联。
- API 速率限制:API 提供商通常要求您使用 API 密钥。提供商可以限制您在特定时间范围内可以进行的 API 调用次数。
- 地理速率限制:也可以为特定地区和国家设置速率限制。
- 基于用户会话的速率限制:WAF 供应商(如 Akamai)设置会话 cookie,然后限制您会话的请求速率。
- 基于 HTTP 请求的速率限制:Cloudflare 支持特定 HTTP 标头和 cookie 的速率限制。也可以通过 TLS 指纹实施速率限制。
为什么 API 速率受限?
许多 API 是有速率限制的,不会使 Web 服务器过载。API 速率限制还可以保护 API 免受恶意机器人和 DDoS 攻击。这些攻击会阻止合法用户使用 API 服务或完全关闭其服务。
为什么网站使用速率限制?
主要原因是为了防止服务器过载并减轻潜在的攻击。然而,即使您的意图不是恶意的,您也可能在网络抓取时陷入速率限制。原因是为了控制服务器端的数据流。
在网络抓取时绕过速率限制
您可以做些什么来避免网络抓取中的速率限制?以下是您可以使用的流行方法和技巧!
- 使用代理服务器
- 使用特定的请求标头
- 更改 HTTP 请求标头
最流行的速率限制方法是基于 IP 的速率限制。因此,最好使用代理服务器,因为大多数平台都实施基于 IP 的速率限制。
在请求中使用特定标头
我们可以使用多个标头在后端欺骗 IP。当 CDN 传送内容时,您可以尝试使用这些标头:
- X-Forwarded-Host:这是一个标头,用于在 Host HTTP 请求标头中标识客户端请求的原始主机。使用广泛的主机名列表可以绕过速率限制。您可以在此标头中传递 URL。
- X-Forwarded-For:标识通过代理服务器连接到 Web 服务器的客户端的原始 IP 地址。它需要指定用于连接的代理服务器的 IP 地址。传递单个 IP 地址或使用 IP 地址列表进行暴力破解是可能的。
下面的标头指定客户端的 IP 地址。但是,它们可能不会在每项服务中实施。您可以更改这些标头上的 IP 地址并试试运气!
- X客户端IP
- X-Remote-IP
- X-远程地址
更改 HTTP 请求标头
发送带有随机 HTTP 标头的请求可用于绕过速率限制。许多网站和 WAF 供应商使用 HTTP 标头来阻止恶意机器人。您可以随机化标题User-Agent
以避免速率限制。这是网络抓取的最佳实践。您可以从我们的文章中了解更多信息,了解避免被屏蔽的 10 个最佳技巧!
如果您使用的是 Python,您可以查看我们的指南以避免像专家一样在 Python 中阻塞!
终极解决方案:代理服务器
当您使用代理服务器时,您发送的请求将被路由到代理服务器。然后代理服务器得到响应并将数据转发给你。您无需处理限速代理,因为您始终可以使用另一个代理。因此,使用代理服务器是IP限速的最终解决方案。
虽然有公共和免费使用的代理服务器,但这些服务器通常被 WAF 供应商(例如 Cloudflare)和网站阻止。您可以在许多网站上找到免费的公共代理服务器。但 WAF 服务提供商也可以使用这些网站并阻止它们。
有两种类型的代理服务器。
- 住宅代理:IP 地址由 ISP 分配。它们比数据中心代理可靠得多,因为它们附加到实际地址。主要缺点是价格;高质量的代理服务器成本更高。
- 数据中心代理:数据中心代理是商业分配的。它们通常没有唯一地址,可以被网站和 WAF 服务标记。因此,它们比住宅代理服务器更实惠但可靠性更低。
住宅代理是行业标准,因为它们更可靠。但您也可以使用智能轮换代理,它会在您每次发送请求时自动使用随机驻留代理服务器。
Python 中的代理轮换
但是,有一个问题:如果该 IP 被阻止怎么办?
您可以构建代理服务器列表并在发送请求时轮换这些服务器!由于这将允许您使用多个 IP 地址,因此您不会因为 IP 速率限制算法而被阻止。
但是,如果存在身份验证会话,则无需在每个请求中更改代理服务器。您的会话也可以被跟踪,因此为每个请求轮换代理服务器不是一个合适的解决方案。
在开始之前,让我们先获取代理列表!
大多数公共代理服务器寿命短且不可靠。因此,当您尝试使用以下某些服务器时,它们可能无法正常工作。
138.68.60.8:3128 54.66.104.168:80 80.48.119.28:8080 157.100.26.69:80 198.59.191.234:8080 198.49.68.80:80 169.57.1.85:8123 219.78.228.211:80 88.215.9.208:80 130.41.55.190:8080 88.210.37.28:80 128.199.202.122:8080 2.179.154.157:808 165.154.226.12:80 200.103.102.18:80
第一步,将代理服务器保存在文本文件 ( proxies.txt
) 中。之后,我们将从ip:port
文件中读取对并检查它们是否正常工作。然后,我们将编写简单的同步函数来从随机代理服务器发送请求。
如果您的应用程序大规模工作,您将需要使用异步代理旋转器。您可以查看我们关于在 Python 中构建成熟的代理旋转器的指南。
为了检查代理服务器,我们将向httpbin发送请求。如果代理服务器不工作,我们将在响应中收到错误消息。
现在,让我们开始吧!
首先,我们需要从以下位置读取代理proxies.txt
:
proxies = open("proxies.txt", "r").read().strip().split("n")
我们将使用该requests
模块向 URL 发送请求。不幸的是,公共代理通常不支持 SSL。所以我们将使用 HTTP 而不是 HTTPS。
该get()
函数使用给定的代理服务器将 GET 请求发送到目标 URL。当出现错误时,返回的状态码会超过400。400到500之间的状态码表示客户端错误,超过500表示服务器端错误。如果是这种情况,该函数将返回None
。最后,如果没有错误,它会返回实际的响应。
def get(url, proxy): """ Sends a GET request to the given url using given proxy server. The proxy server is used without SSL, so the URL should be HTTP. Args: url - string: HTTP URL to send the GET request with proxy proxy - string: proxy server in the form of {ip}:{port} to use while sending the request Returns: Response of the server if the request sent successfully. Returns `None` otherwise. """ try: r = requests.get(url, proxies={"http": f"http://{proxy}"}) if r.status_code < 400: # client-side and server-side error codes are above 400 return r else: print(r.status_code) except Exception as e: print(e) return None
现在,可以检查我们的代理。该函数通过向httpbincheck_proxy()
发送 GET 请求返回 True 或 False 。我们可以从我们的代理列表中过滤掉可用的代理服务器。
def check_proxy(proxy): """ Checks the proxy server by sending a GET request to httpbin. Returns False if there is an error from the `get` function """ return get("http://httpbin.org/ip", proxy) is not None available_proxies = list(filter(check_proxy, proxies))
之后,我们可以使用该random
模块从可用的代理服务器中随机选择一个代理服务器。然后,我们将使用该get
函数发送请求!
结论
恭喜,您现在有一个片段可以从随机 IP 地址发送请求!
作为我们在文章中所涵盖内容的总结:
- 虽然有不同的方法,但最流行的一种是 IP 速率限制
- 可以通过使用不同的 HTTP 标头来传递硬限制
- 最方便的解决方案通常基于代理轮换
- 公共和免费代理服务器不可靠,更好的选择是使用住宅代理服务器。
然而,这种简单的实现对于扩展应用程序来说是不够的。有很大的改进空间。因此,再次查看我们的 Python 指南以了解可扩展的代理轮换!