关于Python爬虫常见的面试题

文章目录

一、介绍爬虫

1.爬虫定义

自动的抓取互联网上信息的脚本文件。

2.爬虫分类

A.通用爬虫:搜索引擎的主要组成,作用就是将互联网的上页面整体的爬取下来之后,保存到本地。

B.聚焦爬虫:聚焦爬虫在实施网页抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息。

通用爬虫和聚焦爬虫的区别:聚焦爬虫在实施网页抓取时会对内容进行处理筛选,尽量保证只抓取与需求相关的网页信息。

3.爬虫可以解决的问题

(1)解决冷启动问题
(2)搜索引擎的根基:做搜索引擎少不了爬虫
(3)可以对爬取的数据进行数据分析

4.爬虫遵循的协议

定义:robot协议(网络爬虫排除标准)
作用:告诉搜索引擎哪里可以爬,哪里不可以爬

5.一些反爬及其应对措施

( 1)通过user-agent来判断是否是爬虫

  • 解决方案:可以通过伪装请求头中的user-agent来解决。若user-agent被检测到,可以找大量的user-agent,放入列表,然后进行更换

(2)将ip进行封杀。

  • 解决方案:可以通过代理来伪装ip

(3)通过访问频率来判断是否是一个爬虫。

  • 解决方案:可以通过设置请求间隔,和爬取间隔。

(4)当一定时间内的总请求数超过上限,弹出验证码

  • 解决方案:对于简单的验证码图片可以使用tesseract来处理,对于复杂的可以去打码平台。

(5)通过js来获取页面数据。

  • 解决方案:可以使用selenium+phantomjs来加载js获取数据

二、介绍搜索引擎

1.搜索引擎的主要组成

通用爬虫:就是将互联网的上页面整体的爬取下来之后,保存到本地。

通用爬虫要想爬取网页,需要网站的url.但是搜索引擎是可以搜索所有网页的。那么通用爬虫url就要涉及到所有网页,这个‘所有’是如何做到的。

  • 新网站向搜索引擎主动提交网址
  • 在其他网站上设置新网站外链。
  • 搜索引擎和DNS解析服务商(如DNSPod等)合作,新网站域名将被迅速抓取。

2.搜索引擎的工作流程(通用爬虫的工作流程)

  1. 抓取网页:通过搜索引擎将待爬取的url加入到通用爬虫的url队列中,进行网页内容的爬取

  2. 数据存储:将爬取下来的网页保存到本地,这个过程会有一定的去重操作,如果某个网页的内 容大部分内容都会重复,搜索引擎可能不会保存

  3. 预处理:提取文字,中文分词,消除噪音(比如版权声明文字,导航条,广告等)

  4. 设置网站排名,为用户提供服务

3.搜索引擎的局限性

​ 1.搜索引擎只能爬取原网页,但是页面90%内容都是无用的
​ 2.搜索引擎不能满足不同行业,不同人的特定需求
​ 3.通用搜索引擎只能爬取文字信息,不能对音频、图片等进行爬取
​ 4.只能基于关键字查询,无法基于语义查询

三、介绍http

网络七层协议
在这里插入图片描述

1.http协议特点

  • http协议是超文本传输协议
  • http协议是一个应用层协议
  • 无连接:每次请求都是独立的。
  • 无状态,表示客户端每次请求都不能记录请求状态,就是两条请求直接不可通信

2.http工作过程

  • 地址进行DNS解析,将url解析出对应的内容
  • 封装http请求数据包
  • 封装成TCP包,建立TCP连接(TCP的三次握手)
  • 客户端发送请求
  • 服务器接收请求,发送响应
  • 客户端接收到响应,进行页面渲染
  • 服务器关闭tcp连接(TCP的四次挥手)

3.http协议和https协议的区别

  • http协议是使用明文数据传输的网络协议,明文传输会让用户存在一个非常大的安全隐患。端口80
  • HTTPS协议可以理解为HTTP协议的安全升级版,就是在HTTP的基础上增加了数据加密。端口443
  • HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议 要比http 协议安全

4.http通信

http通信由两部分组成:客户端请求消息 与 服务器响应消息

5.关于响应常见的响应码

