一.项目问题:
1.你写爬虫的时候都遇到过什么反爬虫措施,你最终是怎样解决的
- 通过headers反爬虫:解决策略,伪造headers
- 基于用户行为反爬虫:动态变化去爬取数据,模拟普通用户的行为, 使用IP代理池爬取或者降低抓取频率,或 通过动态更改代理ip来反爬虫
- 基于动态页面的反爬虫:跟踪服务器发送的ajax请求,模拟ajax请求,selnium
和phtamjs。或 使用selenium + phantomjs 进行抓取抓取动态数据,或者找到动态数据加载的json页面。 - 验证码 :使用打码平台识别验证码
- 数据加密:对部分数据进行加密的,可以使用selenium进行截图,使用python自带的pytesseract库进行识别,但是比较慢最直接的方法是找到加密的方法进行逆向推理。
2.你写爬虫的时候 使用的什么框架 选择这个框架的原因是什么?
scrapy。
优势:
-
可以实现高并发的爬取数据, 注意使用代理;
-
提供了一个爬虫任务管理界面, 可以实现爬虫的停止,启动,调试,支持定时爬取任务;
-
代码简洁
劣势:
-
1.可扩展性不强。
-
2.整体上来说: 一些结构性很强的, 定制性不高, 不需要太多自定义功能时用pyspider即可, 一些定制性高的,需要自定义一 些 功能时则使用Scrapy。
2.scrapy框架专题部分(很多面试都会涉及到这部分)
(1)请简要介绍下scrapy框架。
scrapy 是一个快速(fast)、高层次(high-level)的基于 python 的 web 爬虫构架,
用于抓取web站点并从页面中提取结构化的数据。scrapy 使用了 Twisted异步网络库来
处理网络通讯
(2)为什么要使用scrapy框架?scrapy框架有哪些优点?
- 它更容易构建大规模的抓取项目
- 它异步处理请求,速度非常快
- 它可以使用自动调节机制自动调整爬行速度
(3)scrapy框架有哪几个组件/模块?简单说一下工作流程。
-
Scrapy Engine:
这是引擎,负责Spiders、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等等!(像不像人的身体?) -
Scheduler(调度器): 它负责接受引擎发送过来的requests请求,并按照一定的方式进行整理排列,入队、并等待Scrapy
Engine(引擎)来请求时,交给引擎。 -
Downloader(下载器):负责下载Scrapy
Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy
Engine(引擎),由引擎交给Spiders来处理, -
Spiders:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器),
-
Item
Pipeline:它负责处理Spiders中获取到的Item,并进行处理,比如去重,持久化存储(存数据库,写入文件,总之就是保存数据用的) -
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件
-
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spiders中间‘通信‘的功能组件(比如进入Spiders的Responses;和从Spiders出去的Requests)
工作流程:
数据在整个Scrapy的流向:
程序运行的时候,
引擎:Hi!Spider, 你要处理哪一个网站?
Spiders:我要处理23wx.com
引擎:你把第一个需要的处理的URL给我吧。
Spiders:给你第一个URL是XXXXXXX.com
引擎:Hi!调度器,我这有request你帮我排序入队一下。
调度器:好的,正在处理你等一下。
引擎:Hi!调度器,把你处理好的request给我,
调度器:给你,这是我处理好的request
引擎:Hi!下载器,你按照下载中间件的设置帮我下载一下这个request
下载器:好的!给你,这是下载好的东西。(如果失败:不好意思,这个request下载失败,然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载。)
引擎:Hi!Spiders,这是下载好的东西,并且已经按照Spider中间件处理过了,你处理一下(注意!这儿responses默认是交给def parse这个函数处理的)
Spiders:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,这是我需要跟进的URL,将它的responses交给函数 def xxxx(self, responses)处理。还有这是我获取到的Item。
引擎:Hi !Item Pipeline 我这儿有个item你帮我处理一下!调度器!这是我需要的URL你帮我处理下。然后从第四步开始循环,直到获取到你需要的信息,
注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy会重新下载。)
以上就是Scrapy整个流程了。
官方语言版本:
流程
1.引擎打开一个域名,蜘蛛处理这个域名,并让蜘蛛获取第一个爬取的URL。
2.引擎从蜘蛛那获取第一个需要爬取的URL,然后作为请求在调度中进行调度。
3.引擎从调度那获取接下来进行爬取的页面。
4.调度将下一个爬取的URL返回给引擎,引擎将他们通过下载中间件发送到下载器。
5.当网页被下载器下载完成以后,响应内容通过下载中间件被发送到引擎。
6.引擎收到下载器的响应并将它通过蜘蛛中间件发送到蜘蛛进行处理。
7.蜘蛛处理响应并返回爬取到的项目,然后给引擎发送新的请求。
8.引擎将抓取到的项目项目管道,并向调度发送请求。
系统重复第二步后面的操作,直到调度中没有请求,然后断开引擎与域之间的联系
4.scrapy的去重原理(指纹去重到底是什么原理)
在这里插入图片描述
- 需要将dont_filter设置为False开启去重,默认是False;
- 对于每一个url的请求,调度器都会根据请求的相关信息加密得到一个指纹信息,并且将指纹信息和set()集合中得指纹信息进行比对,如果set()集合中已经存在这个数据,就不在将这个Request放入队列中。如果set()集合中没有,就将这个Request对象放入队列中,等待被调度。
5.scrapy中间件有几种类,你用过哪些中间件*
scrapy的中间件理论上有三种:
-
Schduler Middleware,
-
Spider Middleware,
-
Downloader Middleware),
-
在应用上一般有以下两种:
1.爬虫中间件Spider Middleware
主要功能是在爬虫运行过程中进行一些处理.
2.下载器中间件Downloader Middleware
主要功能在请求到网页后,页面被下载时进行一些处理.
使用
1.Spider Middleware有以下几个函数被管理:
process_spider_input 接收一个response对象并处理,位置是Downloader–>process_spider_input–>Spiders(Downloader和Spiders是scrapy官方结构图中的组件)
process_spider_exception spider出现的异常时被调用
process_spider_output 当Spider处理response返回result时,该方法被调用process_start_requests 当spider发出请求时,被调用
位置是Spiders–>process_start_requests–>Scrapy Engine(Scrapy Engine是scrapy官方结构图中的组件)
2.Downloader Middleware有以下几个函数被管理
- process_request request通过下载中间件时,该方法被调
- process_response 下载结果经过中间件时被此方法处理
- process_exception 下载过程中出现异常时被调用
6.scrapy中间件再哪里起的作用
-
1.爬虫中间件Spider Middleware:主要功能是在爬虫运行过程中进行一些处理.爬虫发起请求request的时候调用,列如更换修改代理ip,修改UA,
-
2.下载器中间件Downloader Middleware:主要功能在请求到网页后,页面被下载时进行一些处理.浏览器返回响应response的时候调用,无效的数据,特殊情况进行重试
三.代理问题:
1.为什么会用到代理
一些网站会有相应的反爬虫措施,例如很多网站会检测某一段时间某个IP的访问次数,如果访问频率太快以至于看起来不像正常访客,它可能就会会禁止这个IP的访问。所以我们需要设置一些代理服务器,每隔一段时间换一个代理,就算IP被禁止,依然可以换个IP继续爬取。
2.代理怎么使用(具体代码, 请求在什么时候添加的代理)
1,可以使用urllib2中的ProxyHandler来设置代理ip
1 import urllib2
2
3 # 构建了两个代理Handler,一个有代理IP,一个没有代理IP
4 httpproxy_handler = urllib2.ProxyHandler({"http" : "124.88.67.81:80"})
5 nullproxy_handler = urllib2.ProxyHandler({})
6 #定义一个代理开关
7 proxySwitch = True
8 # 通过 urllib2.build_opener()方法使用这些代理Handler对象,创建自定义opener对象
9 # 根据代理开关是否打开,使用不同的代理模式
10 if proxySwitch:
11 opener = urllib2.build_opener(httpproxy_handler)
12 else:
13 opener = urllib2.build_opener(nullproxy_handler)
14
15 request = urllib2.Request("http://www.baidu.com/")
16
17 # 使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理。
18 response = opener.open(request)
19
20 # 就是将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理。
21 # urllib2.install_opener(opener)
22 # response = urlopen(request)
23
24 print response.read()
2,使用requets代理
1 import requests
2
3 # 根据协议类型,选择不同的代理
4 proxies = {
5 "http": "http://12.34.56.79:9527",
6 "https": "http://12.34.56.79:9527",
7 }
8
9 response = requests.get("http://www.baidu.com", proxies = proxies)
10 print response.text
3.代理失效了怎么处理
事先用检测代码检测可用的代理,每隔一段时间更换一次代理,如果出现302等状态码,
则立即更换下一个可用的IP。
1 1、将代理IP及其协议载入ProxyHandler赋给一个opener_support变量;
2、将opener_support载入build_opener方法,创建opener;
3、安装opener。具体代码如下:from urllib import requestdef ProxySpider
(url, proxy_ip, header):opener_support =
request.ProxyHa