就库的范围,个人认为网络爬虫必备库知识包括urllib、requests、re、BeautifulSoup、concurrent.futures,接下来将结对concurrent.futures库的使用方法进行总结
建议阅读本博的博友先阅读下上篇博客:python究竟要不要使用多线程,将会对concurrent.futures库的使用有帮助。

1. concurrent.futures库简介

  python标准库为我们提供了threading和mutiprocessing模块实现异步多线程/多进程功能。从python3.2版本开始,标准库又为我们提供了concurrent.futures模块来实现线程池和进程池功能,实现了对threading和mutiprocessing模块的高级抽象,更大程度上方便了我们python程序员。

  concurrent.futures模块提供了ThreadPoolExecutorProcessPoolExecutor两个类

(1)看下来个类的继承关系和关键属性

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

print('ThreadPoolExecutor继承关系:',ThreadPoolExecutor.__mro__)
print('ThreadPoolExecutor属性:',[attr for attr in dir(ThreadPoolExecutor) if not attr.startswith('_')])
print('ProcessPoolExecutor继承关系:',ProcessPoolExecutor.__mro__)
print('ThreadPoolExecutor属性:',[attr for attr in dir(ProcessPoolExecutor) if not attr.startswith('_')])

  都继承自futures._base.Executor类,拥有三个重要方法map、submit和shutdow,这样看起来就很简单了

(2)再看下futures._base.Executor基类实现

class Executor(object):
"""This is an abstract base class for concrete asynchronous executors.""" def submit(self, fn, *args, **kwargs):
"""Submits a callable to be executed with the given arguments. Schedules the callable to be executed as fn(*args, **kwargs) and returns
a Future instance representing the execution of the callable. Returns:
A Future representing the given call.
"""
raise NotImplementedError() def map(self, fn, *iterables, timeout=None, chunksize=):
"""Returns an iterator equivalent to map(fn, iter). Args:
fn: A callable that will take as many arguments as there are
passed iterables.
timeout: The maximum number of seconds to wait. If None, then there
is no limit on the wait time.
chunksize: The size of the chunks the iterable will be broken into
before being passed to a child process. This argument is only
used by ProcessPoolExecutor; it is ignored by
ThreadPoolExecutor. Returns:
An iterator equivalent to: map(func, *iterables) but the calls may
be evaluated out-of-order. Raises:
TimeoutError: If the entire result iterator could not be generated
before the given timeout.
Exception: If fn(*args) raises for any values.
"""
if timeout is not None:
end_time = timeout + time.time() fs = [self.submit(fn, *args) for args in zip(*iterables)] # Yield must be hidden in closure so that the futures are submitted
# before the first iterator value is required.
def result_iterator():
try:
# reverse to keep finishing order
fs.reverse()
while fs:
# Careful not to keep a reference to the popped future
if timeout is None:
yield fs.pop().result()
else:
yield fs.pop().result(end_time - time.time())
finally:
for future in fs:
future.cancel()
return result_iterator() def shutdown(self, wait=True):
"""Clean-up the resources associated with the Executor. It is safe to call this method several times. Otherwise, no other
methods can be called after this one. Args:
wait: If True then shutdown will not return until all running
futures have finished executing and the resources used by the
executor have been reclaimed.
"""
pass def __enter__(self):
return self def __exit__(self, exc_type, exc_val, exc_tb):
self.shutdown(wait=True)
return False

  提供了map、submit、shutdow和with方法,下面首先对这个几个方法的使用进行说明

2. map函数

  函数原型:def map(self, fn, *iterables, timeout=None, chunksize=1)

  map函数和python自带的map函数用法一样,只不过该map函数从迭代器获取参数后异步执行,timeout用于设置超时时间

  参数chunksize的理解

The size of the chunks the iterable will be broken into
before being passed to a child process. This argument is only
used by ProcessPoolExecutor; it is ignored by ThreadPoolExecutor.

  例:

