分类: Python技术

Python技术

Python是什么

Python是什么

python 中文就是蟒蛇的意思。
在计算机中,它是一种编程语言。
Python(英语发音:/ˈpaɪθən/), 是一种面向对象、解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,*个公开发行版发行于1991年。Python语法简洁而清晰,具有丰富和强大的类库。它常被昵称为胶水语言,它能够把用其他语言制作的各种模块(尤其是C/C++)很轻松地联结在一起。常见的一种应用情形是,使用Python快速生成程序的原型(有时甚至是程序的*终界面),然后对其中有特别要求的部分,用更合适的语言改写,比如3D游戏中的图形渲染模块,性能要求特别高,就可以用C++重写。
1,发展历程编辑
自从20世纪90年代初Python语言诞生至今,它逐渐被广泛应用于处理系统管理任务和Web编程。Python[1] 已经成为*受欢迎的程序设计语言之一。2011年1月,它被TIOBE编程语言排行榜评为2010年度语言。自从2004年以后,python的使用率是呈线性增长[2] 。
由于Python语言的简洁、易读以及可扩展性,在国外用Python做科学计算的研究机构日益增多,一些知名大学
已经采用Python教授程序设计课程。例如卡耐基梅隆大学的编程基础和麻省理工学院的计算机科学及编程导论就使用Python语言讲授。众多开源的科学
计算软件包都提供了Python的调用接口,
例如著名的计算机视觉库OpenCV、三维可视化库VTK、医学图像处理库ITK。而Python专用的科学计算扩展库就更多了,例如如下3个十分经典的
科学计算扩展库:NumPy、SciPy和matplotlib,它们分别为Python提供了快速数组处理、数值运算以及绘图功能。因此Python语
言及其众多的扩展库所构成的开发环境十分适合工程技术、科研人员处理实验数据、制作图表,甚至开发科学计算应用程序。
说起科学计算,首先会被提到的可能是MATLAB。然而除了MATLAB的一些专业性很强的工具箱还无法替代之外,MATLAB的大部分常用功能都可以在Python世界中找到相应的扩展库。和MATLAB相比,用Python做科学计算有如下优点:
● 首先,MATLAB是一款商用软件,并且价格不菲。而Python完全免费,众多开源的科学计算库都提供了Python的调用接口。用户可以在任何计算机上免费安装Python及其*大多数扩展库。
● 其次,与MATLAB相比,Python是一门更易学、更严谨的程序设计语言。它能让用户编写出更易读、易维护的代码。
● *后,MATLAB主要专注于工程和科学计算。然而即使在计算领域,也经常会遇到文件管理、界面设计、网络通信等各种需求。而Python有着丰富的扩展库,可以轻易完成各种高级任务,开发者可以用Python实现完整应用程序所需的各种功能。%title插图%num
2,产生
Python的创始人为Guido van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为ABC 语言的一种继承。之所以选中Python(大蟒蛇的意思)作为程序的名字,是因为他是一个叫Monty Python的喜剧团体的爱好者。
ABC是由Guido参加设计的一种教学语言。就Guido本人看来,ABC
这种语言非常优美和强大,是专门为非专业程序员设计的。但是ABC语言并没有成功,究其原因,Guido 认为是非开放造成的。Guido
决心在Python 中避免这一错误。同时,他还想实现在ABC 中闪现过但未曾实现的东西。
就这样,Python在Guido手中诞生了。可以说,Python是从ABC发展起来,主要受到了Modula-3(另一种相当优美且强大的语言,为小型团体所设计的)的影响。并且结合了Unix shell和C的习惯。
3,风格
Python在设计上坚持了清晰划一的风格,这使得Python成为一门易读、易维护,并且被大量用户所欢迎的、用途广泛的语言。
设计者开发时总的指导思想是,对于一个特定的问题,只要有一种*好的方法来解决就好了。这在由Tim
Peters写的Python格言(称为The Zen of Python)里面表述为:There should be one– and
preferably only one –obvious way to do it. 这正好和Perl语言(另一种功能类似的高级动态语言)的中心思想TMTOWTDI(There’s More Than One Way To Do It)完全相反。
Python的作者有意的设计限制性很强的语法,使得不好的编程习惯(例如if语句的下一行不向右缩进)都不能通过编译。其中很重要的一项就是Python的缩进规则。
一个和其他大多数语言(如C)的区别就是,一个模块的界限,完全是由每行的首字符在这一行的位置来决定的(而C语言
是用一对花括号{}来明确的定出模块的边界的,与字符的位置毫无关系)。这一点曾经引起过争议。因为自从C这类的语言诞生后,语言的语法含义与字符的排列
方式分离开来,曾经被认为是一种程序语言的进步。不过不可否认的是,通过强制程序员们缩进(包括if,for和函数定义等所有需要使用模块的地方),Python确实使得程序更加清晰和美观。
4,设计定位
Python的设计哲学是“优雅”、“明确”、“简单”。因此,Perl语言中“总是有多种方法来做同一件事”的理念在Python开发者中通常是难以忍受的。
Python开发者的哲学是“用一种方法,*好是只有一种方法来做一件事”。在设计Python语言时,如果面临多种选择,Python开发者一般会拒*
花俏的语法,而选择明确的没有或者很少有歧义的语法。由于这种设计观念的差异,Python源代码通常被认为比Perl具备更好的可读性,并且能够支撑大
规模的软件开发。这些准则被称为Python格言。在Python解释器内运行import this可以获得完整的列表。
Python开发人员尽量避开不成熟或者不重要的优化。一些针对非重要部位的加快运行速度的补丁通常不会被合并到Python内。所以很多人认为Python很慢。不过,根据二八定律,大多数程序对速度要求不高。在某些对运行速度要求很高的情况,Python设计师
倾向于使用JIT技术,或者用使用C/C++语言改写这部分程序。可用的JIT技术是PyPy。
Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载、派生、多继承,有益于增强源代码的复用性。Python支持重载运算符和动态类型。相对于Lisp这种传统的函数式编程语言,Python对函数式设计只提供了有限的支持。有两个标准库(functools, itertools)提供了Haskell和Standard ML中久经考验的函数式程序设计工具。
虽然Python可能被粗略地分类为“脚本语言”(script language),但实际上一些大规模软件开发计划例如Zope、Mnet及BitTorrent,Google也广泛地使用它。Python的支持者较喜欢称它为一种高级动态编程语言,原因是“脚本语言”泛指仅作简单程序设计任务的语言,如shellscript、VBScript等只能处理简单任务的编程语言,并不能与Python相提并论。
Python本身被设计为可扩充的。并非所有的特性和功能都集成到语言核心。Python提供了丰富的API和
工具,以便程序员能够轻松地使用C语言、C++、Cython来编写扩充模块。Python编译器本身也可以被集成到其它需要脚本语言的程序内。因此,很
多人还把Python作为一种“胶水语言”(glue
language)使用。使用Python将其他语言编写的程序进行集成和封装。在Google内部的很多项目,例如Google
Engine使用C++编写性能要求*高的部分,然后用Python或Java/Go调用相应的模块。《Python技术手册》的作者马特利(AlexMartelli)说:“这很难讲,不过,2004 年,Python 已在 Google 内部使用,Google 召募许多 Python高手,但在这之前就已决定使用Python,他们的目的是 Python where we can, C++ where we
must,在操控硬件的场合使用 C++,在快速开发时候使用 Python。”

Python并发技术

Python并发技术

1、前言
目前大多数编程语言都直接支持并发,而且其标准库通常还提供了一些封装程度较高的功能。并发可以用多种方式来实现,这些方式*重要的区别在于如何访问”共享数据”:是通过”共享内存”等方式直接访问,还是通过”进程间通信”等方式访问。

基于线程的并发:是指同一个系统进程里有各自独立的若干个线程,它们都在并发执行任务。这些线程一般会依序访问共享内存,以此实现数据共享。程序中,通常采用某种锁定机制来确保同一时间只有一个线程能够访问数据。

基于进程的并发:是指多个进程独立地执行任务,这些进程一般通过IPC来访问数据,如果编程语言或者程序库支持,那么也可以通过共享内存来实现数据共享。
还有一种并发,它基于并发等待,而非并发执行,这种方式通常用来实现异步IO。

Python都支持上述两种方式。
Python对多线程的支持方式相当普通,但对于多进程的支持则比大多数语言或程序库更为高级,此外Python的多进程与多线程采用同一套机制,使得开发者很容易就能在两套方案中来回切换。