状态码意义常见举例1常见举例2
1xx表示服务器成功接收部分请求,要求客户端继续提交其余请求才能完成整个处理过程100 :服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求101 :服务器将遵从客户的请求转换到另外一种协议
2xx表示服务器成功接收请求并已完成整个处理过程200:OK 请求成功201 :请求被创建完成,同时新的资源被创建
3xx重定向302:所请求的页面已经临时转移至新的url303 :所请求的页面可在别的url下被找到
4xx客户端错误403:对被请求页面的访问被禁止404:服务器无法找到被请求的页面
5xx服务器错误500:请求未完成。服务器遇到不可预知的情况504 :网关超时。

6.客户端请求(get和post区别)

①组成:请求行、请求头部、空行、请求数据四个部分组成

②请求方法get/post

③get和post的区别

GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

getpost
get是从服务器获取数据post是向服务器提交数据
get参数拼接在url后面,这样是明文传输,很不安全。post的参数放在body体内,相比get比较安全
get提交可以被浏览器缓存post不会被浏览器缓存
get产生一个TCP数据包(对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据))POST产生两个TCP数据包(而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 (返回数据))
传输大小会受限参数是放在是实体里面,而且参数大小不会受限

④常见的请求头

User-Agent:客户端请求标识。
Accept: 传输文件类型。
Referer :请求来源。
cookie (cookie):在做登录的时候需要封装这个头。
Content-Type (POST数据类型)

6.服务器响应

①组成:状态行,响应头,空行,响应正文。

②常见的响应头

Content-Type:text/html;资源文件的类型,还有字符编码
Content-Length:响应长度
Content-Size响应大小
Content-Encoding告诉客户端,服务端发送的资源是采用什么编码的。
Connection:keep-alive这个字段作为回应客户端的Connection:keep-alive,告诉客户端服务器的tcp连接也是一个长连接,客户端可以继续使用这个tcp连接发送http请求

四、url:统一资源定位符

基本格式:scheme://host[:port#]/path/…/?query-string
协议://服务器ip地址:端口号/资源路径/?key1=参数1&key2=参数2
  • scheme:协议(例如:http, http, ftp)
  • host/ip:服务器的IP地址或者域名
  • port:服务器的端口(如果是走协议默认端口,缺省端口80),用来从互联网进入电脑
  • path:访问资源的路径,就是为了在电脑中找到对应的资源路径
  • query-string:参数,发送给http服务器的数据
  • anchor:锚(跳转到网页的指定锚点位置)

五、当我们在浏览器输入一个url,为什么可以加载出一个页面?为什么抓包的过程中请求一个url,出现很多的资源请求?

  • 当我们在浏览器输入一个url,客户端会发送这个url对应的一个请求到服务器获取内容
  • 服务器收到这个请求,解析出对应内容,之后将内容封装到响应里发送到客户端
  • 当客户端拿到这个html页面,会查看这个页面中是否有css、js、image等url,如果有,在分别进行请求,获取到这些资源。
  • 客户端会通过html的语法,将获取到的所有内容完美的显示出来。

六、介绍cookie和session

  • 产生原因:由于http是一个无状态的协议,每次请求如果需要之前的一些信息,无法记录,因此为了解决这个问题,产生了一种记录状态技术------cookie和session

  • cookie指某些网站为了辨别用户身份,进行会话跟踪而存储在用户本地终端上的数据,种类有会话cookie和持久cookie

    • (1)会话cookie指存在浏览器内存的cookie,当浏览器关闭,会话cookie会失效
    • (2)持久cookie是保存在硬盘上的cookie
  • session用来存储特定的用户会话所需的属性及其配置信息。

  • cookie是在客户端记录状态,session是在服务端记录状态

  • 联系:当客户端发送一个cookie,服务器会从这个cookie中找到sessionID,再查找出相应的session信息返回给客户端,来进行用户页面的流转。如果通过sessionID来查找session的时候,发现没有session(一般第一次登陆或者清空了浏览器),那么就会创建一个session。

七、 hashlib密码加密

def get_hex(value): 
	md5_ = hashlib.md5()
    md5_.update(value.encode('utf-8')) 
    return md5_.hexdigest() 

八、关于response.text乱码问题

①response的常用属性

