gpt4 book ai didi

python - 下载文件时 Scrapy i/o block

转载 作者:太空宇宙 更新时间:2023-11-03 15:00:04 28 4
gpt4 key购买 nike

我使用 Scrapy 抓取网页并下载一些文件。由于我得到的file_url会重定向到另一个url(302重定向)。所以我使用另一种方法handle_redirect来获取重定向的url。我像这样自定义文件管道。

class MyFilesPipeline(FilesPipeline):

def handle_redirect(self, file_url):
response = requests.head(file_url)
if response.status_code == 302:
file_url = response.headers["Location"]
return file_url

def get_media_requests(self, item, info):
redirect_url = self.handle_redirect(item["file_urls"][0])
yield scrapy.Request(redirect_url)

def item_completed(self, results, item, info):
file_paths = [x['path'] for ok, x in results if ok]
if not file_paths:
raise DropItem("Item contains no images")
item['file_urls'] = file_paths
return item

通过上面的代码,我可以下载文件,但是下载的过程是阻塞的,所以整个项目变得很慢。

我在 spider 中尝试了另一种解决方案,首先使用 Requests 获取重定向的 url,然后传递给另一个函数。并使用默认的文件管道。

yield scrapy.Request(
download_url[0],
meta={
"name": name,
},
dont_filter=True,
callback=self.handle_redirect)

def handle_redirect(self, response):
logging.warning("respon %s" % response.meta)
download_url = response.headers["Location"].decode("utf-8")

return AppListItem(
name=response.meta["name"],
file_urls=[download_url],
)

还是阻塞进程。

从这里开始

Using the Files Pipeline

When the item reaches the FilesPipeline, the URLs in the file_urls field are scheduled for download using the standard Scrapy scheduler and downloader (which means the scheduler and downloader middlewares are reused), but with a higher priority, processing them before other pages are scraped. The item remains “locked” at that particular pipeline stage until the files have finish downloading (or fail for some reason)

这是否意味着在文件下载之前我不能抓取下一个 url?(我没有在我的设置中设置 download_delay)

编辑

我一开始已经添加了这个:

handle_httpstatus_list = [302]

所以我不会被重定向到重定向的 url,我的第一个解决方案使用 requests 是因为我认为 yield 会像这样工作:

  1. 我抓取一个页面,保持yield回调,然后调用return item
  2. 项目传递到管道,如果它遇到一些 i/o,它会像正常的异步 i/o 一样让蜘蛛抓取下一页。

或者我必须等待下载文件才能抓取下一页?这是Scrapy的缺点吗?第二部分我没有遵循的是如何计算抓取页面的速度。例如,3s 一个完整的页面,默认并发为 16。我猜 @neverlastn 使用 16/2/3 来获得 2.5 页/s.并发16不就是可以同时处理16个请求吗?那么速度应该是16页/秒?如果我错了,请指正。

编辑2

谢谢你的回答,我现在明白怎么计算了,但是我还是不明白第二部分。在302上我第一次遇到这个问题。 Error 302 Downloading File in Scrapy我有一个像这样的网址

http://example.com/first

这将使用 302 并重定向到

http://example.com/second

但是Scrapy不会自动重定向到第二个,也无法下载有线的文件。来自此处的代码 Scrapy-redirect并在这里做RedirectMiddleware指出 scrapy 应该默认处理重定向。这就是为什么我做了一些技巧并试图修复它。我的第三个解决方案将尝试使用 Celery像这样

class MyFilesPipeline(FilesPipeline):
@app.task
def handle_redirect(self, file_url):
response = requests.head(file_url)
if response.status_code == 302:
file_url = response.headers["Location"]
return file_url

def get_media_requests(self, item, info):
redirect_url = self.handle_redirect.delay(item["file_urls"][0])
yield scrapy.Request(redirect_url)

def item_completed(self, results, item, info):
file_paths = [x['path'] for ok, x in results if ok]
if not file_paths:
raise DropItem("Item contains no images")
item['file_urls'] = file_paths
return item

因为我已经有很多蜘蛛,所以我不想使用第二种解决方案来覆盖它们。所以我在管道中处理它们,这个解决方案会更好吗?

最佳答案

您使用 requests同步/阻塞的API。这意味着您将并发数 ( CONCURRENT_REQUESTS_PER_DOMAIN ) 从(默认情况下)8 变为有效的 1。它似乎主宰了你的延迟。你在第二次尝试时做的那个技巧不错。这不使用 requests因此它应该比使用 requests 更快(不是吗?)现在,当然你会增加额外的延迟......如果你的第一个(HTML)请求需要 1s 而第二个(图像)请求需要 2s,那么整个页面你有 3s。默认并发数为 16,这意味着您将以大约 2.5 页/秒的速度爬行。当您的重定向失败并且您没有抓取图像时,该过程将花费大约。 1s 即 8 页/秒。所以你可能会看到 3 倍的减速。一种解决方案可能是通过增加 CONCURRENT_REQUESTS_PER_DOMAIN 将允许并行运行的并发请求数增加 3 倍。和/或 CONCURRENT_REQUESTS .如果您现在从带宽有限和/或延迟增加的地方运行它,另一种解决方案可能是从靠近图像服务器托管区域(例如 EC2 美国东部)的云服务器运行它。

编辑

性能用“小定律”更好理解。第一两个CONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS通常并行工作。 CONCURRENT_REQUESTS_PER_DOMAIN = 8 默认情况下,我猜你通常从单个域下载,因此你的实际并发限制是 8。并发级别(即 8)不是每秒,而是一个固定数字,就像说“那个 toastr 可以在其中最多烘烤 8 个羊角面包”。您的羊角面包烘烤的速度有多快是延迟(这是网络响应时间),您感兴趣的指标是它们的比率,即 8 个羊角面包可以并行烘烤/每个羊角面包 3 秒 = 我将烘烤 2.5 个羊角面包/秒。

enter image description here

关于 302,我不确定你到底想做什么。我认为您只是在关注它们 - 只是您手动进行。我认为 scrapy 会在扩展​​允许的代码时为你做这件事。 FilesPipeline可能无法从 handle_httpstatus_list 中获取值但是全局设置 HTTPERROR_ALLOWED_CODES应该会影响 FilesPipeline

无论如何,requests是一个糟糕的选择,因为它阻塞 = 绝对是非常糟糕的性能。 yield ing Scrapy Request s 将“让他们离开”(现在),但您将再次“遇到他们”,因为他们使用相同的资源、调度程序和下载程序来进行实际下载。这意味着它们很可能会降低您的性能……这是一件好事。我知道您在这里需要快速爬行,但 scrapy 希望您意识到自己在做什么以及何时设置并发限制,例如8 或 16,您相信 scrapy 不会以高于该速率的速率“淹没”您的目标站点。 Scrapy 会采取悲观的假设,即由同一服务器/域提供的媒体文件是到其 Web 服务器(而不是某些 CDN)的流量,并将应用相同的限制以保护目标站点和您。否则,想象一个页面恰好有 1000 张图片。如果您以某种方式“免费”获得了 1000 次下载,您将并行向服务器发出 8000 次请求,并发设置为 8 - 这不是一件好事。

如果您想“免费”获得一些下载,即不遵守并发限制的下载,您可以使用 treq .这是 Twisted 框架的请求包。 Here介绍如何在管道中使用它。使用它来访问我拥有的 API 或 Web 服务器,而不是第 3 方服务器,我会感觉更舒服。

关于python - 下载文件时 Scrapy i/o block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38800942/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com