由于全局解释器锁(GIL),所以Python解释器器在同一刻只能运行于一个处理器中,因此想通过多线程并发来提升程序速度,其效果可能仍然不够理想。

一般来说,计算密集型任务不适合用多线程来实现,因为者通常比非并发程序还要慢。
一种方法是改用Cython来编写代码,Cython代码实际上与Python一样,只是多加了一套写法,能够把程序编译成纯C。这种程序执行起来可以比原来快100倍,而并发很难达到这样的效果。
如果遇到使用并发的场合,而所执行的任务又是计算密集型的,*好避开GIL,改用multiprocessing模块。如何使用多线程,那么同一个进程里的线程在执行时会相互争抢GIL,但如果改用multiprocessing模块,那么每个进程都是独立的,它们都有自己的Python解释器锁,所以就不会争夺GIL了。

对于网络通信等”网络密集型”任务来说,并发可以大幅提高程序执行速度,在这种情况下,决定程序效率的注意因素是网络延迟,这与使用线程还是进程来实现并发没有多大关系。

2、计算密集型并发
使用多线程来执行计算密集型任务的效率比非并发程序的效率还要低,
这是因为python 将所有处理任务都放在了同一个核里。
使用多进程会把任务排布在多个核心上面。
计算密集型程序所使用的线程或进程数量一般与核心数相同。

(1) 用队列及多进程实现并发
(2)用Future及多进程实现并发
Python 3.2 新增了concurrent.futures模块,提供了一种优雅而高级的方式,可以用多线程或多进程实现并发。

3、IO密集型并发
(1)用队列及线程实现并发
(2) 用Future及多进程实现并发

python 架构

python 架构

 

Django: Python Web应用开发框架
Django 应该是*出名的Python框架,GAE甚至Erlang都有框架受它影响。Django是走大而全的方向,它*出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

Diesel:基于Greenlet的事件I/O框架
Diesel提供一个整洁的API来编写网络客户端和服务器。支持TCP和UDP。

Flask:一个用Python编写的轻量级Web应用框架
Flask是一个使用Python编写的轻量级Web应用框架。基于Werkzeug WSGI工具箱和Jinja2
模板引擎。Flask也被称为“microframework”,因为它使用简单的核心,用extension增加其他功能。Flask没有默认使用的数
据库、窗体验证工具。

Cubes:轻量级Python OLAP框架
Cubes是一个轻量级Python框架,包含OLAP、多维数据分析和浏览聚合数据(aggregated data)等工具。

Kartograph.py:创造矢量地图的轻量级Python框架
Kartograph是一个Python库,用来为ESRI生成SVG地图。Kartograph.py目前仍处于beta阶段,你可以在virtualenv环境下来测试。

Pulsar:Python的事件驱动并发框架
Pulsar是一个事件驱动的并发框架,有了pulsar,你可以写出在不同进程或线程中运行一个或多个活动的异步服务器。

Web2py:全栈式Web框架
Web2py是一个为Python语言提供的全功能Web应用框架,旨在敏捷快速的开发Web应用,具有快速、安全以及可移植的数据库驱动的应用,兼容Google App Engine。

Falcon:构建云API和网络应用后端的高性能Python框架
Falcon是一个构建云API的高性能Python框架,它鼓励使用REST架构风格,尽可能以*少的力气做*多的事情。

Dpark:Python版的Spark
DPark是Spark的Python克隆,是一个Python实现的分布式计算框架,可以非常方便地实现大规模数据处理和迭代计算。DPark由豆瓣实现,目前豆瓣内部的*大多数数据分析都使用DPark完成,正日趋完善。

Buildbot:基于Python的持续集成测试框架
Buildbot是一个开源框架,可以自动化软件构建、测试和发布等过程。每当代码有改变,服务器要求不同平台上的客户端立即进行代码构建和测试,收集并报告不同平台的构建和测试结果。

Zerorpc:基于ZeroMQ的高性能分布式RPC框架
Zerorpc是一个基于ZeroMQ和MessagePack开发的远程过程调用协议(RPC)实现。和 Zerorpc 一起使用的 Service API 被称为 zeroservice。Zerorpc 可以通过编程或命令行方式调用。

Bottle: 微型Python Web框架
Bottle是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。

Tornado:异步非阻塞IO的Python Web框架
Tornado的全称是Torado Web Server,从名字上看就可知道它可以用作Web服务器,但同时它也是一个Python Web的开发框架。*初是在FriendFeed公司的网站上使用,FaceBook收购了之后便开源了出来。

webpy: 轻量级的Python Web框架
webpy的设计理念力求精简(Keep it simple and powerful),源码很简短,只提供一个框架所必须的东西,不依赖大量的第三方模块,它没有URL路由、没有模板也没有数据库的访问。

Scrapy:Python的爬虫框架
Scrapy是一个使用Python编写的,轻量级的,简单轻巧,并且使用起来非常的方便。

Python优点

Python有哪些技术上的优点

1.6 Python 有哪些技术上的优点

显然,这是开发者关心的问题。如果你目前还没有程序设计背景,接下来的这些章节可能会显得有些令人费解:别担心,在本书中我们将会对这些内容逐一做出详细解释。那么对于开发者来说,这将是对Python 一些*优的技术特性的快速介绍。

面向对象

从根本上讲,Python 是一种面向对象的语言。它的类模块支持多态、操作符重载和多重继承等高级概念,并且以Python 特有的简洁的语法和类型,OOP 十分易于使用。事实上,即使你不懂这些术语,仍会发现学习Python 比学习其他OOP 语言要容易得多。

除了作为一种强大的代码构建和重用手段以外,Python 的OOP 特性使它成为面向对象系统语言如C++ 和Java 的理想脚本工具。例如,通过适当的粘接代码,Python 程序可以对C++ 、Java 和C# 的类进行子类的定制。

OOP 是Python 的一个选择而已,这一点非常重要。不必强迫自己立马成为一个面向对象高手,你同样可以继续深入学习。就像C++ 一样,Python 既支持面向对象编程也支持面向过程编程的模式。如果条件允许的话,其面向对象的工具即刻生效。这对处于预先设计阶段的策略开发模式十分有用。

免费

Python 的使用和分发是完全免费的。就像其他的开源软件一样,例如,Tcl 、Perl 、Linux 和Apache 。你可以从Internet 上免费获得Python 系统的源代码。复制Python ,将其嵌入你的系统或者随产品一起发布都没有任何限制。实际上,如果你愿意的话,甚至可以销售它的源代码。

但请别误会:”免费”并不代表”无支持”。恰恰相反,Python 的在线社区对用户需求的响应和商业软件一样快。而且,由于Python 完全开放源代码,提高了开发者的实力,并产生了一个很大的专家团队。尽管学习研究或改变一个程序语言的实现并不是对每一个人来说都那么有趣,但是当你知道还有源代码作为*终的帮助和无尽的文档资源是多么的令人欣慰。你不需要去依赖商业厂商。

Python 的开发是由社区驱动的,是Internet 大范围的协同合作努力的结果。这个团体包括Python 的创始者Guido van Rossum:Python 社区内公认的”终身的慈善独裁者”[Benevolent Dictator for Life (BDFL) ] 。Python 语言的改变必须遵循一套规范的有约束力的程序(称作PEP 流程),并需要经过规范的测试系统和BDFL 进行彻底检查。值得庆幸的是,正是这样使得Python 相对于其他语言可以保守地持续改进。

可移植

Python 的标准实现是由可移植的ANSI C 编写的,可以在目前所有的主流平台上编译和运行。例如,如今从PDA 到超级计算机,到处可以见到Python 在运行。Python 可以在下列平台上运行(这里只是部分列表):

Linux 和UNIX 系统。

微软Windows 和DOS (所有版本)。

Mac OS (包括OS X 和Classic )。

BeOS 、OS/2 、VMS 和QNX 。

实时操作系统,例如,VxWorks 。

Cray 超级计算机和IBM 大型机。

运行Palm OS 、PocketPC 和Linux 的PDA 。

运行Windows Mobile 和Symbian OS 的移动电话。

游戏终端和iPod 。

还有更多。

除了语言解释器本身以外,Python 发行时自带的标准库和模块在实现上也都尽可能地考虑到了跨平台的移植性。此外,Python 程序自动编译成可移植的字节码,这些字节码在已安装兼容版本Python 的平台上运行的结果都是相同的。