1.获取字符串类型的响应正文: response.text
2.获取bytes类型的响应正文: response.content
3.响应正文字符串编码:response.encoding
4.状态码:response.status_code
5.响应头:response.headers

②response.text乱码问题

#方法一:转换成utf-8格式  
response.encoding='utf-8'  
print(response.text) 

#方法二:解码为utf-8 :
with open('index.html','w',encoding='utf-8') as fp:      		        fp.write(response.content.decode('utf-8')) 

九、介绍代理

①代理的作用

1、突破自身IP 访问限制, 访问一些平时不能访问的站点。

2、访问一些单位或团体内部资源: 比如使用教育网内地址段免费代理服务器, 就可以用于对教育网开放的各类FTP 下载上传, 以及各类资料查询共享等服务。

3、提高访问速度: 通常代理服务器都设置一个较大的硬盘缓冲区, 当有外界的信息通过时, 同时也将其保存到缓冲区中, 当其他用户再访问相同的信息时, 则直接由缓冲区中取屮信息传给用户, 以提高访问速度。

4、隐藏真实IP : 上网者也可以通过这种方法隐藏自己的IP , 免受攻击。对于爬虫来说, 我们用代理就是为了隐藏自身IP , 防止自身的被封锁。

②代理根据匿名程度的分类

代理介绍
高度匿名代理会将数据包原封不动地转发, 在服务端看来就好像真的是一个普通客户端在访问, 而记录的IP 是代理服务器的IPO
普通匿名代理会在数据包上做一些改动, 服务端上有可能发现这是个代理服务器, 也有一定几率追查到客户端的真实伊代理服务器通常会加人的HITP 头有HTTP_VIA 和HTTP_X_FORWARDED FOR 。
透明代理不但改动了数据包, 还会告诉服务器客户端的真实IPO 这种代理除了能用缓存技术提高浏览速度, 能用内容过滤提高安全性之外, 并无其他显著作用, 最常见的例子是内网中的硬件防火墙。
间谍代理指组织或个人创建的用于记录用户传输的数据, 然后进行研究、监控等目的的代理服务器。

十、介绍json数据

①数据的分类

种类特点
结构化数据数据以行为为单位,一行数据表示一个实体信息,每一行的数据饿属性是相同的。常见关系型数据库中以表存储的数据就是结构化数据
半结构化数据结构化数据的一种形式,并不符合关系型数据库或其他数据表的形式关联起来的数据模型结构,但包含相关标记,用来分隔个语义元素以及对记录和字段进行分层,因此也被称为自描述的结构。常见的半结构化数据有:xml,html,json
非结构化数据1.没有固定的结构,常见的非结构化数据有:文档,图片和视频等。 2.对于非结构数据,一般我们整体存储二进制格式

②json的本质:是一个字符串,Json是对js对象的字符串表达式,它使用文本形式表示一个JS对象的信息。

③ json使用

1)json.dumps(python的list或者dict)   将python的list或者dict返回为一个json字符串
(2)json.loads(json字符串)    将json字符串返回为python的list或者dict3)json.dump(list/dict,fp)   将python的list或者dict转为一个json字符串,保存到文件中
(4)json.load(fp)            从json文件中读出json数据,并转换为python的list或者dict

十一、正则表达式

①贪婪和非贪婪

(1)正则默认是贪婪模式,所以数量控制符默认是取最大值,也是贪婪。例如*
(2)非贪婪是用?来控制,尽量匹配最少的次数,0次或一次

②python使用格式:

pattern=re.compile('正则表达式') 
print(pattern.match(字符串,start,end))#默认从头开始匹配,只匹配一次,返回一个match对象
print(pattern.search(字符串,start,end))#从任意位置开始匹配,只匹配一次,返回一个match对象
print(pattern.findall(字符串,start,end))#全文多次匹配,将匹配到的结果放到一个list返回给我们
print(pattern.finditer(字符串,start,end))#全文多次匹配,将匹配到的结果放到一个match对象的迭代器返回

③常见的正则题目

在这里插入图片描述

十二、介绍xml

1.xml的基本知识

1.定义:xml称为可拓展性标记语言,类似 HTML

2.特点:xml具有自描述特性,是一种半结构化数据

