我没有做太多线程,但想知道我是否可以同时在网页上保存图像而不是一次保存一个。
目前我的代码执行后者:
while pageCount <= 5:
soup = BeautifulSoup(urllib2.urlopen("http://www.url.../%d" % pageCount))
for link in soup.find_all("div", class_="photo"):
pic = link.findAll('img')
url = re.search("(?P<url>https?://[^\s]+\.(?:jpe?g))", str(pic)).group("url")
count +=1
urllib.urlretrieve(url,'C:\Desktop/images/pics%s.jpg' % count)
pageCount +=1
我认为采用多线程方法可以加快这一过程,但不确定如何。
由于
答案 0 :(得分:4)
scrapy正在并行执行,并准备好使用image download middleware
答案 1 :(得分:4)
Python中的多线程只会在IO因GIL
而阻塞的点上使脚本更快,任何CPU / IO密集型应用程序都不会看到任何性能提升(如果有的话,它们可能会变慢)。
我为不同的网站编写了一些刮刀(有些网站的数据量大到8+ TB)。 Python很难在单个脚本上获得全线速率,最好的办法是使用正确的作业队列(例如celery
),然后运行多个工作程序来实现并发。
如果你不想要celery
,那么另一个hacky方法是使用subprocess
来调用curl/wget/axel
的多个实例然后阻塞直到它们返回,检查退出代码,检查文件但是如果你的脚本没有干净地退出,那么你最终会得到僵尸进程(即即使在你杀死脚本后下载也会继续)。如果您不喜欢subprocess
的想法,那么您可以使用eventlet
或gevent
之类的内容,但是您无法在单个脚本上获得完整的线路费率,您将拥有运行多个工人。
某些网站具有速率限制,因此使用作业队列通常是解决此问题的一种好方法(即大量具有随机IP的EC2实例),每个网站上有X个工作人员以获得最大吞吐量。
Python是一个非常好的工具,用于抓取大量数据,你只需要正确地完成它。
此外,在许多情况下,pyquery比BeautifulSoup明显快于处理结果。至少,不要依赖BeautifulSoup库为您请求数据。使用python-requests
之类的东西来获取结果,然后将其传递给解析器(即汤或pyquery等)。
如果您计划抓取/存储大量数据(例如处理作业和下载内容时的带宽优化),还可以考虑可扩展性。存储群集允许您向其API发送URL,并且他们可以为您下载内容。这可以通过下载然后将文件上传到后端来节省浪费带宽 - 这可以将带宽费用减少一半。
还值得一提的是,已经讨论过线程+ BeautifulSoup;
Urllib2 & BeautifulSoup : Nice couple but too slow - urllib3 & threads?
答案 2 :(得分:1)
如果您寻找DIY解决方案,请使用:
我认为你可以将整个soup.findall()
的循环体映射到池中。
答案 3 :(得分:1)
只需使用pool,无论是线程还是多处理。
from multiprocessing.pool import ThreadPool
pool = ThreadPool(10) ## tweak this param
while pageCount <= 5:
soup = BeautifulSoup(urllib2.urlopen("http://www.url.../%d" % pageCount))
for link in soup.find_all("div", class_="photo"):
pic = link.findAll('img')
url = re.search("(?P<url>https?://[^\s]+\.(?:jpe?g))", str(pic)).group("url")
count +=1
_ = pool.apply_async(urllib.urlretrieve, (url,'C:\Desktop/images/pics%s.jpg' % count))
pageCount +=1
pool.close()
pool.join()