这些意味着Python 程序的核心语言和标准库可以在Linux 、Windows 和其他带有Python 解释器的平台无差别的运行。大多数Python 外围接口都有平台相关的扩展(例如,COM 支持Windows ),但是核心语言和库在任何平台都一样。就像之前我们提到的那样,Python 还包含了一个叫做Tkinter 的Tk GUI 工具包,它可以使Python 程序实现功能完整的无需做任何修改即可在所有主流GUI 平台运行的用户图形界面。

功能强大

从特性的观点来看,Python 是一个混合体。它丰富的工具集使它介于传统的脚本语言(例如,Tcl 、Scheme 和Perl )和系统语言(例如,C、C++ 和Java) 之间。Python 提供了所有脚本语言的简单和易用性,并且具有在编译语言中才能找到的高级软件工程工具。不像其他脚本语言,这种结合使Python 在长期大型的开发项目中十分有用。下面是一些Python 工具箱中的工具简介。

动态类型Python 在运行过程中随时跟踪对象的种类,不需要代码中关于复杂的类型和大小的声明。事实上,你将在第6章中看到,Python 中没有类型或变量声明这回事。因为Python 代码不是约束数据的类型,它往往自动地应用了一种广义上的对象。

自动内存管理Python 自动进行对象分配,当对象不再使用时将自动撤销对象(”垃圾回收”),当需要时自动扩展或收缩。Python 能够代替你进行底层的内存管理。

大型程序支持为了能够建立更大规模的系统,Python 包含了模块、类和异常等工具。这些工具允许你组织系统为组件,使用OOP 重用并定制代码,并以一种优雅的方式处理事件和错误。

内置对象类型Python 提供了常用的数据结构作为语言的基本组成部分。例如,列表(list )、字典(dictionary )、字符串(string )。我们将会看到,它们灵活并易于使用。例如,内置对象可以根据需求扩展或收缩,可以任意地组织复杂的信息等。

内置工具为了对以上对象类型进行处理,Python 自带了许多强大的标准操作,包括合并(concatenation )、分片(slice )、排序(sort )和映射(mapping )等。

库工具为了完成更多特定的任务,Python 预置了许多预编码的库工具,从正则表达式匹配到网络都支持。Python 的库工具在很多应用级的操作中发挥作用。

第三方工具由于Python 是开放源代码的,它鼓励开发者提供Python 内置工具之外的预编码工具。从网络上,可以找到COM 、图像处理、CORBA ORB 、XML 、数据库等很多免费的支持工具。

除了这一系列的Python 工具外,Python 保持了相当简洁的语法和设计。综合这一切得到的就是一个具有脚本语言所有可用性的强大编程工具。

可混合

Python 程序可以以多种方式轻易地与其他语言编写的组件”粘接”在一起。例如,Python 的C语言API 可以帮助Python 程序灵活地调用C程序。这意味着可以根据需要给Python 程序添加功能,或者在其他环境系统中使用Python 。例如,将Python 与C或者C++ 写成的库文件混合起来,使Python 成为一个前端语言和定制工具。就像之前我们所提到过的那样,这使Python 成为一个很好的快速原型工具;首先出于开发速度的考虑,系统可以先使用Python 实现,之后转移至C,根据不同时期性能的需要逐步实现系统。

使用简单

运行Python 程序,只需要简单地键入Python 程序并运行就可以了。不需要其他语言(例如,C或C++ )所必须的编译和链接等中间步骤。Python 可立即执行程序,这形成了一种交互式编程体验和不同情况下快速调整的能力,往往在修改代码后能立即看到程序改变后的效果。

当然,开发周期短仅仅是Python 易用性的一方面的体现。Python 提供了简洁的语法和强大的内置工具。实际上,Python 曾有种说法叫做”可执行的伪代码”。由于它减少了其他工具常见的复杂性,当实现相同的功能时,用Python 程序比采用C、C++ 和Java 编写的程序更为简单、小巧,也更灵活。

Python 是工程,不是艺术

当Python 于20 世纪90 年代初期出现在软件舞台上时,曾经引发其拥护者和另一个受欢迎脚本语言Perl 的拥护者之间的冲突,但现今已成为经典的争论。我们认为今天这种争论令人厌倦,也没有根据,开发人员都很聪明,可以找到他们自己的结论。然而,这是我在培训课程上时常被问到的问题之一,所以在此对这个话题说几句话,似乎是合适的。

故事是这样的:你可以用Python 做到一切用Perl 能做到的事,但是,做好之后,还可以阅读自己的程序代码。就是因为这样,两者的领域大部分重叠,但是,Python 更专注于产生可读性的代码。就大多数人而言,Python 强化了可读性,转换为了代码可重用性和可维护性,使得Python 更适合用于不是写一次就丢掉的程序。Perl 程序代码很容易写,但是很难读。由于多数软件在*初的创建后都有较长的生命周期,所以很多人认为Python 是一种更有效的工具。

这个故事反应出两个语言的设计者的背景,并体现出了人们选择使用Python 的一些主要原因。Python 的创立者所受的是数学家的训练,因此,他创造出来的语言具有高度的统一性,其语法和工具集都相当一致。再者,就像数学一样,其设计也具有正交性(orthogonal ),也就是这门语言大多数组成部分都遵循一小组核心概念。例如,一旦掌握Python 的多态,剩下的就只是细节而已。

与之相对比,Perl 语言的创立者是语言学家,而其设计反应了这种传统。Perl 中,相同任务有很多方式可以完成,并且语言材料的交互对背景环境敏感,有时还有相当微妙的方式,就像自然语言那样。就像著名的Perl 所说的格言:”完成的方法不止一种。”有了这种设计,Perl 语言及其用户社群在编写代码时,就一直在鼓励表达式的自由化。一个人的Perl 代码可能和另一个人的完全不同。事实上,编写独特、充满技巧性的代码,常常是Perl 用户之间的骄傲来源。

但是,任何做过任何实质性的代码维护工作的人,应该都可以证实,表达式自由度是很棒的艺术,但是,对工程来说就令人厌恶了。在工程世界中,我们需要*小化功能集和可预测性。在工程世界中,表达式自由度会造成维护的噩梦。不止一位Perl 用户向我们透漏过,太过于自由的结果通常就是程序很容易重头写起,但修改起来就不是那么容易了。

考虑一下:当人们在作画或雕塑时,他们是为自己做,为了纯粹美学考虑。其他人日后去修改图画或雕像的可能性很低。这是艺术和工程之间关键的差异。当人们在编写软件时,他们不是为自己写。事实上,他们甚至不是专门为计算机写的。而实际上,优秀的程序员知道,代码是为下一个会阅读它而进行维护或重用的人写的。如果那个人无法理解代码,在现实的开发场景中,就毫无用处了。

这就是很多人认为Python *有别于Perl 这类描述语言的地方。因为Python 的语法模型几乎会强迫用户编写可读的代码,所以Python 程序会引导他们往完整的软件开发循环流程前进。此外,因为Python 强调了诸如有限互动、统一性、规则性以及一致性这些概念,因此,会更进一步促进代码在首次编写后能够长期使用。

长期以来,Python 本身专注于代码质量,提高了程序员的生产力,以及程序员的满意度。Python 程序员也变得富有创意,以后就知道,语言本身的确对某些任务提供了多种解决办法。不过,本质上,Python 鼓励优秀的工程的方式,是其他脚本语言通常所不具备的。

至少,这是许多采用Python 的人之间所具有的共识。当然,你应该要自行判断这类说法,也就是通过了解Python 提供了什么给你。为了帮助你们入门,让我们进行下一章的学习吧。

简单易学

这一部分引出了本书的重点:相对于其他编程语言,Python 语言的核心是惊人的简单易学。实际上,你可以在几天内(如果你是有经验的程序员,或许只需要几个小时)写出不错的Python 代码。这对于那些想学习语言可以在工作中应用的专业人员来说是一个好消息,同样对于那些使用Python 进行定制或控制系统的终端用户来说也是一个好消息。如今,许多系统依赖于终端用户可以很快地学会Python 以便定制其代码的外围工具,从而提供较少的支持甚至不提供支持。尽管Python 还是有很多高级编程工具,但不论对初学者还是行家高手来说,Python 的核心语言仍是相当简单的。

名字来源于Monty Python

Python 名字的来源这不算是一项技术,但是,这似乎是令人很惊讶、保护得很好的秘密,而我们希望把它全盘托出。尽管Python 世界中都是蟒蛇的图标,但事实是,Python 创立者Guido van Rossum 是以BBC 喜剧Monty Python’s Flying Circus 来命名的。他是Monty Python 的大影迷,而很多软件开发人员也是(事实上,这两个领域似乎有种对称)。