from concurrent.futures import ThreadPoolExecutor
import time
import requests def download(url):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
'Connection':'keep-alive',
'Host':'example.webscraping.com'}
response = requests.get(url, headers=headers)
return(response.status_code) if __name__ == '__main__':
urllist = ['http://example.webscraping.com/places/default/view/Afghanistan-1',
'http://example.webscraping.com/places/default/view/Aland-Islands-2'] pool = ProcessPoolExecutor(max_workers = 2)
start = time.time()
result = list(pool.map(download, urllist))
end = time.time()
print('status_code:',result)
print('使用多线程--timestamp:{:.3f}'.format(end-start))

3. submit函数

  函数原型:def submit(self, fn, *args, **kwargs)

  fn:需要异步执行的函数

  args、kwargs:函数传递的参数

  :下例中future类的使用的as_complete后面介绍

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,as_completed
import time
import requests def download(url):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
'Connection':'keep-alive',
'Host':'example.webscraping.com'}
response = requests.get(url, headers=headers)
return response.status_code if __name__ == '__main__':
urllist = ['http://example.webscraping.com/places/default/view/Afghanistan-1',
'http://example.webscraping.com/places/default/view/Aland-Islands-2'] start = time.time()
pool = ProcessPoolExecutor(max_workers = )
futures = [pool.submit(download,url) for url in urllist]
for future in futures:
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print('#### 分界线 ####')
for future in as_completed(futures, timeout=):
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print(future.result())
end = time.time()
print('使用多线程--timestamp:{:.3f}'.format(end-start))

  输出

  

4. shutdown函数

  函数原型:def shutdown(self, wait=True)

  此函数用于释放异步执行操作后的系统资源

  由于_base.Executor类提供了上下文方法,将shutdown封装在了__exit__中,若使用with方法,将不需要自己进行资源释放

with ProcessPoolExecutor(max_workers = ) as pool:

5. Future类

  submit函数返回Future对象,Future类提供了跟踪任务执行状态的方法:

  future.running():判断任务是否执行

  futurn.done:判断任务是否执行完成

  futurn.result():返回函数执行结果

futures = [pool.submit(download,url) for url in urllist]
for future in futures:
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print('#### 分界线 ####')
for future in as_completed(futures, timeout=):
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print(future.result())

  as_completed方法传入futures迭代器和timeout两个参数

  默认timeout=None,阻塞等待任务执行完成,并返回执行完成的future对象迭代器,迭代器是通过yield实现的。

  timeout>0,等待timeout时间,如果timeout时间到仍有任务未能完成,不再执行并抛出异常TimeoutError

6. 回调函数

  Future类提供了add_done_callback函数可以自定义回调函数:

def add_done_callback(self, fn):
"""Attaches a callable that will be called when the future finishes. Args:
fn: A callable that will be called with this future as its only
argument when the future completes or is cancelled. The callable
will always be called by a thread in the same process in which
it was added. If the future has already completed or been
cancelled then the callable will be called immediately. These
callables are called in the order that they were added.
"""
with self._condition:
if self._state not in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]:
self._done_callbacks.append(fn)
return
fn(self)

  例子:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,as_completed
import time
import requests def download(url):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
'Connection':'keep-alive',
'Host':'example.webscraping.com'}
response = requests.get(url, headers=headers)
return response.status_code def callback(future):
print(future.result()) if __name__ == '__main__':
urllist = ['http://example.webscraping.com/places/default/view/Afghanistan-1',
'http://example.webscraping.com/places/default/view/Aland-Islands-2',
'http://example.webscraping.com/places/default/view/Albania-3',
'http://example.webscraping.com/places/default/view/Algeria-4',
'http://example.webscraping.com/places/default/view/American-Samoa-5'] start = time.time()
with ProcessPoolExecutor(max_workers = ) as pool:
futures = [pool.submit(download,url) for url in urllist]
for future in futures:
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print('#### 分界线 ####')
for future in as_completed(futures, timeout=):
future.add_done_callback(callback)
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
end = time.time()
print('使用多线程--timestamp:{:.3f}'.format(end-start))