3.作用:XML 的设计宗旨是传输数据,而非显示数据。可以作为配置文件使用来记录一些重要信息。

4.XmL 的标签需要我们自行定义。

2.html和xml区别

语法方面:

  • 在html中不区分大小写,在xml中严格区分大小写
  • 在html中,在某些情况可以省略闭合标签。在xml中,绝对不能省略任何标记。
  • 在xml中,单标签结尾处需要加’/’。
  • xml文档中,空白部分不会被解析器自动删除,但是html是过滤掉空格的
  • 在xml中,属性值必须封装在引号中。在html中,引号可用可不用。
  • 在html中属性名可以不带属性值,xml必须带属性值而且不能为空

标记不同:

  • html使用固有的标记,xml没有固有标记

作用不同

  • xml主要用来传输数据,html主要用来显示数据

十三、selenium+phantomjs

selenium:web自动测试工具
pantomjs:是一个无界面的浏览器,所以他可以运行js代码,帮我们拿到页面数据。

特点:功能强大,几乎可以对付任何网页,但会导致代码效率低

Selenium 是一个 Web 的自动化测试工具,可以根据我们的指令,让浏览 器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是 否发生。Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏 览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行, 所以 我们可以用一个PhantomJS 的工具代替真实的浏览器。Selenium 库里有个 叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以查找页面元素,与页面上的元 素进行交互 (发送文本、点击等),以及执行其他动作来运行网络爬虫。

PhantomJS 是一个基于 Webkit 的“无界面”(headless)浏览器,它会把 网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运 行起来比完整的浏览器要高效。相比传统的 Chrome或 Firefox 浏览器等,资源 消耗会更少。 如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强 大的网络爬虫了,这个爬虫可以处理 JavaScript、Cookie、headers,以及任 何我们真实用户需要做的事情。主程序退出后,selenium 不保证 phantomJS 也成功退出,最好手动关闭 phantomJS 进程。(有可能会导致多个 phantomJS 进程运行,占用内存)。 WebDriverWait 虽然可能会减少延时,但是目前存在 bug(各种报错),这种 情况可以采用 sleep。 phantomJS 爬数据比较慢,可以选择多线程。如果运行的时候发现有的可 以运行,有的不能,可以尝试将 phantomJS 改成 Chrome。

十四、实现模拟登录的方式有哪些

1.直接使用已知的cookie访问

先用浏览器登录,获取浏览器里的cookie字符串,然后封装至请求头

2.模拟登录后用session保持登录状态

使用session模拟登陆后,就会自动存储一个cookie次从而保持住登录状态

3.使用selenium+phantomjs访问

Selenium库提供了find_element(s)_by_xxx的方法来找到网页中的输入框、按钮等元素。其中xxx可以是id、name、tag_name(标签名)、class_name(class),也可以是xpath(xpath表达式)等等。当然还是要具体分析网页源代码。

十五、线程+进程+多线程

①定义

程序一个应用可以当做一个程序,比如qq软件。
进程程序运行的最小的资源分配单位,一个程序可以有多个进程。
线程cpu最小的调度单位,必须依赖进程而存在。
多线程多线程是指一个程序包含多个并行的线程来完成不同的任务 优点:可以提高cpu的利用率

关系:一个程序至少有一个进程,一个进程至少有一个线程。

②线程的顺序

  • 新建:线程创建(t=threading.Thread(target=方法名)或者线程类)
  • 就绪:当启动线程后,线程就进入就绪状态,就绪状态的线程会被放到一个cpu调度队列里面,cpu会负责让其中的线程运行,变为运行状态。
  • 运行状态:cpu调度一个就绪状态的线程,该线程就变为运行状态。
  • 阻塞状态:当运行状态的线程被阻塞变为阻塞状态,阻塞状态的线程就会重新变为就绪状态才能继续运行
  • 死亡状态:线程执行完毕

③多线程和多进程优缺点

多线程的优点:

  • 程序逻辑和控制方式复杂;
  • 所有线程可以直接共享内存和变量;
  • 线程方式消耗的总资源比进程方式好。

多线程缺点

  • 每个线程与主程序共用地址空间,受限于2GB地址空间;
  • 线程之间的同步和加锁控制比较麻烦;
  • 一个线程的崩溃可能影响到整个程序的稳定性;