这给Python 代码的例子加入一种幽默的特质。比如,一般来说,传统常规的变量名为”foo “和”bar “,在Python 的世界中变成了”spam “和”eggs “。而有时出现的”Brian “、”ni “、”shrubbery “等也是这样来的。这种方式甚至很大程度上影响了Python 社区:Python 会议上的演讲往往叫做”The Spanish Inquisition “。

当然,如果你熟悉这个幽默剧的话,所有这些你都会觉得很有趣,否则就没那么有意思了。你没有必要为了理解引自Monty Python (也许本书中你就会找到)的例子而刻意去熟悉这一串剧情,但是至少你现在应该知道它们的来源。

Python技术栈

Python后端技术栈

Happiness is a way of travel. Not a destination.

幸福是一种旅行方式。 不是目的地。

1.导航
1.1Python 语言基础
1.语言特点

2.语法基础

3.高级特性

1.2算法与数据结构
1.常用算法和数据结构

2.分析时间和空间复杂度

3.实现常见数据结构和算法

1.3编程范式
1.面向对象编程

2.常用设计模式

3.函数式编程

1.4操作系统
1.常用 Linux

2.进程和线程

3.内存管理

1.5网络编程
1.常用协议 TCP、IP、HTTP

2.Socket 编程基础

3.Python 并发库

1.6数据库
1.MySQL 数据库、索引优化

2.关系型和 NoSQL 的使用场景

3.Redis 缓存(常用的数据类型以及使用场景,底层实现了解会更好)

1.7Python Web框架
1.常用框架的对比,使用 Restful

2.WSGI 原理

3.Web 安全的问题

1.8系统设计
1.设计原则,如何分析

2.后端系统常用的组件(缓存、数据库、消息队列等等)

3.技术选型和实现(短网址服务、Feed 流系统)

1.9技术之外的软实力
1.学习能力

2.业务理解能力,沟通交流能力

3.心态

2.0小扩展-STAR模型
在生活中描述一件事情或者是在面试中描述项目经验,如何让我们的语言更加有条理,逻辑性?可以采用如下的模型进行梳理。

情境(situation)

什么情况下发生的

任务(task)

你是如何明确你的任务的

行动(action)

采取了什么样的行动

结果(result)

结果怎么样?学到了什么?

2.技术栈详解
2.1 Python 语言基础
2.1.1 Python 语言特性
Python 是动态强类型语言,很多人都误认为是弱类型语言,其实是错误的。

动态是指在运行期确定类型(静态则是在编译期确定类型)。强类型指的是在没有强制类型转化前,不允许两种不同类型的变量相互操作(也就是不会发生隐式类型转换)。

2.1.2 Python 作为后端语言的优缺点
为什么使用 Python ?

答:它是一门胶水语言,轮子多,应用广泛;语言灵活,生产力高,是一些创业公司以及外包项目节省时间的首选语言。但是在使用的时候,需要考虑到性能的问题,代码维护问题,以及2和3版本的兼容问题。

2.1.3 Python 其他的重要知识点
鸭子类型简单介绍

曾有一个生动的例子来描述鸭子类型:当看到一只鸟,如果它走起来像鸭子、叫起来像鸭子,游泳的时候也像鸭子,那么我们就称这只鸟是鸭子。它的关注点在对象的行为,而不是类型。比如一些常用对象 file、StringIO、socket 都支持 read/write 方法,我们可以看做类似的对象 file like object;再举个例子,在 Python 中实现了 iter 魔法方法的对象都可以用 for 迭代。

什么是 monkey patch ?

答:所谓的 monkey patch 就是运行时的属性替换。比如我们常用的一个并发库 gevent ,需要将内置的 socket 修改为非阻塞。我们在使用的时候,用到如下的代码:

from gevent import monkey

打补丁,让gevent框架识别耗时操作,比如:time.sleep,网络请求延时
monkey.patch_all()
什么是自省?

答:自省就是在运行时判断一个对象的类型的能力。我们可以通过 type、id和 isinstance 等方法获取对象类型的信息。Inspect 模块提供了更多获取对象信息的函数。

什么是列表和字典推导式?

列表生成式:

my_list = [i for i in range(10) if i % 2 == 0]
字典推导式:

dict1 = {k: v for k, v in zip(a, b)}
特殊的情况:将列表推导式的方括号修改为小括号的时候,会返回一个生成器。

2.1.4 Python 之禅
The Zen of Python 便是著名的Python 之禅,它是由 Tim Peters 编写的关于 Python 编程的准则,我们可以使用下面的代码进行查看:

import this
我们在编程的过程中,如果拿不准的时候可以进行一个参考。

2.2 Python2 和 Python3 的差异
2.2.1 Python2/3 差异
Python3 中做了一些改进,我们需要了解。比如 print 成为了函数;还有编码的问题,Python3 中不再有 Unicode 对象,默认 str 就是 Unicode;除法也有所变化,比如 Python3 除法返回的是浮点数。

Python2 里面是没有类型申明的,Python3 中我们可以添加一个类型注解(type hint),帮助 IDE 实现类型提示以及类型检查(mypy)。Python3 中优化的 super() 方便直接调用父类函数。Python3 中还有一些高级的解包操作,如下面示例:

a, b, *rest = range(10)
上面会将0赋值给 a,将1赋值给 b,然后将剩下的赋值给 rest。

类型检查示例:

In [2]: def fuction(name: str): return ‘hello’ + name
In [3]: fuction(‘Ethan’)
Out[3]: ‘helloEthan’
Python3 限定关键字参数。也就是函数在传参的时候,我们可以通过关键字参数方式,指定参数名传参,避免参数太多时候搞混。

Python3 中重新抛出异常不会丢失栈信息,方便我们去排错(在 Python2 中如果在一个异常中 raise 一个异常,原来的异常就会丢失,Python3 中支持 raise from,保留异常栈信息)。

Python3 中一切都是返回迭代器,比如 range/zip/map/dict.value/etc. are all iterators。

2.2.2 Python3 新增
1.yield from 链接子生成器

2.asyncio 内置库, async、await 原生协程支持异步编程

3.新的内置库 enum(枚举),mock(单测时用),asyncio, ipaddress (处理ip地址)等等。

2.2.3 Python3 改进
1.生成的 pyc 文件统一放到 __pycache__文件夹下。

2.一些内置库的修改。如 urllib,selector(支持select、epoll等Linux底层的一些封装,方便我们统一做一些接口,实现异步IO) 等。

3.一些性能的优化,比如 dict。

2.2.4一些兼容2、3的工具

six 模块。

2to3 等工具转换代码。(脚本工具,将 Python2 转换为 Python3 代码)

__future__模块。在 Python2 中使用 Python3 的函数功能可参照如下代码:

from future import print_fuction
2.3 Python 函数
2.3.1 Python 如何传递参数?
答:Python 其实不是引用传递也不是值传递,而是共享传参(函数形参获得实参中各个引用的副本)。简单的理解一下:

我们在每一次传递参数的时候,形参和实参都指向同一个对象,这样就叫做对象传递,既不是拷贝了一个值,也不是直接去操作这块内存,但是它的结果有两个。对于可变对象来说,我们直接去修改它,对于不可变对象来说,表现就好像 copy 了一个值,然后去修改新的值。

不可变对象好像是传值,可变对象好像是传引用。但是实际是不同的。

2.3.2 Python 可变/不可变对象
1.可变对象:bool、int、float、tuple、str

2.不可变对象:list、set、dict

可变对象作为默认参数的时候,注意默认参数只计算一次。

2.3.3 Python 中 *args 和 **kwargs
函数传递中,他们处理可变参数。如果使用 *args那么会将所有的参数打包成一个 tuple 对象。 **kwargs 则是将所有的关键字参数打包成一个 dict 对象。

2.4 Python 异常机制
2.4.1什么是 Python 的异常?
答:异常就是一种错误处理机制。所有的异常都继承自 BaseException 。举几个和系统相关的异常:SystemExit、KeyboardInterrupt、GeneratorExit(生成器退出的异常)。还有一个异常的基类就是 Exception。

2.4.2使用异常的常见场景
答:网络请求(超时、连接错误);资源访问(权限问题、资源不存在);代码逻辑(越界访问、KeyError等)。

