乐趣区

Python爬虫面试总结

Python 爬虫面试总结

1. 写一个邮箱地址的正则表达式?

[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$

2. 谈一谈你对 Selenium 和 PhantomJS 了解

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

PhantomJS 是一个基于 Webkit 的“无界面”(headless) 浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。相比传统的 Chrome 或 Firefox 浏览器等,资源消耗会更少。

如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。主程序退出后,selenium 不保证 phantomJS 也成功退出,最好手动关闭 phantomJS 进程。(有可能会导致多个 phantomJS 进程运行,占用内存)。WebDriverWait 虽然可能会减少延时,但是目前存在 bug(各种报错),这种情况可以采用 sleep。phantomJS 爬数据比较慢,可以选择多线程。如果运行的时候发现有的可以运行,有的不能,可以尝试将 phantomJS 改成 Chrome。

3. 为什么 requests 请求需要带上 header?

原因是:模拟浏览器,欺骗服务器,获取和浏览器一致的内容
header 的形式:字典

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}

用法:requests.get(url,headers=headers)

4. 你遇到的反爬虫策略有哪些?及应对策略有什么?

  • 通过 headers 反爬虫
  • 基于用户行为的发爬虫:例如同一 IP 短时间内多次访问同一页面,或者同一账户短时间内多次进行相同操作
  • 动态网页反爬虫,例如:我们需要爬取的数据是通过 ajax 请求得到,或者通过 JavaScript 生成的
  • 对部分数据进行加密处理的,例如:我们要抓的数据部分能够抓到,另外的部分加密处理了,是乱码

应对策略:

 对于基本网页的抓取可以自定义 headers, 添加 headers 的数据,代理来解决

有些网站的数据抓取必须进行模拟登陆才能抓取到完整的数据,所以要进行模拟登陆。对于限制抓取频率的,可以设置抓取的频率降低一些,对于限制 ip 抓取的可以使用多个代理 ip 进行抓取,轮询使用代理


针对动态网页的可以使用 selenium+phantomjs 进行抓取,但是比较慢,所以也可以使用查找接口的方式进行抓取。对部分数据进行加密的,可以使用 selenium 进行截图,饭后使用 python 自带的 pytesseract 库进行识别,但是比较慢最直接的方法是找到加密的方法进行逆向推理。

5. 分布式爬虫原理?

scrapy-redis 实现分布式,其实从原理上来说很简单,这里为描述方便,我们把自己的核心服务器称为 master,而把用于跑爬虫程序的机器称为 slave。

我们知道,采用 scrapy 框架抓取网页,我们需要首先给定它一些 start_urls,爬虫首先访问 start_urls 里面的 url,再根据我们的具体逻辑,对里面的元素、或者是其他的二级、三级页面进行抓取。而要实现分布式,我们只需要在这个 starts_urls 里面做文章就行了。

我们在 master 上搭建一个 redis 数据库(注意这个数据库只用作 url 的存储,不关心爬取的具体数据,不要和后面的 mongodb 或者 mysql 混淆),并对每一个需要爬取的网站类型,都开辟一个单独的列表字段。通过设置 slave 上 scrapy-redis 获取 url 的地址为 master 地址。这样的结果就是,尽管有多个 slave,然而大家获取 url 的地方只有一个,那就是服务器 master 上的 redis 数据库。并且,由于 scrapy-redis 自身的队列机制,slave 获取的链接不会相互冲突。这样各个 slave 在完成抓取任务之后,再把获取的结果汇总到服务器上(这时的数据存储不再在是 redis,而是 mongodb 或者 mysql 等存放具体内容的数据库了)这种方法的还有好处就是程序移植性强,只要处理好路径问题,把 slave 上的程序移植到另一台机器上运行,基本上就是复制粘贴的事情。

6. pythoon2.x 中 urllib 和 urllib2 的区别?

 异同:都是做 url 请求的操作的,但是区别很明显。urllib2 可以接受一个 Request 类的实例来设置 URL 请求的 headers,urllib 仅可以接受 URL。这意味着,你不可以通过 urllib 模块伪装你的 User Agent 字符串等(伪装浏览器)。urllib 提供 urlencode 方法用来 GET 查询字符串的产生,而 urllib2 没有。这是为何 urllib 常和 urllib2 一起使用的原因。模块比较优势的地方是 urlliburllib2.urlopen 可以接受 Request 对象作为参数,从而可以控制 HTTP Request 的 header 部。但是 urllib.urlretrieve 函数以及 urllib.quote 等一系列 quote 和 unquote 功能没有被加入 urllib2 中,因此有时也需要 urllib 的辅助。

7.robots 协议是什么?

Robots 协议(也称为爬虫协议、爬虫规则、机器人协议等)也就是 robots.txt,网站通过 robots 协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。

Robots 协议是网站国际互联网界通行的道德规范,其目的是保护网站数据和敏感信息、确保用户个人信息和隐私不被侵犯。因其不是命令,故需要搜索引擎自觉遵守。

8. 什么是爬虫?

爬虫是请求网站并提取数据的自动化程序

9. 爬虫的基本流程?