多进程优点:

  • 每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
  • 通过增加CPU,就可以容易扩充性能;
  • 每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大 。

多进程缺点

  • 逻辑控制复杂,需要和主程序交互;

  • 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 多进程调度开销比较大。

    对比维度多进程多线程总结
    数据共享、同步数据共享复杂,需要用IPC;数据是分开的,同步简单因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂各有优势
    内存、CPU占用内存多,切换复杂,CPU利用率低占用内存少,切换简单,CPU利用率高线程占优
    创建销毁、切换创建销毁、切换复杂,速度慢创建销毁、切换简单,速度很快线程占优
    编程、调试编程简单,调试简单编程复杂,调试复杂进程占优
    可靠性进程间不会互相影响一个线程挂掉将导致整个进程挂掉进程占优
    分布式适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单适应于多核分布式进程占优

在实际开发中,选择多线程和多进程应该从具体实际开发来进行选择。最好是多进程和多线程结合

十六、互斥锁和死锁和GLF锁

1.互斥锁

定义:当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。线程同步能够保证多个线程安全访问“竞争资源”,最简单的同步机制就是引用互斥锁。

由于线程共享进程的内存空间和数据,因此在某个线程要共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进入写入操作,从而保证了多线程情况下数据的正确性。互斥锁体现的就是一个同步的机制,即该线程释放资源就是一个条件,条件完成,才能执行下一步操作。是微观的操作

锁的好处:

  • (1)确定了某段代码只能由一个线程从头到尾完整地执行。
  • (2)全局变量的安全

锁的坏处:

  • (1)阻止了多线程的并发执行,包含锁的某段代码实际上只能以单线程模块执行,效率降低
  • (2)由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁的时,可能会造成“死锁”。

2.死锁

  • (1)同一个线程先后两次调用lock,在第二次调用时,由于锁已经被自己占用,该线程会挂起等待自己释放锁,由于该线程已被挂起而没有机会释放锁,因此 它将一直处于挂起等待状态,变为死锁;
  • (2)线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都在等待对方释放自己才释放,从而造成两个都永远处于挂起状态,造成死锁。

3.有GLF锁为什么还要有互斥锁

(1)为什么设计GLF锁?

Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是GIL锁能保证同一时刻只有一个线程在运行。

(2)宏观微观考虑GLF锁?

**GIL是宏观的操作。**比如在一个4核的环境下,只有一个核是运行着线程,而其他三个核是空的。GIL是线程锁,针对线程,而不是进程。

十七、MongoDB

①MongoDB和传统的关系型数据库区别

  • 1.传统数据库特点是存储结构化数据,数据以行为单位,每行的数据结构和类型相同
  • 2.MongoDB存储的是文档,每个文档得结构可以不相同,能够更便捷的获取数据。
  • 3.MongoDB的集合不需要提前创建,可隐式创建,而关系型数据库的表需要提前定义
  • 4.mongo第三方支持丰富。(这是与其他的NoSQL相比,MongoDB也具有的优势)
  • 5.mongodb不支持事务操作
  • 6.mongodb支持大容量的存储,占用空间过大

②MongoDB和sql的对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qeA5AAmA-1575721569808)(../../AppData/Roaming/Typora/typora-user-images/1575705781687.png)]

③游标

定义:由于mongodb底层是js编写,因此可以使用一些js代码,通俗的说游标不是查询结果,而是查询的返回资源或者接口,就像python中的生成器,通过这个生成器,可以一次一次的获取每一个资源。

十八、scrapy和scrapy-redis

①什么是scrapy?

scrapy 是一个快速、高层次的基于 python 的 web 爬虫构架,它用于抓取web站点并从页面中提取结构化的数据。scrapy 使用了 Twisted异步网络库来处理网络通讯。
Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

②Scrapy优缺点

优点:

  • scrapy 是异步的(scrapy 框架的异步机制是基于 twisted 异步网络框架处理的,在 settings.py 文件里可以设置具体的并发量数值(默认是并发量 16))
  • 采取可读性更强的xpath代替正则
  • 强大的统计和log系统
  • 同时在不同的url上爬行
  • 支持shell方式,方便独立调试
  • 写middleware,方便写一些统一的过滤器
  • 通过管道的方式存入数据库