2.4.3处理异常
try:
# 可能会抛出异常的代码
except (Exception1, Exception2) as e:
# 异常处理代码
else:
# 异常没有发生时代码逻辑
finally:
# 无论异常有没有发生都会执行的代码,一般处理资源的关闭和释放。
2.4.4如何自定义异常
1.继承自 Exception 实现自定义异常(想想为什么不是 BaseException)

可以通过查看异常的等级信息,发现如果继承自顶级父类,那么一些常用的异常也没有了,自己需要定义的异常就太多太多,耗费时间。

2.可以给异常加上一些附加信息。

3.通常都是处理一些和业务相关的特定异常(raise MyException)

2.5 Python 性能分析与优化
Python 作为一门脚本语言来说,它的性能一直被诟病。并且由于存在一个臭名昭著的 GIL 导致没有办法充分利用多核,这都限制了 Python 的性能。

2.5.1什么是 CPython GIL?
GIL (Global Interpreter Lock)

1.CPython 解释器的内存管理并不是线程安全的,存在多个线程时,有可能会出现同时修改同一对象,这样容易出现问题。

2.为了保护多线程情况下对 Python 对象的访问,CPython 使用了简单的锁机制避免多个线程同时执行字节码。

缺陷便是没有办法同时利用 CPU 的多核,只有一个线程执行字节码。对于 CPU 密集型的程序来说,影响会比较大。

2.5.2 GIL 的影响
限制了程序的多核执行。

1.同一个时间只能有一个线程执行字节码

2.CPU 密集型程序难以利用多核优势。

3.IO 期间会释放 GIL ,对 IO 密集型程序影响不大。

2.5.3如何规避 GIL 的影响
1.CPU 密集型可以使用多进程 + 进程池的方式充分的利用多核。

2.IO 密集型可以使用多线程或者是协程。

3.使用 cython 扩展(将 Python 程序转化成 C 代码的一个扩展)。

2.5.4 GIL 的实现
CPython 中才会有 GIL ,其他的解释器是没有的。底层的代码逻辑是设置一个ticker,每执行多少个字节码的时候,去检查当前是否有全局解释器锁,如果有那么执行函数释放,让其他的线程去执行;如果没有,就重新获取锁。通俗一点就是每隔一段时间,就会尝试去释放当前线程的锁,让其他线程获取锁并去执行。

2.5.5为什么有了 GIL 之后,还要关注线程安全?
Python中什么操作才是原子的?一步到位执行完的。

1.一个操作如果是一个字节码指令可以完成的就是原子的。

2.原子的是可以保证线程安全的,非原子操作不是线程安全的。

3.使用 dis 操作来分析字节码。

import dis

def update_list(l):
l[0] = 1

dis.dis(update_list)
2.5.6如何剖析程序性能
使用各种 profile 工具(内置或第三方)

1.遵循二八定律,其实大部分的时间耗时在少量的代码上。

2.通过内置的 profile 和 cprofile 等工具衡量程序的运行时间。

3.对于 web 应用来说,使用 pyflame(uber开源) 的火焰图工具分析产品的性能。

2.5.7服务端性能优化措施
web应用一般语言不会成为瓶颈。可以采用如下的一些优化措施:

1.数据结构和算法优化。

2.数据库层:索引优化、慢查询消除、批量操作减少IO、NoSQL的使用。

3.网络IO:批量操作, pipline 操作减少 IO。

4.缓存:使用内存数据库 redis、memcached 等。以此抗一些并发比较高的请求。

5.使用异步的框架或者库如 asyncio 和 celery。

6.对于并发相关的一些请求使用 gevent 协程或者多线程。

2.6 Python 生成器与协程
2.6.1什么是生成器
Generator

1.生成器就是可以生成值的函数。

2.当一个函数里有了 yield 关键字就成了生成器。

3.生成器可以挂起执行并且保持当前执行的状态。

2.6.2基于生成器的协程
Python3 之前没有原生协程,只有基于生成器的协程。

1.pep 342(Coroutines via Enhanced Generators)增强生成器功能。

2.生成器可以通过 yield 暂停执行和产出数据。

3.同时支持 send() 向生成器发送数据和 throw() 向生成器抛异常。

示例:

def coro():
# yield 关键字在 = 右边作为表达式,可以被send值
hello = yield ‘hello’
yield hello
c = coro()

输出 hello,这里调用next产出*个值 hello,之后函数暂停
print(next©)

再次调用 send 发送值,此时hello变量赋值为 world,然后yield 产出hello变量的值 world
print(c.send(‘world’))

之后协程结束,后续再send值会抛出异常StopIteration
2.6.3协程的注意点
1.协程需要使用 send(None) 或者 next(coroutine) 来 『预激』(prime) 才能启动。

2.在 yield 处协程会暂停执行。

3.单独的 yield value 会产出值给对方调用

4.可以通过 coroutine.send(value) 来给协程发送值,发送的值会赋值给 yield 表达式左边的变量 value=yield

5.协程执行完成之后(没有遇到下一个 yield 语句)会抛出 StopIteration 异常。

2.6.4协程装饰器
避免每次都要用 send 预激它。

from functools import wraps
def coroutine(func):
# 这样就不需要每次都用send(None)启动了
# 装饰器:向前执行到*个 yield 表达式,预激func
@wraps(func)
def primer(*args,**kwargs):
gen = func(*args,**kwargs)
next(gen)
return gen
return primer
2.6.5Python3 原生协程
Python3.5 引入 async/await 支持原生协程(native coroutine)

2.7单元测试
2.7.1什么是单元测试
Unit Testing

1.针对程序模块进行正确性检验。

2.一个函数,一个类进行验证。

3.自底向上保证程序正确性。

2.7.2为什么写单元测试
三无代码不可取(无文档、无注释、无单测)

1.保证代码逻辑的正确性(甚至有些采用测试驱动开发(TDD))

2.单测影响设计,易测的代码往往是高内聚低耦合的。

3.回归测试,防止改一处整个服务不可用。

2.7.3单元测试相关的库
1.nose/pytest 较为常用

2.mock 模块用来模拟替换网络请求等

3.coverage 统计测试覆盖率

如何设计测试用例:(等价类划分): 1.正常值功能测试。 2.边界值(比如*大*小,*左*右值) 3.异常值(比如None,空值,非法值)

2.8重点知识
2.8.1 Python 深拷贝与浅拷贝
浅拷贝:对于不可变对象相当于引用赋值;浅拷贝对于可变对象拷贝时只拷贝*层引用。

深拷贝:对于不可变对象同样相当于引用赋值;对于可变对象会逐层进行拷贝。

Python 中浅拷贝的方式:copy 模块的 copy 方法;对象本身的 copy 方法;工厂方法;切片(只对列表有效)。

工厂方法就是直接使用 list 等方法进行修改。 Python 中默认使用的就是浅拷贝方式。
Python技术交流群871458817 免费分享机器学习,爬虫,数据分析等,

2.8.2小结
1.不可变对象在赋值时会开辟新空间

2.可变对象在赋值时,修改一个引用的值,另一个引用也会发生改变。

3.深浅拷贝对不可变对象拷贝时,不开辟新的空间,相当于赋值操作。

4.浅拷贝在拷贝时,只拷贝顶层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化。

5.深拷贝在拷贝时,会逐层进行拷贝,直到所有的引用都是不可变对象为止。

6.Python 中有多种方式实现浅拷贝,copy 模块的 copy 函数,对象的 copy 函数,工厂方法,切片等。

7.大多数情况下,编写程序时,都是使用浅拷贝,除非有特定的需求。

8.浅拷贝的优点:拷贝速度快,占用空间少,拷贝效率高。
————————————————

Python技术工程师能力要求?

Python技术工程师能力要求?

Python这门语言近来是越来越火,在国家层面越来越被重视。除了之前热议的加入高考和中小学教育之外,现在连普通大学生也无法逃脱Python的毒手了。

 

今年Python业已加入NCRE(全国计算机等级考试)豪华套餐,与Java、C、C++等传统的强势语言并列。属于Python的首次认证考试将在今年9月进行,考试合格将可获取国家承认的计算机二级认证。

Python已经有了国家级别的认证开始,那么国家认证的Python工程师都有哪些技能要求呢?

首先,我们来看一下这次认证考试的大纲:

基本要求

1.掌握Python语言的基本语法规则。%title插图%num

2.学握不少于2个基本的Python标准库。

3.掌握不少于2个Python第三方库,掌握获取并安装第三方库的方法。

4.能够阅读和分析Python程序。

5.熟练使用IDLE开发环境,能够将脚本程序转变为可执行程序。