7. wait函数

  函数原型:def wait(fs, timeout=None, return_when=ALL_COMPLETED)

def wait(fs, timeout=None, return_when=ALL_COMPLETED):
"""Wait for the futures in the given sequence to complete. Args:
fs: The sequence of Futures (possibly created by different Executors) to
wait upon.
timeout: The maximum number of seconds to wait. If None, then there
is no limit on the wait time.
return_when: Indicates when this function should return. The options
are: FIRST_COMPLETED - Return when any future finishes or is
cancelled.
FIRST_EXCEPTION - Return when any future finishes by raising an
exception. If no future raises an exception
then it is equivalent to ALL_COMPLETED.
ALL_COMPLETED - Return when all futures finish or are cancelled. Returns:
A named -tuple of sets. The first set, named 'done', contains the
futures that completed (is finished or cancelled) before the wait
completed. The second set, named 'not_done', contains uncompleted
futures.
"""
with _AcquireFutures(fs):
done = set(f for f in fs
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
not_done = set(fs) - done if (return_when == FIRST_COMPLETED) and done:
return DoneAndNotDoneFutures(done, not_done)
elif (return_when == FIRST_EXCEPTION) and done:
if any(f for f in done
if not f.cancelled() and f.exception() is not None):
return DoneAndNotDoneFutures(done, not_done) if len(done) == len(fs):
return DoneAndNotDoneFutures(done, not_done) waiter = _create_and_install_waiters(fs, return_when) waiter.event.wait(timeout)
for f in fs:
with f._condition:
f._waiters.remove(waiter) done.update(waiter.finished_futures)
return DoneAndNotDoneFutures(done, set(fs) - done)

  wait方法返回一个中包含两个元组,元组中包含两个集合(set),一个是已经完成的(completed),一个是未完成的(uncompleted)

  它接受三个参数,重点看下第三个参数:

  FIRST_COMPLETED:Return when any future finishes or iscancelled. 

  FIRST_EXCEPTION:Return when any future finishes by raising an exception,
             If no future raises an exception then it is equivalent to ALL_COMPLETED.
  ALL_COMPLETED:Return when all futures finish or are cancelled
  例:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,\
as_completed,wait,ALL_COMPLETED, FIRST_COMPLETED, FIRST_EXCEPTION
import time
import requests def download(url):
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
'Connection':'keep-alive',
'Host':'example.webscraping.com'}
response = requests.get(url, headers=headers)
return response.status_code if __name__ == '__main__':
urllist = ['http://example.webscraping.com/places/default/view/Afghanistan-1',
'http://example.webscraping.com/places/default/view/Aland-Islands-2',
'http://example.webscraping.com/places/default/view/Albania-3',
'http://example.webscraping.com/places/default/view/Algeria-4',
'http://example.webscraping.com/places/default/view/American-Samoa-5'] start = time.time()
with ProcessPoolExecutor(max_workers = ) as pool:
futures = [pool.submit(download,url) for url in urllist]
for future in futures:
print('执行中:%s, 已完成:%s' % (future.running(), future.done()))
print('#### 分界线 ####')
completed, uncompleted = wait(futures, timeout=, return_when=FIRST_COMPLETED)
for cp in completed:
print('执行中:%s, 已完成:%s' % (cp.running(), cp.done()))
print(cp.result())
end = time.time()
print('使用多线程--timestamp:{:.3f}'.format(end-start))

  输出

  只返回了一个完成的