缺点:

  • 基于python的爬虫框架,扩展性比较差
  • 基于twisted框架,运行中的exception是不会干掉reactor,并且异步框架出错后是不会停掉其他任务的,数据出错后难以察觉。

③scrapy的组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lBdPRM1d-1575721569811)(../../AppData/Roaming/Typora/typora-user-images/1575705944820.png)]

④scrapy和scrapy-redis的区别

  • scrapy是一个Python爬虫框架,爬取效率极高,具有高度定制性,但是不支持分布式。而scrapy-redis一套基于redis数据库、运行在scrapy框架之上的组件,可以让scrapy支持分布式策略,Slaver端共享Master端redis数据库里的item队列、请求队列和请求指纹集合

  • 为什么选择redis数据库,因为redis支持主从同步,而且数据都是缓存在内存中的,所以基于redis的分布式爬虫,对请求和数据的高频读取效率非常高。

    redis的优点

1.数据读取快,因为数据都放在内存上
2.支持事务watch
3.数据持久化,支持快照和日志,方便恢复数据
4.拥有丰富的数据类型:list,string,set,qset,hash
5.支持主从复制,可以进行数据备份
6.丰富的特性:可以作为缓存,消息队列,设置过期时间,到期自动删除

⑤分布式爬虫主要解决什么问题?

  • ip、带宽、cpu、io

⑥scrapy如何实现分布式抓取?

可以借助scrapy_redis类库来实现。

在分布式爬取时,会有master机器和slave机器,其中,master为核心服务器,slave为具体的爬虫服务器。

我们在master服务器上搭建一个redis数据库,并将要抓取的url存放到redis数据库中,所有的slave爬虫服务器在抓取的时候从redis数据库中去链接,由于scrapy_redis自身的队列机制,slave获取的url不会相互冲突,然后抓取的结果最后都存储到数据库中。master的redis数据库中还会将抓取过的url的指纹存储起来,用来去重。相关代码在dupefilter.py文件中的request_seen()方法中可以找到。

⑦定时任务

1.可以设计一个定时的类,使用时间模块(time,datetime),比如爬取时候获取当前时间,再当前时间多久后再爬取

2.使用linux的crontab的计划任务
	crontab -l 列出所有的定时任务    看不到配置文件中写的定时任务  
	crontab -e 新增计划任务  跟上面的区别在于  没有用户名 
	crontab  -r 清空计划任务  
	分  时 日  月  周   命令    
	 	
	举例使用:
	*  *   *   *  *    命令   每分每时每天每月每周 执行这个命令  
	0-59 0-23 1-31 1-12 0-6  0是 周天 1-6 周一到周六      
	0  2   *   *   *   mysqldump  每天的2点备份数据库  
	0  2   *   *   2   sync    每个周二的2点做数据同步     
	0  8   15  *   *   /home/jsgz.py 每个月15号的八点给大家算工资  
	0  */2 *   *   *   /home/camera.py 每隔2个小时执行一次查看摄像头  
	0  8,12,18 * * 1-5 kq.py    每周1-5 的 8点 12点 18点  执行打卡  
	0  8  *  * * *  spider.sh   每天 8点爬虫

十九、 使用过的爬虫框架或者模块有哪些?

  • Python自带:urllib,urllib2,但是没有使用过

    urllib和urllib2模块都做与请求URL相关的操作,但他们提供不同的功能。
    urllib2.:urllib2.urlopen可以接受一个Request对象或者url,(在接受Request对象时候,并以此可以来设置一个URL 的headers),urllib.urlopen只接收一个url
    urllib 有urlencode,urllib2没有,因此总是urllib,urllib2常会一起使用的原因
    
  • 第 三 方:requests

    request 是一个HTTP库, 它只是用来,进行请求,对于HTTP请求,他是一个强大的库,下载,解析全部自己处理,灵活性更高,高并发与分布式部署也非常灵活,对于功能可以更好实现.
    
  • 框 架:Scrapy

    scrapy是封装起来的框架,他包含了下载器,解析器,日志及异常处理,基于多线程, twisted的方式处理,对于固定单个网站的爬取开发,有优势,但是对于多网站爬取 100个网站,并发及分布式处理方面,不够灵活,不便调整与括展。
    