6.了解Python计算生态在以下方面(不限于)的主要第三方库名称:网络爬虫、数据分析、数据可视化、机器学习.Web开发等。

考试内容

一、Python语言基本语法元素

1.程序的基本语法元素:程序的格式框架缩进注释、变量、命名、保留字、数据类型、赋值语句引用。

2.基本输人输出函数: input() .eval() 、print()。

3.源程序的书写风格。

4.Python语言的特点。

二、基本数据类型

1.数字类型:整数类型、浮点数类型和复数类型。

2. 数字类型的运算:数值运算操作符、数值运算函数。

3. 字符串类型及格式化:索引切片、基本的format()格式化方法。

4.字符串类型的操作:字符串操作符处理丽数和处理方法。

5.类型判断和类型间转换。

三、程序的控制结构

1. 程序的三种控制结构。

2.程序的分支结构:单分支结构、二分支结构、多分支结构。

3.程序的循环结构:遍历循环、无限循环、break和continue循环控制。

4.程序的异常处理:try-excepl。

四、函数和代码复用

1.函数的定义和使用。

2.函数的参数传递:可选参数传递、参数名称传递、函数的返回值。

3.变量的作用域:局部变量和全局变量。

五、组合数据类型

1.组合数据类型的基本概念。

2. 列表类型:定义、索引、切片。

3.列表类型的操作:列表的操作函数,列表的操作方法。

4.字典类型:定义、索引。

5.字典类型的操作:字典的操作函数,字典的操作方法。

六、文件和数据格式化

1.文件的使用:文件打开;读写和关闭。

2.数据组织的维度:一维数据和二维数据。

3.一维数据的处理:表示.存储和处理。

4.二维数据的处理:表示存储和处理。

5. 采用CSV格式对一二维数据文件的读写。

七、Python计算生态

1.标准库;turtle库(必选) .random库(必选) .time库(可选)。

2.基本的Python内置函数。

3.第三方库的获取和安装。

3.脚本程序转变为可执行程序的第三方库:Pynsaller库(必选)。(小编注:此处出现编号重复,应为第4条)

4.第三方库:jieba库(必选) , wordcloud库(可选)。

5.更广泛的Python计算生态,只要求了解第三方库的名称,不限于以下领域;网络爬虫数据分析、文本处理、数据可视化、用户图形界面、机器学习、Web开发、游戏开发等。

从考纲可以发现,二级考察内容比较简单,但方向非常明确,除去必考的语法之外,偏重于数据、AI这两个方向。在必考的四个Python库中,turtle库用于图形绘制,random库用于随机数生成,jieba库用于中文分词。当然,Python的全能性注定它还会在更多领域大展身手。

不过也必须注意到,NCRE的考察内容还是十分浅显的,即使高分通过也并不意味着你能够成为一名合格的Python工程师。想要成为一名能在企业站稳脚跟的工程师,还需要学习很多。

如果你对web感兴趣,那么你需要掌握Django和Flask框架,这是目前Python Wed开发中*常用到的两个应用框架。

如果是想加入大热的Al大军中,那么你就需要掌握Python的机器学习库scikit-learn,TensorFlow、Keras、Theano、Caffe等机器学习框架,当然你可以只选择其中一个,不要贪多,关于它们各自的区别自行百度。

如果你以后向成为一名爬虫工程师那你就要掌握urllib、urllib2、request、bs4等包,如果是大规模的爬虫你还需要掌握Scrapy等爬虫框架。

*后一个数据科学方面,细化一点主要为数据分析和数据挖掘,这方面*主要有五个包,Pandas、Numpy、Scipy、Matplotlib,scikit-learn,其中Pandas用于数据处理,Numpy和Scipy用于数据的科学化计算,Matplotlib用于数据可视化,*后一个有scikit-learn主要用于数据挖掘算法的实现。

国家准备在Python领域发力的决心一目了然,你准备好迎接这个时代了吗?下边有Python的基础学习资料,可以免费领取。

 

你知道怎么利用利用爬虫爬网页(Python代码)必看

手教你利用爬虫爬网页(Python代码)%title插图%num

本文主要分为两个部分:一部分是网络爬虫的概述,帮助大家详细了解网络爬虫;另一部分是HTTP请求的Python实现,帮助大家了解Python中实现HTTP请求的各种方式,以便具备编写HTTP网络程序的能力。

01

网络爬虫概述

接下来从网络爬虫的概念、用处与价值和结构等三个方面,让大家对网络爬虫有一个基本的了解。

1. 网络爬虫及其应用