网络爬虫必备知识之concurrent.futures库的更多相关文章

  1. 网络爬虫必备知识之urllib库

    就库的范围,个人认为网络爬虫必备库知识包括urllib.requests.re.BeautifulSoup.concurrent.futures,接下来将结合爬虫示例分别对urllib库的使用方法进行 ...

  2. 网络爬虫必备知识之requests库

    就库的范围,个人认为网络爬虫必备库知识包括urllib.requests.re.BeautifulSoup.concurrent.futures,接下来将结对requests库的使用方法进行总结 1. ...

  3. 【网络爬虫入门02】HTTP客户端库Requests的基本原理与基础应用

    [网络爬虫入门02]HTTP客户端库Requests的基本原理与基础应用 广东职业技术学院  欧浩源 1.引言 实现网络爬虫的第一步就是要建立网络连接并向服务器或网页等网络资源发起请求.urllib是 ...

  4. 网络爬虫基础知识(Python实现)

    浏览器的请求 url=请求协议(http/https)+网站域名+资源路径+参数 http:超文本传输协议(以明文的形式进行传输),传输效率高,但不安全. https:由http+ssl(安全套接子层 ...

  5. python网络爬虫,知识储备,简单爬虫的必知必会,【核心】

    知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...

  6. 网络爬虫:利用selenium,pyquery库抓取并处理京东上的图片并存储到使用mongdb数据库进行存储

    一,环境的搭建已经简单的工具介绍 1.selenium,一个用于Web应用程序测试的工具.其特点是直接运行在浏览器中,就像真正的用户在操作一样.新版本selenium2集成了 Selenium 1.0 ...

  7. Python 网络爬虫的常用库汇总

    爬虫的编程语言有不少,但 Python 绝对是其中的主流之一.下面就为大家介绍下 Python 在编写网络爬虫常常用到的一些库. 请求库:实现 HTTP 请求操作 urllib:一系列用于操作URL的 ...

  8. python 爬虫基础知识一

    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 网络爬虫必备知识点 1. Python基础知识2. P ...

  9. 《Python3网络爬虫开发实战》

    推荐:★ ★ ★ ★ ★ 第1章 开发环境配置 第2章 网页基础知识 第3章 网络爬虫基础 第4章 基本库的使用 第5章 解析库的使用 第6章 数据存储 第7章 Ajax数据爬取 第8章 动态渲染页面 ...

随机推荐

  1. android各种组件的监听器

    <一>Spinner(旋转按钮或下拉列表):设置监听器为:setOnItemSelectedListener 设置动画效果为:setOnTouchListener              ...

  2. Apache commons-io实现单文件读取和写入

    Apache commons-io提供了很多类,这里只介绍FileUtils类. FileUtils类提供了一些操作文件对象的实用方法,包括文件的读取.写入.复制和比较等. 比如逐句读取和写入一个文件 ...

  3. $Android中日期和时间选择器的实现

    创建日期或时间选择窗口需要弹出Dialog的时候,Activity类的showDialog方法已经弃用了,而推荐使用的是DialogFragment,本文总结一下其具体用法. (一)日期选择器 1.创 ...

  4. 【HackerRank】 Chocolate Feast

    Little Bob loves chocolates, and goes to the store with $N money in his pocket. The price of each ch ...

  5. 转移灶,原发灶,cfDNA的外显子测序得到的突变点的关系

    文章名称:Exome Sequencing of Cell-Free DNA from Metastatic Cancer Patients IdentifiesClinically Actionab ...

  6. Qt下TCP编程

    一.服务器 1.声明一个QTcpServer对象 QTcpServer* serverListener; 2.new出对象 this->serverListener = new QTcpServ ...

  7. HTTP与HTTPS有什么区别?

    HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用 ...

  8. Spark 总结2

    网页访问时候 没有打开 注意防火墙! 启动park shell bin下面的spark-shell   这样启动的是单机版的 可以看到没有接入集群中: 应该这么玩儿  用park协议  spark:/ ...

  9. Codeforces Round #425 (Div. 2) D 树链剖分 + 树状数组维护区间

    一看就知道 可以LCA判断做 也可以树链剖分拿头暴力 然而快速读入和线段树维护区间会T70 于是只能LCA? 线段树的常数不小 于是需要另外一种办法来进行区间加减和查询区间和 就是使用树状数组 这个题 ...

  10. QT QMimeData类

    http://blog.csdn.net/xie376450483/article/details/5863810 QMimeData类提为数据提供一个容器,用来记录关于MIME类型数据的信息 QMi ...