二十、MyISAM 与 InnoDB 两个引擎有什么区别?

  • InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高级的处理方式,如果在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM就不可以了;
  • MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到安全性较高的应用;
  • InnoDB 支持外键,MyISAM 不支持;
  • MyISAM 是默认引擎,InnoDB 需要指定;
  • InnoDB 不支持 FULLTEXT 类型的索引;
  • InnoDB 中不保存表的行数,如 select count( * ) from table 时,InnoDB;需要扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即 可。注意的是,当 count( * )语句包含 where 条件时 MyISAM 也需要扫描整个表;
  • 对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM表中可以和其他字段一起建立联合索引;
  • 清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重建表;

二十一、写爬虫是用多进程好?还是多线程好? 为什么?

  • IO密集型情况使用多线程
  • 计算密集型情况下使用多进程
IO 密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有 IO 操作会进行 IO 等待,造成不必要的时间浪费,而开启多线程能在线程 A 等待时,自动切换到线程 B,可以不浪费 CPU 的资源,从而能提升程序执行效率)。在实际的数据采集过程中,既考虑网速和响应的问题,也需要考虑自身 机器的硬件情况,来设置多进程或多线程。

二十二、数据库的优化?

为什么要优化?

一个应用吞吐量瓶颈往往出现在数据库的处理速度上,随着应用程序的使用和业务的拓展,数据库数据量逐渐增多,数据库处理压力逐渐增大,关系型数据库数据存放在磁盘上的,读写速度较慢(与内存中的数据相比)

优化方式:

  • 设计表的时候严格根据数据库的设计范式来设计数据库;
  • select 后尽量不使用*
  • 尽量不使用嵌套查询,使用连接查询或者where查询
  • sql关键词尽量使用大写
  • 尽量使用逻辑外交不使用物理外键
  • 给查询频繁的字段添加索引,并且遵循最左原则(尽量将首选关键字段放在最前边)
  • 垂直分库分表:把一些不经常读的数据或者结果复杂的表拆分成多张表,较少磁盘I/O操作;
  • 水平分库分表:于数据量庞大的表,使用水平分库分表
  • 使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能节约磁盘IO;
  • 优化硬件;
  • 主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来;

二十二、使用过的解析数据包

Xpath、正则

二十三、怎么监控爬虫的状态

(1)使用 python 的 STMP 包将爬虫的状态信心发送到指定的邮箱

(2)Scrapyd、pyspider

(3)引入日志

二十四、panads读取数据

import pandas as pd

# 加载detail
detail = pd.read_excel("./meal_order_detail.xlsx")

# 1、直接查看方式--先后索引
#  先列 后行的方式
# 获取dishes_id counts amounts dishes_name 多列数据
res = detail[["dishes_id","counts","amounts","dishes_name"]]
# 获取多列的前n行
res1 = detail[["dishes_id", "counts", "amounts", "dishes_name"]][:20]
res2 = detail[["dishes_id", "counts", "amounts", "dishes_name"]].head(20)

# res = detail[["dishes_id", "counts", "amounts", "dishes_name"]][[0,1,2,3,4]] #  # 不可以的
# res = detail["dishes_id"][[0,1,2,3,4]] # 可以的
# print("获取多列的结果:\n", res)

# 2、同时索引
# loc  只能使用名称 ---注意:可以使用名称切片---包含收尾
# iloc 只能使用下标
res3 = detail.loc[:,"dishes_id":"counts"]

# 3、ix ---同时索引-----混合索引
# 既可以使用名称,也可以使用下标
# res = detail.ix[0:4, "dishes_id":"counts"]
# res = detail.ix[0:4, 0:2]  # 前面行使用名称,列使用下标
#
# res = detail.ix[0:4, 0:"amounts"] # 错误的,不能混搭
# print("res:\n", res)

# 直接索引方式  # 速度最快
# loc iloc  #速度适中 # 某些大的平台上只封装loc iloc方式 --推荐
# ix # 速度最慢 --在最新的版本中提示,将要被删除掉

二十五、Nginx的正向代理和反向代理