1、通过 http 库向目标站点发起请求,即发送一个 Request,请求可以包含额外的 headers 等信息,等待服务器响应
2、如果服务器能正常响应,会得到一个 Response,Response 的内容比啊是索要获取的页面内容
3、解析内容:正则表达式、页面解析库、json
4、保存数据:文本或者存入数据库 

10. 什么是 Request 和 Response?

本地 向 服务器 发送 Request,服务器根据请求返回一个 Response,页面就显示在页面上了

1、浏览器就发送消息给该网址所在的服务器,这个过程叫做 Http Request

2、服务器收到浏览器发送的消息后,能够根据浏览器发送消息的内容,做相应处
理,然后把消息回传给浏览器,这个过程叫做 HTTP Response

3、浏览器收到服务器的 Response 消息后,会对信息进行相应处理,然后显示

11.Request 中包含什么呢?

1、请求方式:主要有 GET 和 POST 两种方式,POST 请求的参数不会包含在 url 里面
2、请求 URL
URL:统一资源定位符,如一个网页文档、一张图片、一个视频等都可以用 URL 来唯一确定
3、请求头信息, 包含了 User-Agent(浏览器请求头)、Host、Cookies 信息
4、请求体,GET 请求时,一般不会有,POST 请求时,请求体一般包含 form-data

12.Response 中包含什么信息?

1、响应状态:状态码 正常响应 200 重定向
2、响应头:如内容类型、内容长度、服务器信息、设置 cookie 等
3、响应体信息:响应源代码、图片二进制数据等等 

13. 常见的 http 状态码

200 状态码 服务器请求正常

301 状态码:被请求的资源已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。302 状态码:请求的资源临时从不同的 URI 响应请求,但请求者应继续使用原有位置来进行以后的请求

401 状态码:请求要求身份验证。对于需要登录的网页,服务器可能返回此响应。403 状态码:服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。404 状态码:请求失败,请求所希望得到的资源未被在服务器上发现。500 状态码:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。503 状态码:由于临时的服务器维护或者过载,服务器当前无法处理请求。

14.HTTP 的请求和响应都包含哪些内容

HTTP 请求头

Accept: 浏览器能够处理的内容类型
Accept-Charset: 浏览器能够显示的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Accept-Language:浏览器当前设置的语言
Connection:浏览器与服务器之间连接的类型
Cookie:当前页面设置的任何 Cookie
Host:发出请求的页面所在的域
Referer:发出请求的页面的 URL
User-Agent:浏览器的用户代理字符串 
HTTP 响应头部信息:Date:表示消息发送的时间,时间的描述格式由 rfc822 定义
server: 服务器名字。Connection:浏览器与服务器之间连接的类型
content-type: 表示后面的文档属于什么 MIME 类型
Cache-Control:控制 HTTP 缓存 

15. mysql 的索引在什么情况下失效

1. 如果条件中有 or,即使其中有条件带索引也不会使用 (这也是为什么尽量少用 or 的原因)
要想使用 or,又想让索引生效,只能将 or 条件中的每个列都加上索引
2. 对于多列索引,不是使用的第一部分,则不会使用索引
3.like 查询以 % 开头
4. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来, 否则不使用索引
5. 如果 mysql 估计使用全表扫描要比使用索引快, 则不使用索引 

15.MySQL 有什么引擎,各引擎之间有什么区别?

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

16.Scrapy 优缺点:

 优点:scrapy 是异步的


采取可读性更强的 xpath 代替正则


强大的统计和 log 系统


同时在不同的 url 上爬行


支持 shell 方式,方便独立调试


写 middleware, 方便写一些统一的过滤器


通过管道的方式存入数据库


缺点:基于 python 的爬虫框架,扩展性比较差


基于 twisted 框架,运行中的 exception 是不会干掉 reactor,并且异步框架出错后是不会停掉其他任务的,数据出错后难以察觉。

17.HTTPS 是如何实现安全传输数据的

 客户端(通常是浏览器)先向服务器发出加密通信的请求


服务器收到请求, 然后响应


客户端收到证书之后会首先会进行验证


服务器收到使用公钥加密的内容,在服务器端使用私钥解密之后获得随机数 pre-master secret,然后根据 radom1、radom2、pre-master secret 通过一定的算法得出 session Key 和 MAC 算法秘钥,作为后面交互过程中使用对称秘钥。同时客户端也会使用 radom1、radom2、pre-master secret,和同样的算法生成 session Key 和 MAC 算法的秘钥。然后再后续的交互中就使用 session Key 和 MAC 算法的秘钥对传输的内容进行加密和解密。

18. 描述下 scrapy 框架运行的机制?

 从 start_urls 里获取第一批 url 并发送请求,请求由引擎交给调度器入请求队列,获取完毕后,调度器将请求队列里的请求交给下载器去获取请求对应的响应资源,并将响应交给自己编写的解析方法做提取处理:如果提取出需要的数据,则交给管道文件处理;如果提取出 url,则继续执行之前的步骤(发送 url 请求,并由引擎将请求交给调度器入队列...),直到请求队列里没有请求,程序结束。

请继续关注我

退出移动版