基础部分:
1、闭包及装饰器作用【实际开发使用】?
闭包:就是在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且 外函数的返回值是内函数的引用。
装饰器(本质就是闭包):主要作用为已经存在的对象添加额外的功能,例如日志记录、数据校验等。
2、深拷贝及浅拷贝?
深拷贝使用deepcopy()函数完成(deepcopy的本质是递归 copy)
浅拷贝有三种形式:
切片操作:b = a[:]或者b = [x for x in a];
工厂函数:b = list(a);
copy函数:b = copy.copy(a)
浅拷贝和深拷贝的区别是:浅拷贝只是将原对象在内存中引用地址拷贝
而深拷贝是将这个对象的所有内容拷贝过来了,包括值与内存地址
3、python2与python3的区别,举5例
2: 字符串以 8-bit 字符串存储 3改为: 字符串以 16-bit Unicode 字符串存储
2: print是一个类 3改为: print是一个函数
2: xrange() 生成迭代对象(range的升级版)3改为:统一使用range() 效率提升了
2: 默认编码是ASCII 3改为: 默认编码是UTF-8
2: long类型 3改为: 去除long
还有一些模块名字的改变例如queue、urllib等
4、is和==区别?
is:比较两边的内存地址是否相等
==:比较两边的数值是否相等
5、正则:写手机尾号除了4和7的正则表达式
re.match("1d{9}[0-3,5-6,8-9]",str)
6、有没有接触过多线程?怎么将线程启动起来?怎么结束线程?
创建线程对象(继承threading.Thread),并重写run()函数,线程的启动通过实例化线程对象并调用start()函数进行启动(多线程循环start()即可),结束线程通过join()函数。
7、Python3中的range(),比如range(1,100000000)将里面的数取出来,是怎么实现这个能力的?
Python3中的range() 返回的是一个Iterable(可迭代对象,注意不是迭代器),对其调用iter(Iterable)将会得到一个迭代器,而平常我们所使用range()则表示一个范围的容器。
range(start, stop, [step]) 三个参数分别如下:
- start: 计数从 start 开始。默认是从0开始。例如range(5)等价于range(0,5)
- stop: 计数到 stop 结束,但不包括 stop。例如: range(0,5)是[0, 1, 2, 3, 4]没有5的
- step:(可有 可无)步长,默认为1。例如:range(0,5)等价于range(0, 5, 1)
8、静态函数,object类?
在面向对象三大特性之一的多态中,有用到@staticmethod,这是Python的内置装饰器,用途:该函数只能访问类变量,而不能访问实例变量。
现在Python3中所有的类默认都继承object类,在Python2自定义类时不继承object类,只拥有了__doc__ , __module__和自己定义的name变量,而类的高级特性则不被继承,在实际开发中通过继承object类获得高级特性(例如继承__class__、__hash__),可以捕获异常通过__class__来定位类的名称等。
9、__slot__是什么概念?什么能力?
在定义class时通过__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量;这样Python就不会再使用dict,从而节省内存空间。
10、python中数据结构有哪些?列表,字典是怎么存储的?
列表(list)、元组(tuple)、字典(dict)、集合(set)
列表数据存储:列表是一个线性的集合,它允许用户在任何位置插入、删除、访问和替换元素。列表实现是基于数组或基于链表结构的。当使用列表迭代器的时候,双链表结构比单链表结构更快。有序的列表是元素总是按照升序或者降序排列的元素。
字典数据存储:Python 调用内部的散列函数,将键(Key)作为参数进行转换,得到一个唯一的地址(这也就解释了为什么给相同的键赋值会直接覆盖的原因,因为相同的键转换后的地址是一样滴),然后将值(Value)存放到该地址中。
11、python内存多大?如何优化内存?
Python本身内存没有限制,这和操作系统有关。
一方面可以加内存,设置更大虚拟内存;另一方面看算法(代码)是否有问题,有无数据重复;再有就是分块处理,用时间换空间;
补充:具体业务根据实际情况进行分析处理。
12、如何进行垃圾回收?
Python只会在特定情况下自启动垃圾回收(分代回收),当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。
可以通过 gc.get_threshold()查看阈值
通俗来讲就是当对象的引入计数为0时,就会被解释器回收。当然在交互模式下,内存不会马上释放,重新启动解释器就会释放了。
当然也可以手动垃圾回收,调用gc.collect()即可。不建议频繁使用,频繁使用会降低Python工作效率。
Web及Sql部分:
1、谈谈对wsgi的理解?
wsgi是描述web server与web application通信的一种规范,运行在WSGI协议之上的web框架有Flask,Django,Torando,Odoo等。
wsgi server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端。
补充:uwsgi与WSGI一样是一种通信协议是uWSGI服务器的独占协议,与wsgi协议不同是用于nginx等代理服务器通信(uWSGI是一个web服务器)
2、请解释一下MVT?
MVT其实是基于MVC设计模式的,主要用于解耦。
M 表示Model,负责与数据库交互(与MVC中的M相同)
V 表示View,是核心,负责接收请求、获取数据、返回结果(与MVC中的C相同)
T 表示Template,负责呈现内容到浏览器(与MVC中的V相同)
3、写出Session,Cookie和Token的区别?
Session是服务器在和客户端建立连接时添加客户端连接标志,代表服务器与客户端之间的一次会话,Session是对于服务器来讲的(保存在服务器:内存、redis | memcached缓存、数据库等),session_id则可以保存到Cookie(客户端)中
Cookie 存储在浏览器目录中的文本文件,一旦用户从该网站或服务器退出,Cookie 可存储在用户本地的硬盘上 (俗称浏览器缓存)
Token 就是令牌,例如你授权(登录)一个程序时,它就是个依据,判断你是否已经授权该软件,提供的主要作用就是认证(针对用户)和授权(针对APP)
补充:随着移动端的崛起,无法确定request是由浏览器发送还是移动端发送,不能从传统意义上使用Session+Cookie来验证用户身份,故产生Token。
4、请解释一下restful?说下你用过的Web框架?
restful就是接口规范(主要是基于HTTP协议的网络服务)。
Flask、Django、Torando、Odoo等
对比:
Flask|Django是同步框架,处理Json数据速度快,用来做传统项目开发比较擅长,Flask相对比Django更加轻量级,目前使用Flask也越来越多。当然也可以做互联网项目采用Flask/Django + Celery + Redis/Memcached/RabbitMQ增加异步处理能力。
Torando是异步框架,处理远程Http请求速度快,知乎所采用web框架就是Torando。
Odoo做ERP项目的大杀器,内部封装大量ERP模板,谁用谁知道。
补充:Flask目前国内外使用率上格外突出,原因:轻量级、自由、加上异步处理不比Torando弱。
5、rest_framework怎么实现api接口开发?
安装djangorestframework,做好相关配置(setting、路由等),定义序列化数据模板,在View中使用类视图继承 generics.CreateAPIView 或者函数装饰器 @api_view(['GET', 'POST']) 来实现请求控制。
补充:详细参考官方说明文档
Home - Django REST frameworkwww.django-rest-framework.org![ab204fac-6b13-eb11-8da9-e4434bdf6706.png](http://p01.5ceimg.com/content/ab204fac-6b13-eb11-8da9-e4434bdf6706.png)
6、django分布式?
使用django+celery+rabbitmq实现分布式,celery做异步,rabbitmq做消息队列。
补充:不建议使用redis作为中间件,redis单线程,当业务量增大会导致很大问题,虽然有不少人依然再用。
7、是否了解消息队列Kafka、RocketMQ?
Kafka是Apache旗下开源框架(Java),高吞吐无限消息堆积,定位于日志传输,单对于核心业务交易、订单、充值等核心业务特性不足,RocketMQ是淘宝内部用重写的框架(Java),在淘宝订单,交易,充值,流计算,消息推送,日志流式处理,binglog分发等场景。
8、支付实现(支付宝、银联、微信接口)?
支付宝、银联、微信目前是没有关于Python语言的API所对应的SDK和调用示例,所以需要自己造,不过现已经有很多成熟的轮子可以使用。
支付宝支付实现(亲测可用):
https://github.com/fzlee/alipaygithub.com微信支付实现(亲测可用):
zwczou/weixin-pythongithub.com![b1204fac-6b13-eb11-8da9-e4434bdf6706.png](http://p05.5ceimg.com/content/b1204fac-6b13-eb11-8da9-e4434bdf6706.png)
银联支付实现(参考):
https://blog.csdn.net/qq_42571805/article/details/83313683blog.csdn.net9、sql语句优化、索引及自己的见解?
推荐使用sql server profiler工具监控sql(分析出sql慢的相关语句:也就是执行时间过长,占用系统资源[cpu]的sql语句)
sql语句优化主要有以下4点:
1)保证不查询多余的列与行。
- 尽量避免select * 的存在,使用具体的列代替*,避免多余的列
- 使用where限定具体要查询的数据,避免多余的行
- 使用top,distinct关键字减少多余重复的行
2)慎用distinct关键字
3)慎用union关键字
4)连接查询的优化
根据业务需求获取需要的数据选择合适的连接查询,减少连接表的数据数量可以提高效率。尽量使用连接代替子查询,因为使用 join 时,MySQL 不会在内存中创建临时表。
索引优化:
1)较频繁的作为查询条件的字段应该创建索引;
2)唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件;
3)增、删、改操作较多的数据库字段不适合建索引;
4)索引占空间的会带来存储空间的消耗,合理使用索引。
10、redis数据类型(结构)?
string(字符串),hash(哈希),list(列表),set(集合)及 zset(sorted set:有序集合)
补充:这里会延伸一个新问题,这五个数据类型(结构)分别适应于什么业务场景?
string类型:可以直接存储序列化的对象(Json对象),也是最常用的类型;
hash类型:可以用来存储对象,这里会和string类型功能重叠,但是当对象的某个属性需要频繁修改时,不适合用string+json,每次修改都需要重新将整个对象序列化并赋值,如果使用hash类型,则可以针对某个属性单独修改,如商品的价格、销量、关注数等可以存在hash中;
list类型:lpop和rpush能实现消息队列的功能,但是不推荐,因为redis是单线程的,并且现在已经有成熟的消息队列(NIO)框架如Kafka、NSQ、RabbitMQ等;当然除了消息队列可以用来做排名(注意:是排名不是热搜);
set类型:唯一的特点使得其适合用于存储好友/关注/粉丝/感兴趣的人集合(集合元素无序且不重复)
Zset类型:有序集合是对集合的一个扩展,增加了score字段。通过score字段,我们可以选出最大或者最小的topN用来做热搜榜单(微博热搜就是如此实现的)
11、redis、mongodb区别?及项目中的使用场景?
1)数据结构:
redis有5种数据结构,mongodb较为单一(文档存储是使用BSON类型类似于JSON)但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富,而且在4.0版本支持事务操作。
2)数据分析:
mongodb内置数据分析功能(mapreduce),而Redis不支持。
3)内存管理:
Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。
MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘。
4)数据量及性能:
当物理内存够用的时候,redis>mongodb>mysql,
当物理内存不够用的时候,redis和mongodb都会使用虚拟内存。
实际上如果redis要开始虚拟内存,那很明显要么加内存条。
Mongodb数据存在内存,由linux系统mmap实现,当内存不够的时候,只将热点数据放入内存,其他的数据存在磁盘。所以Mongodb很吃硬盘。
redis业务场景可以看上一题;Mongodb可以做日志服务器,甚至可以直接替代Mysql数据库直接做核心业务数据库使用。
12、GET与POST区别?
1)GET传送的数据量较小,不能大于2KB;POST传送的数据量较大,一般被默认为不受限制【这取决于服务器设置和内存大小】
2)GET安全性相对较低,一般都在地址栏可见,POST安全性相对较高,POST传递数据比较隐私,所以在地址栏看不到;但如果没有加密,他们安全级别都是一样的,随便用抓包工具都可看到
补充:GET请求把参数包含在URL中,将请求信息放在URL后面,POST请求通过request body传递参数,将请求信息放置在报文体中
3)一般而言GET用来做查询;POST主要对数据进行增删改
4)GET请求返回的内容可以被浏览器缓存起来。而每次提交的POST,浏览器在你按F5的时候会跳出确认框,浏览器不会缓存POST请求返回的内容
13、http与https区别?
http的连接方式是无状态的,https则是SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议(前者端口80,后者443)。这里可能会延伸三次握手、对称加密算法【密钥】
爬虫部分:
1、你负责的项目有多少人参与,还是你一个人负责的?
一般在公司项目组中,如果是较大的爬虫项目是几个人协同负责编写及维护,例如全网服装商品数据爬取(国内及国外电商平台、各专卖网等);如果是十几二十个网站的爬虫项目基本一个人完全可以负责。【一般一个爬虫(反爬较多的网站|APP)编写速度为3天左右】
2、分布式主节点和从节点是怎么部署的,是通过容器(Docker),还是在python上启动进程?
通过Docker创建好环境(相关依赖包、业务代码),在子节点(Slave)服务直接复制主节点(Master)Docker,通过脚本进行启动。
补充:鉴于 Redis 的异步复制技术,出于各种原因,Slave 节点更新可能会落后于其 Master 节点。可能的原因包括,Master 节点的 I/O 写入量超过了 Slave 节点同步的速度;或者Master 节点和 Slave 节点之间有网络延迟。因此 Slave 节点与其 Master 节点之间可能存在滞后或在某一时候有一定程度上的数据不一致。
3、是定时的,还是通过提交url来启动爬虫?
一般是通过脚本定时(crontab)启动爬虫;若是做爬虫自动化系统可以通过手动提交url的方式进行启动爬虫(类似于八爪鱼工具)。
4、有1万个没有规律的url,如何批量爬取?
在进行深度爬取(一个网页里面中N多个url)会出现很多没有规律的url,通常在爬取前先做url规则定义,当然该url规则要根据所爬取的网站进行分析后设置,可以直接使用正则定义url的规则。
5、如何进行深度、定向爬取?
该问题与上个问题类似,主要就是设定爬取规则定向爬取:
1) 清晰地定义好爬虫的爬取目标,规划好主题。
2) 建立好爬取网址的过滤筛选规则以及内容的过滤筛选规则。
3) 建立好URL排序算法。
而深度爬取(深度优先算法)就是从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续追踪链接,scrapy默认就是使用的深度优先算法。
6、ip代理池怎么设置?
如果资金宽裕的话,可以直接调用第三方的ip(经济实惠)
如果资金紧缩,爬取第三方提供的免费ip之后测试可用后保存到redis或其他数据库,建立ip代理池,这里需要注意的是爬取第三方别用自己的ip,否则永久封印。
7、去重是对数据去重还是对请求url进行去重?分别是如何来实现的?
url去重可以使用Scrapy+redis实现url去重(使用set)
另一种方式:Scrapy-Redis手动添加去重url(指纹),实现实录:通过 MD5 加密,把请求体,请求方式,请求 url 放在一起。然后进行 32 进制的转义符字符串生成指纹。生成一个字符串,放到数据库中作为唯一标示。
数据去重可以使用sql语句或者pandas对爬取数据进行去重操作即可。
8、爬取的数据要做分析,这块是你在做吗?
9、那你做的这个项目是多少台服务器在部署?怎么分配任务的?
10、除了UA,COOKIE,还有哪些请求头,有什么作用?
11、遇到反爬有哪些?
请求头、cookie(参数加密)、ip、验证码、登陆等
12、滑块验证码如何进行破解?
参考另一篇文章:
xxs:python3+Selenium+PIL实现极验3滑块验证码破解(以瞪眼查为例)zhuanlan.zhihu.com13、爬取网站中的加密字符如何解决?JS混淆如何处理?
加密方式看看是否为可逆,在js中能看到加密方式,一般是在登陆是返回密钥;
如果是不可逆,直接明文关键字转成md5再发送请求就可以
14、请说一下Scrapy及底层实现?如何设置多线程?爬虫除了Scrapy还了解过其他框架吗?
Scrapy由五大组件组成:调度器(Scheduler)、下载器(Dpwnloader)、爬虫(Spider)
、实体管道(item Pipline)、Scrapy引擎(Scrapy Engine)
1)爬虫将url通过引擎交给调度器;
2)排序处理后,经ScrapyEngine,DownloaderMiddlewares(有User_Agent, Proxy代理)交给Downloader;
3)Downloader向互联网发送请求,并接收下载响应,将响应经ScrapyEngine,可选交给Spiders;
4)Spiders处理response,提取数据并将数据经ScrapyEngine交给ItemPipeline保存;
5)提取url重新经ScrapyEngine交给Scheduler进行下一个循环。直到无Url请求程序停止结束。
scrapy网络请求是基于Twisted,而Twisted默认支持多线程,而且scrapy默认也是通过多线程请求的,并且支持多核CPU的并发,我们通过一些设置提高scrapy的并发数可以提高爬取速度。
setting中设置:
CONCURRENT_REQUESTS_PER_IP = 100
CONCURRENT_REQUESTS = 100
CONCURRENT_REQUESTS_PER_DOMAIN = 100
除了Scrapy框架还有PySpider。
15、App、微信公众号爬取是如何来实现的?
16、爬个淘宝
目前爬淘宝具有时效性,之后看看能不能发个文章。
不定时更新~~!