scrapy框架的工作流程?
a、spider解析下载器下下来的response,返回item或是links
b、item或者link经过spidermiddleware的process_spider_out( )方法,交给engine
c、engine将item交给item pipeline ,将links交给调度器
d、在调度器中,先将requests对象利用scrapy内置的指纹函数生成一个指纹对象
e、如果requests对象中的don’t filter参数设置为False,并且该requests对象的指纹不在信息指纹的队列中,那么就把该request对象放到优先级队列中
f、从优先级队列中获取request对象,交给engine
g、engine将request对象交给下载器下载,期间会通过downloadmiddleware的process_request方法
h、下载器完成下载,获得response对象,将该对象交给engine,期间会经过downloadmiddleware的 process_response( )方法
i、engine将获得的response对象交给spider进行解析,期间会经过spidermiddleware的process_spider_input()的方法
j、从a开始循环
1,你了解的反爬机制,如何处理?
通过headers反爬虫
ip的访问频率
动态加载数据,通过ajax请求数据,或者通过js代码生成数据
部分数据加密处理
解决方法:
对于基本网页的抓取可以自定义headers,添加headers的数据
使用多个代理ip进行抓取或者设置抓取的频率降低一些,
动态网页的可以使用selenium + phantomjs 进行抓取
对部分数据进行加密的,可以使用selenium进行截图,使用python自带的pytesseract库进行识别,但是比较慢最直接的方法是找到加密的方法进行逆向推理。
2,scrapy的基本架构
Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器),
Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方.
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
3,scrapy的去重原理
1.找到Request类:需要将dont_filter设置为False开启去重,默认是True,没有开启去重;
2.对于每一个url的请求,调度器都会根据请求得相关信息加密得到一个指纹信息,并且将指纹信息和set()集合中的指纹信息进行比对,如果set()集合中已经存在这个数据,就不在将这个Request放入队列中。如果set()集合中没有存在这个加密后的数据,就将这个Request对象放入队列中,等待被调度。
4,scrapy中间件有哪几种类,你用过哪些?
下载中间件,爬虫中间件
5,scrapy中间件在哪起的作用
爬虫中间件:爬虫发起请求request的时候调用,列如更换修改代理ip,修改UA,
下载器中间件:浏览器返回响应response的时候调用,无效的数据,特殊情况进行重试
6,为什么会用到代理?
如果你一直用同一个代理IP爬取这个网页,很有可能IP会被禁止访问网页,所以,基本上做爬虫的都躲不过去IP的问题。
7,代理怎么使用?
1,可以使用urllib2中的ProxyHandler来设置代理ip
uillib2代理ip
2,使用requets代理
requests代理
8,代理失效了怎么处理?
View Code
9,爬取过程中,登录验证码如何处理?
抓取验证码图,对接打码平台进行处理返回
10,爬取速度过快,出现的验证码如何处理?
抓取验证码图,对接打码平台进行处理返回
11,如何用机器识别验证码?
对接打码平台
12,cookie如何处理?
requests.session
13,如何处理网站加密传参的情况?
简单加密可以使用selenium,或者执行js,存储cookie,手动修改cookie的值
也可以下载它们相关的APP
14,分布式的原理?
捅过重写scheduler和spider类,实现了调度、spider启动和redis的交互。实现新的dupefilter和queue类,达到了判重和调度容器和redis的交互,因为每个主机上的爬虫进程都访问同一个redis数据库,所以调度和判重都统一进行统一管理,达到了分布式爬虫的目的。
15,分布式如何判断爬虫已经停止了?
View Code
16,爬取下来的数据如何选择什么存储方式会更好
针对数据而定。
18,动态加载的数据如何提取?
动态网页的可以使用selenium + phantomjs 进行抓取
19,json数据如何提取?
json.loads, json.dumps
20,Python里面深拷贝,浅拷贝的区别?
浅拷贝不管几层只会拷贝第一层
拷贝就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,不管数据结构多么的复杂,数据之间的修改都不会相互影响
21,是否了解线程的同步和异步?
线程同步是多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低
线程异步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制
22,链表和顺序表存储时各自有什么特点?
顺序表的优点是可以随机访问数据元素;
缺点是大小固定,不利于增删结点。
链表的优点是采用指针方式增减结点,非常方便(只需要改变指针指向,不移动结点);
缺点是不能进行随机访问,另外,每个结点上增加指针域,造成额外存储空间增大。
23,使用redis搭建分布式系统时如何处理网络延迟和网络异常?
由于网络异常的存在,分布式系统中请求结果存在“三态”的概念,即三种状态:“成功”、“失败”、“超时(未知)”
当出现“超时”时可以通过发起读取数据的操作以验证 RPC 是否成功(例如银行系统的做法)
另一种简单的做法是,设计分布式协议时将执行步骤设计为可重试的,即具有所谓的“幂等性”
24,数据仓库是什么?
数据仓库是一个面向主题的、集成的、稳定的、反映历史变化的、随着时间的流逝发生变化的数据集合。它主要支持管理人员的决策分析。
数据仓库收集了企业相关内部和外部各个业务系统数据源、归档文件等一系列历史数据,最后转化成企业需要的战略决策信息。
特点:
面向主题:根据业务的不同而进行的内容划分;
集成特性:因为不同的业务源数据具有不同的数据特点,当业务源数据进入到数据仓库时,需要采用统一的编码格式进行数据加载,从而保证数据仓库中数据的唯一性;
非易失性:数据仓库通过保存数据不同历史的各种状态,并不对数据进行任何更新操作。
历史特性:数据保留时间戳字段,记录每个数据在不同时间内的各种状态。
25,假设有一个爬虫程序,从网络上的获取的频率快,本地写入数据的频率慢,使用什么数据结构比较好?
26,你是否了解谷歌的无头浏览器?
无头浏览器即headless browser,是一种没有界面的浏览器。既然是浏览器那么浏览器该有的东西它都应该有,只是看不到界面而已。
Python中selenium模块中的PhantomJS即为无界面浏览器(无头浏览器):是基于QtWebkit的无头浏览器,
27,你是否了解mysql数据库的几种引擎?
InnoDB:
InnoDB是一个健壮的事务型存储引擎,这种存储引擎已经被很多互联网公司使用,为用户操作非常大的数据存储提供了一个强大的解决方案。
在以下场合下,使用InnoDB是最理想的选择:
1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。
2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。
3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。
4.外键约束。MySQL支持外键的存储引擎只有InnoDB。
5.支持自动增加列AUTO_INCREMENT属性。
一般来说,如果需要事务支持,并且有较高的并发读取频率,InnoDB是不错的选择。
MEMORY:
使用MySQL Memory存储引擎的出发点是速度。为得到最快的响应时间,采用的逻辑存储介质是系统内存。
虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩溃时,所有的Memory数据都会丢失。
获得速度的同时也带来了一些缺陷。
一般在以下几种情况下使用Memory存储引擎:
1.目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。
2.如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。
3.存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。
28,redis数据库有哪几种数据结构?
5种数据结构
string
使用string时,redis大多数情况下并不会理解或者解析其含义,无论使用json、xml还是纯文本在redis看来都是一样的,只是一个字符串,只能进行strlen、append等对字符串通用的操作,无法针对其内容进一步操作。其基本操作命令有set、get、strlen、getrange、append:
1
2
3
4
5
SET key value
GET key
STRLEN key
GETRANGE key start end
APPEND key value
在大多数情况之外,就是string中存储的为纯数字的情况,redis可以将字符串当做数字进行进一步操作,这些操作包括decr、decrby、incr、incrby和incrbyfloat。
hash
使用hash时,在我看来,就是value本身就是一组key-value对,不过redis将这里的key称为field(但是hkeys命令为什么不叫hfields命令呢哈哈),也就是value是一组field-value对。其基本操作命令有hset、hget、hmset、hmget、hgetall、hkeys和hdel:
1
2
3
4
5
6
7
HSET key field value
HGET key field
HMSET key field value [field value …]
HMGET key field [field …]
HGETALL key
HKEYS key
HDEL key field [field …]
list
使用list时,value就是一个string数组,操作这组string时,可以像对待栈一样使用pop和push操作,但是这个栈两端都能进行操作;也可以像对待数组一样使用一个index参数来操作。list的操作命令略杂,主要分为两类:L开头的和R开头的,L代表LEFT或者LIST,进行一些从列表左端进行的操作,或者一些与端无关的操作;R代表RIGHT,进行一些从列表右端进行的操作。
set
set用于存储一组不重复的值,也可以进行一些集合的操作,就像数学上的集合,它是无序的。基本操作有sadd和sismember:
1
2
SADD key member [member …]
SISMEMBER key member
集合操作有:求交sinter、求并sunion和求差sdiff:
1
2
3
SINTER key [key …]
SUNION key [key …]
SDIFF key [key …]
sorted set
sorted set类似set,但是sorted set里每个元素都有一个score,这个score可用于排序和排名。基本操作有zadd、zcount、zrank:
1
2
3
ZADD key score member [score member …]
ZCOUNT key min max
ZRANK key member
29,对 name=='main’的理解
name__是当前模块名,当模块被直接运行时模块名为_main,也就是当前的模块,当模块被导入时,模块名就不是__main_,即代码将不会执行。
30,python是如何进行内存管理的?
a、对象的引用计数机制
python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
b、垃圾回收
1>当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
2>当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象 的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
c、内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
1>Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理 对小块内存的申请和释放。
2>Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用 系统的malloc。
3>对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
31,__new)_和__init__的区别
new:它是创建对象时调用,会返回当前对象的一个实例,可以用_new_来实现单例
init:它是创建对象后调用,对当前对象的一些实例初始化,无返回值
32,常用的网络爬取方法
正则表达式
Beautiful Soup
Lxml
33,urllib 和urllib2的区别?
urllib 和urllib2都是接受URL请求的相关模块,但是urllib2可以接受一个Request类的实例来设置URL请求的headers,urllib仅可以接受URL。urllib不可以伪装你的User-Agent字符串。
urllib提供urlencode()方法用来GET查询字符串的产生,而urllib2没有。这是为何urllib常和urllib2一起使用的原因。
34,列举爬虫用到的网络数据包,解析包?
网络数据包 urllib、urllib2、requests
解析包 re、xpath、beautiful soup、lxml
35,手写一个单列模式?
单列模式
36,常用的网络爬取方法?
urllib2 , Beautiful Soup 正则 xpath
37,代码实现删除list里面的重复元素
set
38,手写代码二分查找
39,python2和python3的区别
40,python的装饰器 ,手写
41,python常用的内置库,
42,如何做增量式爬取?
去爬帖子列表页, 每次都把当前页的 url 和数据库中的对比,如果没有重复的说明,这一夜都是新的 URL,然后下一页,直到出现部分重复或完全重复的页面
43,简述beautifulsoup模块的作用及基本使用?
BeautifulSoup是一个模块,该模块用于接收一个HTML或XML字符串,然后将其进行格式化,之后遍可以使用他提供的方法进行快速查找指定元素,从而使得在HTML或XML中查找指定元素变得简单。
44,seleniun模块的作用及基本使用?
操作浏览器
45,scrapy如何实现大文件的下载?
当使用requests的get下载大文件/数据时,建议使用使用stream模式。
当把get函数的stream参数设置成False时,它会立即开始下载文件并放到内存中,如果文件过大,有可能导致内存不足。
当把get函数的stream参数设置成True时,它不会立即开始下载,当你使用iter_content或iter_lines遍历内容或访问内容属性时才开始下载。需要注意一点:文件没有下载之前,它也需要保持连接。
iter_content:一块一块的遍历要下载的内容
iter_lines:一行一行的遍历要下载的内容
使用上面两个函数下载大文件可以防止占用过多的内存,因为每次只下载小部分数据。
示例代码:
View Code
46,scrapy如何实现限速?
在settings里面,
DOWNLOAD_DELAY = 0.25 # 250 ms of delay
47,scrapy如何实现暂停爬虫程序?
实现暂停与重启记录状态
方法一:
1、首先cd进入到scrapy项目里(当然你也可以通过编写脚本Python文件直接在pycharm中运行)
2、在scrapy项目里创建保存记录信息的文件夹
3、执行命令:
scrapy crawl 爬虫名称 -s JOBDIR=保存记录信息的路径
如:scrapy crawl cnblogs -s JOBDIR=zant/001
执行命令会启动指定爬虫,并且记录状态到指定目录
爬虫已经启动,我们可以按键盘上的ctrl+c停止爬虫,停止后我们看一下记录文件夹,会多出3个文件,其中的requests.queue文件夹里的p0文件就是URL记录文件,这个文件存在就说明还有未完成的URL,当所有URL完成后会自动删除此文件
当我们重新执行命令:scrapy crawl cnblogs -s JOBDIR=zant/001 时爬虫会根据p0文件从停止的地方开始继续爬取。
方法二:
在settings.py文件里加入下面的代码:
JOBDIR=‘sharejs.com’
使用命令scrapy crawl somespider,就会自动生成一个sharejs.com的目录,然后将工作列表放到这个文件夹里
48,scrapy如何进行自定制指令?
单爬虫运行
代码:
View Code
同时运行多个爬虫
步骤如下:
- 在spiders同级创建任意目录,如:commands
- 在其中创建 crawlall.py 文件 (此处文件名就是自定义的命令)
- 在settings.py 中添加配置 COMMANDS_MODULE = ‘项目名称.目录名称’
- 在项目目录执行命令:scrapy crawlall
代码:
View Code
49,scrapy如何实现记录爬虫的深度?
通过scrapy.CrawlSpider
50,scrapy中的pipelines工作原理?
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。
每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:
验证爬取的数据(检查item包含某些字段,比如说name字段)
查重(并丢弃)
将爬取结果保存到文件或者数据库中
51,简述scrapy爬虫中间件和下载中间件的作用?
52,scrapy-redis组件的作用?
scheduler - 调度器
dupefilter - URL去重规则(被调度器使用)
pipeline - 数据持久化
53,scrapy-redis组件中如何实现任务的去重?
dupefilter - URL去重规则(被调度器使用)
54,scrapy-redis的调度器如何实现任务的深度优先和广度优先?
55,手写正则匹配邮箱,手机号,一段html内容
56,robots协议是什么?
Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
57,常见的http状态码?
View Code
58,http的请求和响应都包含哪些内容?
View Code