随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战,网络爬虫应运而生。网络爬虫(又被称为网页蜘蛛、网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。下面通过图3-1展示一下网络爬虫在互联网中起到的作用:

640?wx_fmt=png

▲图3-1 网络爬虫

网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫、聚焦网络爬虫、增量式网络爬虫、深层网络爬虫。实际的网络爬虫系统通常是几种爬虫技术相结合实现的。

搜索引擎(Search Engine),例如传统的通用搜索引擎baidu、Yahoo和Google等,是一种大型复杂的网络爬虫,属于通用性网络爬虫的范畴。但是通用性搜索引擎存在着一定的局限性:

不同领域、不同背景的用户往往具有不同的检索目的和需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。

通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。

万维网数据形式的丰富和网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现和获取。

通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。

为了解决上述问题,定向抓取相关网页资源的聚焦爬虫应运而生。

聚焦爬虫是一个自动下载网页的程序,它根据既定的抓取目标,有选择地访问万维网上的网页与相关的链接,获取所需要的信息。与通用爬虫不同,聚焦爬虫并不追求大的覆盖,而将目标定为抓取与某一特定主题内容相关的网页,为面向主题的用户查询准备数据资源。

说完了聚焦爬虫,接下来再说一下增量式网络爬虫。增量式网络爬虫是指对已下载网页采取增量式更新和只爬行新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬行的页面是尽可能新的页面。

和周期性爬行和刷新页面的网络爬虫相比,增量式爬虫只会在需要的时候爬行新产生或发生更新的页面,并不重新下载没有发生变化的页面,可有效减少数据下载量,及时更新已爬行的网页,减小时间和空间上的耗费,但是增加了爬行算法的复杂度和实现难度。

例如:想获取赶集网的招聘信息,以前爬取过的数据没有必要重复爬取,只需要获取更新的招聘数据,这时候就要用到增量式爬虫。

*后说一下深层网络爬虫。Web页面按存在方式可以分为表层网页和深层网页。表层网页是指传统搜索引擎可以索引的页面,以超链接可以到达的静态网页为主构成的Web页面。深层网络是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获得的Web页面。

例如用户登录或者注册才能访问的页面。可以想象这样一个场景:爬取贴吧或者论坛中的数据,必须在用户登录后,有权限的情况下才能获取完整的数据。

2. 网络爬虫结构

下面用一个通用的网络爬虫结构来说明网络爬虫的基本工作流程,如图3-4所示。

640?wx_fmt=png

▲图3-4 网络爬虫结构

网络爬虫的基本工作流程如下:

首先选取一部分精心挑选的种子URL。

将这些URL放入待抓取URL队列。

从待抓取URL队列中读取待抓取队列的URL,解析DNS,并且得到主机的IP,并将URL对应的网页下载下来,存储进已下载网页库中。此外,将这些URL放进已抓取URL队列。

分析已抓取URL队列中的URL,从已下载的网页数据中分析出其他URL,并和已抓取的URL进行比较去重,*后将去重过的URL放入待抓取URL队列,从而进入下一个循环。

02

HTTP请求的Python实现

通过上面的网络爬虫结构,我们可以看到读取URL、下载网页是每一个爬虫必备而且关键的功能,这就需要和HTTP请求打交道。接下来讲解Python中实现HTTP请求的三种方式:urllib2/urllib、httplib/urllib以及Requests。

1. urllib2/urllib实现

urllib2和urllib是Python中的两个内置模块,要实现HTTP功能,实现方式是以urllib2为主,urllib为辅。

1.1 首先实现一个完整的请求与响应模型

urllib2提供一个基础函数urlopen,通过向指定的URL发出请求来获取数据。*简单的形式是:

import urllib2
response=urllib2.urlopen(‘http://www.zhihu.com’)
html=response.read()
print html

其实可以将上面对http://www.zhihu.com的请求响应分为两步,一步是请求,一步是响应,形式如下:

import urllib2
# 请求
request=urllib2.Request(‘http://www.zhihu.com’)
# 响应
response = urllib2.urlopen(request)
html=response.read()
print html

上面这两种形式都是GET请求,接下来演示一下POST请求,其实大同小异,只是增加了请求数据,这时候用到了urllib。示例如下:

import urllib
import urllib2
url = ‘http://www.xxxxxx.com/login’
postdata = {‘username’ : ‘qiye’,
‘password’ : ‘qiye_pass’}
# info 需要被编码为urllib2能理解的格式,这里用到的是urllib
data = urllib.urlencode(postdata)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
html = response.read()

但是有时会出现这种情况:即使POST请求的数据是对的,但是服务器拒*你的访问。这是为什么呢?问题出在请求中的头信息,服务器会检验请求头,来判断是否是来自浏览器的访问,这也是反爬虫的常用手段。

1.2 请求头headers处理

将上面的例子改写一下,加上请求头信息,设置一下请求头中的User-Agent域和Referer域信息。

import urllib
import urllib2
url = ‘http://www.xxxxxx.com/login’
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
referer=’http://www.xxxxxx.com/’
postdata = {‘username’ : ‘qiye’,
‘password’ : ‘qiye_pass’}
# 将user_agent,referer写入头信息
headers={‘User-Agent’:user_agent,’Referer’:referer}
data = urllib.urlencode(postdata)
req = urllib2.Request(url, data,headers)
response = urllib2.urlopen(req)
html = response.read()

也可以这样写,使用add_header来添加请求头信息,修改如下:

import urllib
import urllib2
url = ‘http://www.xxxxxx.com/login’
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
referer=’http://www.xxxxxx.com/’
postdata = {‘username’ : ‘qiye’,
‘password’ : ‘qiye_pass’}
data = urllib.urlencode(postdata)
req = urllib2.Request(url)
# 将user_agent,referer写入头信息
req.add_header(‘User-Agent’,user_agent)
req.add_header(‘Referer’,referer)
req.add_data(data)
response = urllib2.urlopen(req)
html = response.read()

对有些header要特别留意,服务器会针对这些header做检查,例如:

User-Agent:有些服务器或Proxy会通过该值来判断是否是浏览器发出的请求。

Content-Type:在使用REST接口时,服务器会检查该值,用来确定HTTP Body中的内容该怎样解析。在使用服务器提供的RESTful或SOAP服务时,Content-Type设置错误会导致服务器拒*服务。常见的取值有:application/xml(在XML RPC,如RESTful/SOAP调用时使用)、application/json(在JSON RPC调用时使用)、application/x-www-form-urlencoded(浏览器提交Web表单时使用)。

Referer:服务器有时候会检查防盗链。

1.3 Cookie处理

urllib2对Cookie的处理也是自动的,使用CookieJar函数进行Cookie的管理。如果需要得到某个Cookie项的值,可以这么做:

import urllib2
import cookielib
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open(‘http://www.zhihu.com’)
for item in cookie:
print item.name+’:’+item.value

但是有时候会遇到这种情况,我们不想让urllib2自动处理,我们想自己添加Cookie的内容,可以通过设置请求头中的Cookie域来做:

import urllib2
opener = urllib2.build_opener()
opener.addheaders.append( ( ‘Cookie’, ’email=’ + “xxxxxxx@163.com” ) )
req = urllib2.Request( “http://www.zhihu.com/” )
response = opener.open(req)
print response.headers
retdata = response.read()

1.4 Timeout设置超时

在Python2.6之前的版本,urllib2的API并没有暴露Timeout的设置,要设置Timeout值,只能更改Socket的全局Timeout值。示例如下:

import urllib2
import socket
socket.setdefaulttimeout(10) # 10 秒钟后超时
urllib2.socket.setdefaulttimeout(10) # 另一种方式

在Python2.6及新的版本中,urlopen函数提供了对Timeout的设置,示例如下:

import urllib2
request=urllib2.Request(‘http://www.zhihu.com’)
response = urllib2.urlopen(request,timeout=2)
html=response.read()
print html

1.5 获取HTTP响应码

对于200 OK来说,只要使用urlopen返回的response对象的getcode()方法就可以得到HTTP的返回码。但对其他返回码来说,urlopen会抛出异常。这时候,就要检查异常对象的code属性了,示例如下:

import urllib2
try:
response = urllib2.urlopen(‘http://www.google.com’)
print response
except urllib2.HTTPError as e:
if hasattr(e, ‘code’):
print ‘Error code:’,e.code

1.6 重定向

urllib2默认情况下会针对HTTP 3XX返回码自动进行重定向动作。要检测是否发生了重定向动作,只要检查一下Response的URL和Request的URL是否一致就可以了,示例如下:

import urllib2
response = urllib2.urlopen(‘http://www.zhihu.cn’)
isRedirected = response.geturl() == ‘http://www.zhihu.cn’

如果不想自动重定向,可以自定义HTTPRedirectHandler类,示例如下:

import urllib2
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
pass
def http_error_302(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code,
msg, headers)
result.status = code
result.newurl = result.geturl()
return result
opener = urllib2.build_opener(RedirectHandler)
opener.open(‘http://www.zhihu.cn’)

1.7 Proxy的设置

在做爬虫开发中,必不可少地会用到代理。urllib2默认会使用环境变量http_proxy来设置HTTP Proxy。但是我们一般不采用这种方式,而是使用ProxyHandler在程序中动态设置代理,示例代码如下:

import urllib2
proxy = urllib2.ProxyHandler({‘http’: ‘127.0.0.1:8087’})
opener = urllib2.build_opener([proxy,])
urllib2.install_opener(opener)
response = urllib2.urlopen(‘http://www.zhihu.com/’)
print response.read()

这里要注意的一个细节,使用urllib2.install_opener()会设置urllib2的全局opener,之后所有的HTTP访问都会使用这个代理。这样使用会很方便,但不能做更细粒度的控制,比如想在程序中使用两个不同的Proxy设置,这种场景在爬虫中很常见。比较好的做法是不使用install_opener去更改全局的设置,而只是直接调用opener的open方法代替全局的urlopen方法,修改如下:

import urllib2
proxy = urllib2.ProxyHandler({‘http’: ‘127.0.0.1:8087’})
opener = urllib2.build_opener(proxy,)
response = opener.open(“http://www.zhihu.com/”)
print response.read()

2. httplib/urllib实现

httplib模块是一个底层基础模块,可以看到建立HTTP请求的每一步,但是实现的功能比较少,正常情况下比较少用到。在Python爬虫开发中基本上用不到,所以在此只是进行一下知识普及。下面介绍一下常用的对象和函数:

创建HTTPConnection对象:

class httplib.HTTPConnection(host[, port[, strict[, timeout[, source_address]]]])。

发送请求:

HTTPConnection.request(method, url[, body[, headers]])。

获得响应:

HTTPConnection.getresponse()。

读取响应信息:

HTTPResponse.read([amt])。

获得指定头信息:

HTTPResponse.getheader(name[, default])。

获得响应头(header, value)元组的列表:

HTTPResponse.getheaders()。

获得底层socket文件描述符:

HTTPResponse.fileno()。

获得头内容:

HTTPResponse.msg。

获得头http版本:

HTTPResponse.version。

获得返回状态码:

HTTPResponse.status。

获得返回说明:

HTTPResponse.reason。

接下来演示一下GET请求和POST请求的发送,首先是GET请求的示例,如下所示:

import httplib
conn =None
try:
conn = httplib.HTTPConnection(“www.zhihu.com”)
conn.request(“GET”, “/”)
response = conn.getresponse()
print response.status, response.reason
print ‘-‘ * 40
headers = response.getheaders()
for h in headers:
print h
print ‘-‘ * 40
print response.msg
except Exception,e:
print e
finally:
if conn:
conn.close()

POST请求的示例如下:

import httplib, urllib
conn = None
try:
params = urllib.urlencode({‘name’: ‘qiye’, ‘age’: 22})
headers = {“Content-type”: “application/x-www-form-urlencoded”
, “Accept”: “text/plain”}
conn = httplib.HTTPConnection(“www.zhihu.com”, 80, timeout=3)
conn.request(“POST”, “/login”, params, headers)
response = conn.getresponse()
print response.getheaders() # 获取头信息
print response.status
print response.read()
except Exception, e:
print e
finally:
if conn:
conn.close()

3. 更人性化的Requests

Python中Requests实现HTTP请求的方式,是本人*力推荐的,也是在Python爬虫开发中*为常用的方式。Requests实现HTTP请求非常简单,操作更加人性化。

Requests库是第三方模块,需要额外进行安装。Requests是一个开源库,源码位于:

GitHub: https://github.com/kennethreitz/requests

希望大家多多支持作者。

使用Requests库需要先进行安装,一般有两种安装方式:

使用pip进行安装,安装命令为:pip install requests,不过可能不是*新版。

直接到GitHub上下载Requests的源代码,下载链接为:

https://github.com/kennethreitz/requests/releases

将源代码压缩包进行解压,然后进入解压后的文件夹,运行setup.py文件即可。

如何验证Requests模块安装是否成功呢?在Python的shell中输入import requests,如果不报错,则是安装成功。如图3-5所示。

640?wx_fmt=png

▲图3-5 验证Requests安装

3.1 首先还是实现一个完整的请求与响应模型

以GET请求为例,*简单的形式如下:

import requests
r = requests.get(‘http://www.baidu.com’)
print r.content

大家可以看到比urllib2实现方式的代码量少。接下来演示一下POST请求,同样是非常简短,更加具有Python风格。示例如下:

import requests
postdata={‘key’:’value’}
r = requests.post(‘http://www.xxxxxx.com/login’,data=postdata)
print r.content

HTTP中的其他请求方式也可以用Requests来实现,示例如下:

r = requests.put(‘http://www.xxxxxx.com/put’, data = {‘key’:’value’})
r = requests.delete(‘http://www.xxxxxx.com/delete’)
r = requests.head(‘http://www.xxxxxx.com/get’)
r = requests.options(‘http://www.xxxxxx.com/get’)

接着讲解一下稍微复杂的方式,大家肯定见过类似这样的URL:

http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

就是在网址后面紧跟着“?”,“?”后面还有参数。那么这样的GET请求该如何发送呢?肯定有人会说,直接将完整的URL带入即可,不过Requests还提供了其他方式,示例如下:

import requests
payload = {‘Keywords’: ‘blog:qiyeboy’,’pageindex’:1}
r = requests.get(‘http://zzk.cnblogs.com/s/blogpost’, params=payload)
print r.url

通过打印结果,我们看到*终的URL变成了:

http://zzk.cnblogs.com/s/blogpost?Keywords=blog:qiyeboy&pageindex=1

3.2 响应与编码

还是从代码入手,示例如下:

import requests
r = requests.get(‘http://www.baidu.com’)
print ‘content–>’+r.content
print ‘text–>’+r.text
print ‘encoding–>’+r.encoding
r.encoding=’utf-8’
print ‘new text–>’+r.text

其中r.content返回的是字节形式,r.text返回的是文本形式,r.encoding返回的是根据HTTP头猜测的网页编码格式。

输出结果中:“text–>”之后的内容在控制台看到的是乱码,“encoding–>”之后的内容是ISO-8859-1(实际上的编码格式是UTF-8),由于Requests猜测编码错误,导致解析文本出现了乱码。Requests提供了解决方案,可以自行设置编码格式,r.encoding=’utf-8’设置成UTF-8之后,“new text–>”的内容就不会出现乱码。

但是这种手动的方式略显笨拙,下面提供一种更加简便的方式:chardet,这是一个非常优秀的字符串/文件编码检测模块。安装方式如下:

pip install chardet

安装完成后,使用chardet.detect()返回字典,其中confidence是检测精确度,encoding是编码形式。示例如下:

import requests
r = requests.get(‘http://www.baidu.com’)
print chardet.detect(r.content)
r.encoding = chardet.detect(r.content)[‘encoding’]
print r.text

直接将chardet探测到的编码,赋给r.encoding实现解码,r.text输出就不会有乱码了。

除了上面那种直接获取全部响应的方式,还有一种流模式,示例如下:

import requests
r = requests.get(‘http://www.baidu.com’,stream=True)
print r.raw.read(10)

设置stream=True标志位,使响应以字节流方式进行读取,r.raw.read函数指定读取的字节数。

3.3 请求头headers处理

Requests对headers的处理和urllib2非常相似,在Requests的get函数中添加headers参数即可。示例如下:

import requests
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
headers={‘User-Agent’:user_agent}
r = requests.get(‘http://www.baidu.com’,headers=headers)
print r.content

3.4 响应码code和响应头headers处理

获取响应码是使用Requests中的status_code字段,获取响应头使用Requests中的headers字段。示例如下:

import requests
r = requests.get(‘http://www.baidu.com’)
if r.status_code == requests.codes.ok:
print r.status_code# 响应码
print r.headers# 响应头
print r.headers.get(‘content-type’)# 推荐使用这种获取方式,获取其中的某个字段
print r.headers[‘content-type’]# 不推荐使用这种获取方式
else:
r.raise_for_status()

上述程序中,r.headers包含所有的响应头信息,可以通过get函数获取其中的某一个字段,也可以通过字典引用的方式获取字典值,但是不推荐,因为如果字段中没有这个字段,第二种方式会抛出异常,*种方式会返回None。

r.raise_for_status()是用来主动地产生一个异常,当响应码是4XX或5XX时,raise_for_status()函数会抛出异常,而响应码为200时,raise_for_status()函数返回None。

3.5 Cookie处理

如果响应中包含Cookie的值,可以如下方式获取Cookie字段的值,示例如下:

import requests
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
headers={‘User-Agent’:user_agent}
r = requests.get(‘http://www.baidu.com’,headers=headers)
# 遍历出所有的cookie字段的值
for cookie in r.cookies.keys():
print cookie+’:’+r.cookies.get(cookie)

如果想自定义Cookie值发送出去,可以使用以下方式,示例如下:

import requests
user_agent = ‘Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)’
headers={‘User-Agent’:user_agent}
cookies = dict(name=’qiye’,age=’10’)
r = requests.get(‘http://www.baidu.com’,headers=headers,cookies=cookies)
print r.text

还有一种更加高级,且能自动处理Cookie的方式,有时候我们不需要关心Cookie值是多少,只是希望每次访问的时候,程序自动把Cookie的值带上,像浏览器一样。Requests提供了一个session的概念,在连续访问网页,处理登录跳转时特别方便,不需要关注具体细节。使用方法示例如下:

import Requests
oginUrl = ‘http://www.xxxxxxx.com/login’
s = requests.Session()
#首先访问登录界面,作为游客,服务器会先分配一个cookie
r = s.get(loginUrl,allow_redirects=True)
datas={‘name’:’qiye’,’passwd’:’qiye’}
#向登录链接发送post请求,验证成功,游客权限转为会员权限
r = s.post(loginUrl, data=datas,allow_redirects= True)
print r.text

上面的这段程序,其实是正式做Python开发中遇到的问题,如果没有*步访问登录的页面,而是直接向登录链接发送Post请求,系统会把你当做非法用户,因为访问登录界面时会分配一个Cookie,需要将这个Cookie在发送Post请求时带上,这种使用Session函数处理Cookie的方式之后会很常用。

3.6 重定向与历史信息

处理重定向只是需要设置一下allow_redirects字段即可,例如:

r=requests.get(‘http://www.baidu.com’,allow_redirects=True)

将allow_redirects设置为True,则是允许重定向;设置为False,则是禁止重定向。如果是允许重定向,可以通过r.history字段查看历史信息,即访问成功之前的所有请求跳转信息。示例如下:

import requests
r = requests.get(‘http://github.com’)
print r.url
print r.status_code
print r.history

打印结果如下:

https://github.com/
200
(,)

上面的示例代码显示的效果是访问GitHub网址时,会将所有的HTTP请求全部重定向为HTTPS。

3.7 超时设置

超时选项是通过参数timeout来进行设置的,示例如下:

requests.get(‘http://github.com’, timeout=2)

3.8 代理设置

使用代理Proxy,你可以为任意请求方法通过设置proxies参数来配置单个请求:

import requests
proxies = {
“http”: “http://0.10.1.10:3128”,
“https”: “http://10.10.1.10:1080”,
}
requests.get(“http://example.org”, proxies=proxies)

也可以通过环境变量HTTP_PROXY和HTTPS_PROXY?来配置代理,但是在爬虫开发中不常用。你的代理需要使用HTTP Basic Auth,可以使用http://user:password@host/语法:

proxies = {
“http”: “http://user:pass@10.10.1.10:3128/”,
}

03

小结

本文主要讲解了网络爬虫的结构和应用,以及Python实现HTTP请求的几种方法。希望大家对本文中的网络爬虫工作流程和Requests实现HTTP请求的方式重点吸收消化。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速