web 开发中,部署方式大致类似。简单来说,使用 Nginx 主要是为了实现分流、转发、负载均衡, 以及分担服务器的压力。Nginx 部署简单,内存消耗少,成本低。Nginx 既可以做正向代理,也可以做反向代理。

  • 正向代理:请求经过代理服务器从局域网发出,然后到达互联网上的服务器。特点:服务端并不知道真正的客户端是谁。
  • 反向代理:请求从互联网发出,先进入代理服务器,再转发给局域网内的服务器。特点:客户端并不知道真正的服务端是谁。

区别:正向代理的对象是客户端。反向代理的对象是服务端。

二十六、缓存穿透、缓存雪崩

redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题。

1.缓存穿透:

  • 产生原因: 缓存穿透又称缓存击穿,是指在高并发场景下缓存中(包括本地缓存和redis缓存)的某一个key被高并发的访问并没有命中, 此时会去db中访问数据,导致数据库并发的执行大量查询操作,对db造成巨大压力。
  • 解决方案一:
    对缓存失效的key加分布式锁,当一个key在本地缓存以及redis缓存中未查询到数据,此时对key加分布式锁访问db ,如果取到数据反写到缓存中,避免大量请求进入db ;如果取不到数据则缓存一个空对象 ,这样可以保证db不会被大量请求直接打挂,从而引起缓存颠簸,更甚者缓存雪崩效应。
  • 解决方案二:
    在本地缓存一个set集合,存储对应数据为空的key的集合,在请求前做拦截,此种方式牵涉到数据变更还要校验set集合的问题,一般适用于数据更新较少的场景
  • 解决方案三:
    使用布隆过滤器

2.缓存雪崩:

  • 产生原因: 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

  • 解决方案一:
    ①缓存失效时的雪崩效应对底层系统的冲击非常可怕!大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。

  • 解决方案二:
    简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

二十七、python垃圾回收机制

引用计数是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某 个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如 某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0, 那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了。
一般是类中的 __del__方法进行的。

二十八、Redis的持久化机制

①持久化:日志和快照对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ieNhS7iD-1575721569809)(../../AppData/Roaming/Typora/typora-user-images/1575705877736.png)]

②快照和日志两者如何选择?

推荐两种共同使用

  • 1.如果redis仅仅是用来做为缓存服务器的话,我们可以不使用任何的持久化。
  • 2.一般情况下我们会将两种持久化的方式都开启。redis优先加载AOF文件来回复数据。RDB的好处是快速。
  • 3.在主从节点中,RDB作为我们的备份数据,只在salve(从节点)上启动,同步时间可以设置的长一点,只留(save 900 1)这条规则就可以了。
  • 4.开启AOF的情况下,主从同步是时候必然会带来IO的性能影响,此时我们可以调大auto-aof-rewrite-min-size的值,比如5GB。来减少IO的频率
  • 5.不开启AOF的情况下,可以节省IO的性能影响,这是主从间通过RDB持久化同步,但如果主从都挂掉,影响较大

③在dump rdb过程中,aof如果停止同步,会不会丢失?

答: 不会,所有的操作缓存在内存的队列里, dump完成后,统一操作.

④aof重写是指什么?

答:由于日志保存的是所有操作命令,导致存的日志会过大,而且数据库中有可能数据进行过删除,因此日志中的一些命令就相当于无效,因此日志先会删除,然后内存中的数据会逆化成命令,再重新写入到日志文件中,以解决 aof日志过大的问。

⑤如果rdb文件,和aof文件都存在,优先用谁来恢复数据?

答: 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件完整。

⑥恢复时rdb和aof哪个恢复的快?

答: rdb快,因为其是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行

二十九.TCP和UDP协议的区别

  • tcp的目的是提供可靠的数据传输,并在相互进行通信的设备或服务之间保持一个虚拟连接,tcp在数据包接收无序,丢失或在交付期间被破坏时,负责数据的恢复,tcp面向连接,如打电话要先拨号建立连接,udp则是无连接的,即发送数据之前不需要建立连接。
  • tcp提供可靠的服务,通过tcp连接传送的数据能无差错,不丢失、不重复、且按序到达,而udp是尽最大努力交付,但不保证可靠交付,每一条tcp连接只能是点到点的,而udp支持一对一,一对多,多对一和多对多的交互通信。
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页