通过在settings.py中设置DEPTH_LIMIT的值可以限制爬取深度,这个深度是与start_urls中定义url的相对值。也就是相对url的深度。若定义url为http://www.domz.com/game/,DEPTH_LIMIT=1那么限制爬取的只能是此url下一级的网页。深度大于设置值的将被忽视。
答:可以使用正则、xpath、json、pyquery、bs4等(任选一二即可)。
[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
1. 自己维护代理池
2. 付费购买(目前市场上有很多ip代理商,可自行百度了解,建议看看他们的接口文档(API&SDK))
透明代理的意思是客户端根本不需要知道有代理服务器的存在,但是它传送的仍然是真实的IP。你要想隐藏的话,不要用这个。
普通匿名代理能隐藏客户机的真实IP,但会改变我们的请求信息,服务器端有可能会认为我们使用了代理。不过使用此种代理时,虽然被访问的网站不能知道你的ip地址,但仍然可以知道你在使用代理,当然某些能够侦测ip的网页仍然可以查到你的ip。
高匿名代理不改变客户机的请求,这样在服务器看来就像有个真正的客户浏览器在访问它,这时客户的真实IP是隐藏的,服务器端不会认为我们使用了代理。
存放在数据库(redis、mysql等)
维护多个代理网站
一般代理的存活时间往往在十几分钟左右,定时任务,加上代理IP去访问网页,验证其是否可用,如果返回状态为200,表示这个代理是可以使用的。
1. Web端加密可尝试移动端(app)
2. 解析加密,看能否破解
3. 反爬手段层出不穷,js加密较多,只能具体问题具体分析
Selenium是一个Web的自动化测试工具,可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器。Selenium 库里有个叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以像 BeautifulSoup 或者其他 Selector 对象一样用来查找页面元素,与页面上的元素进行交互 (发送文本、点击等),以及执行其他动作来运行网络爬虫。
PhantomJS 是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。
如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。
1.selenium控制鼠标实现,速度太机械化,成功率比较低
2.计算缺口的偏移量(推荐博客:http://blog.csdn.net/paololiu/article/details/52514504?%3E)
3.“极验”滑动验证码需要具体网站具体分析,一般牵扯算法乃至深度学习相关知识
分布式只是提高爬虫功能和效率的一个环节而已,它从来不是爬虫的本质东西。
爬虫的本质是网络请求和数据处理,如何稳定地访问网页拿到数据,如何精准地提取出高质量的数据才是核心问题。
分布式爬虫只有当爬虫任务量很大的时候才会凸显优势,一般情况下也确实不必动用这个大杀器,所以要明确你的目标是什么
1)ip
2)带宽
3)cpu
4)io
5)大量任务
传统定义:分布式存储系统是大量PC服务器通过Internet互联,对外提供一个整体的服务。
分布式存储系统具有以下的几个特性:
可扩展:分布式存储系统可以扩展到几百台甚至几千台这样的一个集群规模,系统的整体性能线性增长。
低成本:分布式存储系统的自动容错、自动负载均衡的特性,允许分布式存储系统可以构建在低成本的服务器上。另外,线性的扩展能力也使得增加、减少服务器的成本低,实现分布式存储系统的自动运维。
高性能:无论是针对单台服务器,还是针对整个分布式的存储集群,都要求分布式存储系统具备高性能。
易用:分布式存储系统需要对外提供方便易用的接口,另外,也需要具备完善的监控、运维工具,并且可以方便的与其他的系统进行集成。
分布式存储系统的挑战主要在于数据和状态信息的持久化,要求在自动迁移、自动容错和并发读写的过程中,保证数据的一致性。分布式存储所涉及到的技术主要来自于两个领域:分布式系统以及数据库,如下所示:
数据分布:如何将数据均匀的分布到整个分布式存储集群中的各台服务器?如何从分布式存储集群中读取数据?
一致性:如何将数据的多个副本复制到多台服务器,即使在异常情况下,也能保证不同副本之间的数据一致性。
容错:如何可以快速检测到服务器故障,并自动的将在故障服务器上的数据进行迁移
负载均衡:新增的服务器如何在集群中保障负载均衡?数据迁移过程中如何保障不影响现有的服务。
事务与并发控制:如何实现分布式事务。
易用性:如何设计对外接口,使得设计的系统易于使用
压缩/加压缩:如何根据数据的特点设计合理的压缩/解压缩算法?如何平衡压缩/解压缩算法带来的空间和CPU计算资源?
三种分布式爬虫策略:
1.Slaver端从Master端拿任务(Request/url/ID)进行数据抓取,在抓取数据的同时也生成新任务,并将任务抛给Master。Master端只有一个Redis数据库,负责对Slaver提交的任务进行去重、加入待爬队列。
优点:scrapy-redis默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作scrapy-redis都已经帮我们做好了,我们只需要继承RedisSpider、指定redis_key就行了。
缺点:scrapy-redis调度的任务是Request对象,里面信息量比较大(不仅包含url,还有callback函数、headers等信息),导致的结果就是会降低爬虫速度、而且会占用Redis大量的存储空间。当然我们可以重写方法实现调度url或者用户ID。
2.Master端跑一个程序去生成任务(Request/url/ID)。Master端负责的是生产任务,并把任务去重、加入到待爬队列。Slaver只管从Master端拿任务去爬。
优点:将生成任务和抓取数据分开,分工明确,减少了Master和Slaver之间的数据交流;Master端生成任务还有一个好处就是:可以很方便地重写判重策略(当数据量大时优化判重的性能和速度还是很重要的)。
缺点:像QQ或者新浪微博这种网站,发送一个请求,返回的内容里面可能包含几十个待爬的用户ID,即几十个新爬虫任务。但有些网站一个请求只能得到一两个新任务,并且返回的内容里也包含爬虫要抓取的目标信息,如果将生成任务和抓取任务分开反而会降低爬虫抓取效率。毕竟带宽也是爬虫的一个瓶颈问题,我们要秉着发送尽量少的请求为原则,同时也是为了减轻网站服务器的压力,要做一只有道德的Crawler。所以,视情况而定。
3.Master中只有一个集合,它只有查询的作用。Slaver在遇到新任务时询问Master此任务是否已爬,如果未爬则加入Slaver自己的待爬队列中,Master把此任务记为已爬。它和策略一比较像,但明显比策略一简单。策略一的简单是因为有scrapy-redis实现了scheduler中间件,它并不适用于非scrapy框架的爬虫。
优点:实现简单,非scrapy框架的爬虫也适用。Master端压力比较小,Master与Slaver的数据交流也不大。
缺点:“健壮性”不够,需要另外定时保存待爬队列以实现“断点续爬”功能。各Slaver的待爬任务不通用。 如果把Slaver比作工人,把Master比作工头。策略一就是工人遇到新任务都上报给工头,需要干活的时候就去工头那里领任务;策略二就是工头去找新任务,工人只管从工头那里领任务干活;策略三就是工人遇到新任务时询问工头此任务是否有人做了,没有的话工人就将此任务加到自己的“行程表”。
1.5、6万条数据相对来说数据量比较小,线程数量不做强制要求(做除法得一个合理值即可)
2.多线程使用代理,应保证不在同时一刻使用一个代理IP
3. 一般请求并发量主要考虑网站的反爬程度来定。
1. 使用 python 的 STMP 包将爬虫的状态信心发送到指定的邮箱
2. Scrapyd、pyspider
3. 引入日志 集成日志处理平台来进行监控,如 elk
静态页面可以考虑使用 http 的 head 方法查看网站的最后更新时间
如果前者行不通,则需要对数据进行标识,如利用加密算法生成指纹,然后定期发起请求获取数据,比对指纹是否一致,如果一致,说明网站没有更新;反之说明更新。
使用MD5数字签名,每次下载网页时,把服务器返回的数据流ResponseStream先放在内存缓冲区,然后对ResponseStream生成MD5数字签名S1,下次下载同样生成签名S2,比较S2和S1,如果相同,则页面没有跟新,否则网页就有更新。
增量爬取即保存上一次状态,本次抓取时与上次比对,如果不在上次的状态中,便视为增量,保存下来。对于scrapy来说,上一次的状态是抓取的特征数据和上次爬取的 request队列(url列表),request队列可以通过request队列可以通过scrapy.core.scheduler的pending_requests成员得到,在爬虫启动时导入上次爬取的特征数据,并且用上次request队列的数据作为start url进行爬取,不在上一次状态中的数据便保存。
选用BloomFilter原因:对爬虫爬取数据的保存有多种形式,可以是数据库,可以是磁盘文件等,不管是数据库,还是磁盘文件,进行扫描和存储都有很大的时间和空间上的开销,为了从时间和空间上提升性能,故选用BloomFilter作为上一次爬取数据的保存。保存的特征数据可以是数据的某几项,即监控这几项数据,一旦这几项数据有变化,便视为增量持久化下来,根据增量的规则可以对保存的状态数据进行约束。比如:可以选网页更新的时间,索引次数或是网页的实际内容,cookie的更新等...
一般爬虫使用的数据库,是根据项目来定的。如需求方指定了使用什么数据库、如果没指定,那么决定权就在爬虫程序员手里,如果自选的话,mysql 和 mongodb 用的都是比较多的。但不同的数据库品种有各自的优缺点,不同的场景任何一种数据库都可以用来存储,但是某种可能会更好。比如如果抓取的数据之间的耦合性很高,关系比较复杂的话,那么 mysql 可能会是更好的选择。如果抓取的数据是分版块的,并且它们之间没有相似性或关联性不强,那么可能 mongodb 会更好。另外主流的几种永久存储数据库,都是具备处理高并发、具备存储大量数据的能力的,只是由于各自的实现机制不一样,因此优化方案也是不尽相同。总结就是:数据库的选择尽量从项目的数据存在的特性来考虑,还有一个问题就是开发人员最擅长那种数据库。
MongoDB 是使用比较多的数据库,这里以 MongoDB 为例,大家需要结合自己真实开发环境回答。
原因:
1)与关系型数据库相比,MongoDB 的优点如下。
①弱一致性(最终一致),更能保证用户的访问速度
举例来说,在传统的关系型数据库中,一个 COUNT 类型的操作会锁定数据集,这样可以保证得到“当前”情况下的较精确值。这在某些情况下,例如通过 ATM 查看账户信息的时候很重要, 但对于 Wordnik 来说,数据是不断更新和增长的,这种“较精确”的保证几乎没有任何意义,反而 会产生很大的延迟。他们需要的是一个“大约”的数字以及更快的处理速度。
但某些情况下 MongoDB 会锁住数据库。如果此时正有数百个请求,则它们会堆积起来,造成许多问题。我们使用了下面的优化方式来避免锁定。
每次更新前,我们会先查询记录。查询操作会将对象放入内存,于是更新则会尽可能的迅速。在主/ 从部署方案中,从节点可以使用“-pretouch”参数运行,这也可以得到相同的效果。 使用多个 mongod 进程。我们根据访问模式将数据库拆分成多个进程。
②文档结构的存储方式,能够更便捷的获取数据。 对于一个层级式的数据结构来说,如果要将这样的数据使用扁平式的,表状的结构来保存数据, 这无论是在查询还是获取数据时都十分困难。
③内置 GridFS,支持大容量的存储。 GridFS 是一个出色的分布式文件系统,可以支持海量的数据存储。内置了 GridFS 了 MongoDB, 能够满足对大数据集的快速范围查询。
④内置 Sharding。 提供基于 Range 的 Auto Sharding 机制:一个 collection 可按照记录的范围,分成若干个段, 切分到不同的 Shard 上。Shards 可以和复制结合,配合 Replica sets 能够实现 Sharding+fail-over, 不同的 Shard 之间可以负载均衡。查询是对 客户端是透明的。客户端执行查询,统计,MapReduce 等操作,这些会被 MongoDB 自动路由到后端的数据节点。这让我们关注于自己的业务,适当的时候可以无痛的升级。MongoDB 的 Sharding 设计能力较大可支持约 20 petabytes,足以支撑一般 应用。
这可以保证 MongoDB 运行在便宜的 PC 服务器集群上。PC 集群扩充起来非常方便并且成本很低, 避免了“sharding”操作的复杂性和成本。
⑤第三方支持丰富。(这是与其他的 NoSQL 相比,MongoDB 也具有的优势) 现在网络上的很多 NoSQL 开源数据库完全属于社区型的,没有官方支持,给使用者带来了很大的风险。而开源文档数据库 MongoDB 背后有商业公司 10gen 为其提供供商业培训和支持。 而且 MongoDB 社区非常活跃,很多开发框架都迅速提供了对 MongDB 的支持。不少知名大公司和网站也在生产环境中使用 MongoDB,越来越多的创新型企业转而使用 MongoDB 作为和 Django,RoR 来搭配的技术方案。
⑥性能优越 。在使用场合下,千万级别的文档对象,近 10G 的数据,对有索引的 ID 的查询不会比 mysql 慢, 而对非索引字段的查询,则是全面胜出。 mysql 实际无法胜任大数据量下任意字段的查询,而 mongodb 的查询性能实在让我惊讶。写入性能同样很令人满意,同样写入百万级别的数据, mongodb 比我以前试用过的 couchdb 要快得多,基本 10 分钟以下可以解决。补上一句,观察过程中 mongodb 都远算不上是 CPU 杀手。
2)Mongodb 与 redis 相比较
①mongodb 文件存储是 BSON 格式类似 JSON,或自定义的二进制格式。 mongodb 与 redis 性能都很依赖内存的大小,mongodb 有丰富的数据表达、索引;最类似于关系数据库,支持丰富的查询语言,redis 数据丰富,较少的 IO ,这方面 mongodb 优势明显。
②mongodb 不支持事物,靠客户端自身保证,redis 支持事物,比较弱,仅能保证事物中的操作按顺序执行,这方面 redis 优于 mongodb。
③mongodb 对海量数据的访问效率提升,redis 较小数据量的性能及运算,这方面 mongodb 性能优于 redis .monbgodb 有 mapredurce 功能,提供数据分析,redis 没有 ,这方面 mongodb 优于 redis 。
Python 自带:urllib、urllib2
第三方:requests,aiohttp
框架: Scrapy、pyspider
urllib 和 urllib2 模块都做与请求 URL 相关的操作,但他们提供不同的功能。
urllib2:urllib2.urlopen 可以接受一个 Request 对象或者 url,(在接受 Request 对象时候,并以 此可以来设置一个 URL 的 headers),urllib.urlopen 只接收一个 url。
urllib 有 urlencode,urllib2 没有,因此总是 urllib,urllib2 常会一起使用的原因。
scrapy 是封装起来的框架,它包含了下载器,解析器,日志及异常处理,基于多线程,twisted 的 方式处理,对于固定单个网站的爬取开发,有优势,但是对于多网站爬取,并发及分布式处理方面,不够灵活,不便调整与括展。
request 是一个 HTTP 库, 它只是用来,进行请求,对于 HTTP 请求,他是一个强大的库,下载, 解析全部自己处理,灵活性更高,高并发与分布式部署也非常灵活,对于功能可以更好实现
aiohttp 是一个基于 python3 的 asyncio 携程机制实现的一个 http 库,相比 requests,aiohttp 自身就具备了异步功能。但只能在 python3 环境使用。
Scrapy 优点:
Scrapy 缺点:
一般情况下,在选择是使用多进程还是多线程时,主要考虑的业务到底是 IO 密集型(多线程)还是计算密集型(多进程)。在爬虫中,请求的并发业务属于是网络 的 IO 类型业务,因此网络并发适宜使用多线程;但特殊需求下,比如使用 phantomjs 或者 chrome-headless 来抓取的爬虫,应当是多进程的,因为每一个 phan/chro 实例就是一个进程了,并发只能是多进程。此外爬虫中还是数据处理业务,如果数据处理业务是一个比较耗时的计算型操作,那么对数据处理部分应当设为多进程,但更多可能会考虑将该部分数据处理操作和爬虫程序解耦,也就是先把数据抓取下来,事后单独运行另外的程序解析数据。
反爬虫简单的说指的是:网站根据某些因素断定该请求是一个爬虫程序发出的请求,然后对该请求采取了一定的制裁措施。
因此反爬虫应该从两方面来探讨:
1. 网站如何断定该请求是一个爬虫:请求头、请求频率、IP 地址、cookie 等(持续更新请求头、cookie、用户 cookie 池、代理 IP 池、设置一定的延时)
2. 网站如何制裁这个它认为是爬虫的请求(假数据、空数据、不返回响应、验证码、4xx 状态码等)
通过 Headers 反爬虫: 从用户请求的 Headers 反爬虫是最常见的反爬虫策略。很多网站都会对 Headers 的 User-Agent 进行检测,还有一部分网站会对 Referer 进行检测(一些资源网站的防盗链就是检测 Referer)。如果遇到了这类反爬虫机制,可以直接在爬虫中添加 Headers,将浏览器的User-Agent 复制到爬虫的Headers 中;或者将 Referer 值修改为目标网站域名。对于检测 Headers 的反爬虫,在爬虫中修改或者添加 Headers 就能很好的绕过。
基于用户行为反爬虫:
还有一部分网站是通过检测用户行为,例如同一 IP 短时间内多次访问同一页面,或者同一账户短时间内多次进行相同操作。
大多数网站都是前一种情况,对于这种情况,使用 IP 代理就可以解决。可以专门写一个爬虫,爬取网上公开的代理 ip,检测后全部保存起来。这样的代理 ip 爬虫经常会用到,最好自己准备一个。有了大量代理 ip 后可以每请求几次更换一个 ip,这在 requests 或者 urllib2 中很容易做到,这样就能很容易的绕过第一种反爬虫。
对于第二种情况,可以在每次请求后随机间隔几秒再进行下一次请求。有些有逻辑漏洞的网站,可 以通过请求几次,退出登录,重新登录,继续请求来绕过同一账号短时间内不能多次进行相同请求的限制。
动态页面的反爬虫:
上述的几种情况大多都是出现在静态页面,还有一部分网站,我们需要爬取的数据是通过 ajax 请求得到,或者通过 JavaScript 生成的。首先用 Fiddler 对网络请求进行分析。如果能够找到 ajax 请求, 也能分析出具体的参数和响应的具体含义,我们就能采用上面的方法,直接利用 requests 或者 urllib2 模拟 ajax 请求,对响应的 json 进行分析得到需要的数据。
能够直接模拟 ajax 请求获取数据固然是极好的,但是有些网站把 ajax 请求的所有参数全部加密了。 我们根本没办法构造自己所需要的数据的请求。这种情况下就用 selenium+phantomJS,调用浏览器内核,并利用 phantomJS 执行 js 来模拟人为操作以及触发页面中的 js 脚本。从填写表单到点击按钮再到滚动页面,全部都可以模拟,不考虑具体的请求和响应过程,只是完完整整的把人浏览页面获取数据的过程模拟一遍。
用这套框架几乎能绕过大多数的反爬虫,因为它不是在伪装成浏览器来获取数据(上述的通过添加 Headers 一定程度上就是为了伪装成浏览器),它本身就是浏览器,phantomJS 就是一个没有界面的 浏览器,只是操控这个浏览器的不是人。利 selenium+phantomJS 能干很多事情,例如识别点触式 (12306)或者滑动式的验证码,对页面表单进行暴力破解等。
解决限制 IP 可以使用代理 IP 地址池、服务器;
不适用动态爬取的情况下可以使用反编译 JS 文件获取相应的文件,或者换用其他平台(比如手机端) 看看是否可以获取相应的 json 文件。
图形验证码:干扰、杂色不是特别多的图片可以使用开源库 Tesseract 进行识别,太过复杂的需要 借助第三方打码平台。
点击和拖动滑块验证码可以借助 selenium、无图形界面浏览器(chromedirver 或者 phantomjs) 和 pillow 包来模拟人的点击和滑动操作,pillow 可以根据色差识别需要滑动的位置。
手动打码(有的验证码确实无解)
MySQL 数据库:开源免费的关系型数据库,需要实现创建数据库、数据表和表的字段,表与表之 间可以进行关联(一对多、多对多),是持久化存储。
Mongodb 数据库:是非关系型数据库,数据库的三元素是,数据库、集合、文档,可以进行持久 化存储,也可作为内存数据库,存储数据不需要事先设定格式,数据以键值对的形式存储。
redis 数据库:非关系型数据库,使用前可以不用设置格式,以键值对的方式保存,文件格式相对自由,主要用与缓存数据库,也可以进行持久化存储。
字符是各种文字和符号的总称,包括各个国家文字、标点符号、图形符号、数字等。
字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有: ASCII 字符集、ISO 8859 字符集、GB2312 字符集、BIG5 字符集、GB18030 字符集、Unicode 字符集等。
字符编码就是以二进制的数字来对应字符集的字符。
常见的编码字符集(简称字符集)如下所示:
Unicode:也叫统一字符集,它包含了几乎世界上所有的已经发现且需要使用的字符 (如中文、日文、英文、德文等)。
ASCII:ASCII 既是编码字符集,又是字符编码。早期的计算机系统只能处理英文,所以 ASCII 也 就成为了计算机的缺省字符集,包含了英文所需要的所有字符。
GB2312:中文字符集,包含 ASCII 字符集。ASCII 部分用单字节表示,剩余部分用双字节表 示。
GBK:GB2312 的扩展,但完整包含了 GB2312 的所有内容。
GB18030:GBK 字符集的超集,常叫大汉字字符集,也叫 CJK(Chinese,Japanese, Korea)字符集,包含了中、日、韩三国语。
注意:Unicode 字符集有多种编码方式,如 UTF-8、UTF-16 等;ASCII 只有一种;大多 数 MBCS(包括 GB2312)也只有一种。
user-agent、代理池等。
因为 cookie 存在过期的现象,一个很好的处理方法就是做一个异常类,如果有异常的话 cookie 抛 出异常类在执行程序。
分析出数据接口 API(利用 chrome 或者抓包工具),然后利用 requests 等 http 库实现爬虫,如 果有需要执行 js 代码,可借助 js2py、pyexecjs 等工具实现。
Selenium+Phantomjs
尽量不使用 sleep 而使用 WebDriverWait
优点:
1、使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
2、HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 http 协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
3、HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本
缺点:
1.HTTPS 协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用
2.HTTPS 协议还会影响缓存,增加数据开销和功耗,甚至已有安全措施也会受到影响也会因此 而受到影响。
3.SSL 证书需要钱。功能越强大的证书费用越高。个人网站、小网站没有必要一般不会用。
4.HTTPS 连接服务器端资源占用高很多,握手阶段比较费时对网站的相应速度有负面影响。
5.HTTPS 连接缓存不如 HTTP 高效。
HTTPS 其实就是在 HTTP 跟 TCP 中间加多了一层加密层 TLS/SSL。SSL 是个加密套件,负责对 HTTP 的数据进行加密。TLS 是 SSL 的升级版。现在提到 HTTPS,加密套件基本指的是 TLS。原先是应用层将数据直接给到 TCP 进行传输,现在改成应用层将数据给到 TLS/SSL,将数据加密后,再给到 TCP 进行 传输。
Selenium 是一个 Web 的自动化测试工具,可以根据我们的指令,让浏览器自动加载页面,获取需 要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行, 所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器。Selenium 库里有个叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以像 BeautifulSoup 或者其他Selector 对象一样用来查找页面元素,与页面上的元素进行交互 (发送文本、点击等),以及执行其他 动作来运行网络爬虫。
PhantomJS 是一个基于 Webkit 的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。相比传统的 Chrome 或 Firefox 浏览器等,资源消耗会更少。 如果我们把 Selenium 和 PhantomJS 结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理 JavaScript、Cookie、headers,以及任何我们真实用户需要做的事情。 主程序退出后,selenium 不保证 phantomJS 也成功退出,最好手动关闭 phantomJS 进程。(有可能会导致多个 phantomJS 进程运行,占用内存)。 WebDriverWait 虽然可能会减少延时,但是目前存在 bug(各种报错),这种情况可以采用 sleep。 phantomJS 爬数据比较慢,可以选择多线程。如果运行的时候发现有的可以运行,有的不能,可以尝试将 phantomJS 改成 Chrome。
透明代理的意思是客户端根本不需要知道有代理服务器的存在,但是它传送的仍然是真实的 IP。你要想隐藏的话,不要用这个。
普通匿名代理能隐藏客户机的真实 IP,但会改变我们的请求信息,服务器端有可能会认为我们使用了代理。不过使用此种代理时,虽然被访问的网站不能知道你的 ip 地址,但仍然可以知道你在使用代理,当然某些能够侦测 ip 的网页仍然可以查到你的 ip。
高匿名代理不改变客户机的请求,这样在服务器看来就像有个真正的客户浏览器在访问它,这时客 户的真实 IP 是隐藏的,服务器端不会认为我们使用了代理。 设置代理有以下两个好处:
1,让服务器以为不是同一个客户端在请求
2,防止我们的真实地址被泄露,防止被追究
a)response.text 返回的是 Unicode 型数据;
a)response.content 返回的是 bytes 类型,也就是二进制数据;
b)获取文本使用,response.text;
b)获取图片,文件,使用 response.content;
c)response.text
c)response.content
Robots 协议:网站通过 Robots 协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
让我们的爬虫请求看起来就是一个正常的浏览器请求
原因是:模拟浏览器,欺骗服务器,获取和浏览器一致的内容
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)
json.dumps()将 pyhton 的 dict 数据类型编码为 json 字符串;
json.loads()将 json 字符串解码为 dict 的数据类型;
json.dump(x,y) x 是 json 对象, y 是文件对象,最终是将 json 对象写入到文件中;
json.load(y) 从文件对象 y 中读取 json 对象。
1、reqeusts.util.dict_from_cookiejar 把 cookie 对象转化为字典
1.1. requests.get(url,cookies={})
2、设置请求不用 SSL 证书验证 response = requests.get("https://www.12306.cn/mormhweb/ ", verify=False)
3、设置超时 response = requests.get(url,timeout=10)
4、配合状态码判断是否请求成功
assert response.status_code == 200
1. 自己维护代理池
2. 付费购买(目前市场上有很多 ip 代理商,可自行百度了解,建议看看他们的接口文档(API&SDK))
存放在数据库(redis、mysql 等)。
维护多个代理网站:
一般代理的存活时间往往在十几分钟左右,定时任务,加上代理 IP 去访问网页,验证其是否可用, 如果返回状态为 200,表示这个代理是可以使用的。
1. Web 端加密可尝试移动端(app)
2. 解析加密,看能否破解
3. 反爬手段层出不穷,js 加密较多,只能具体问题具体分析
分析前端 js 文件,找到加密解密数据的 js 代码,用 Python 代码实现或者利用 js2py 或 pyexecjs 等执行 js 代码
从 start_urls 里获取第一批 url 并发送请求,请求由引擎交给调度器入请求队列,获取完毕后,调度器将请求队列里的请求交给下载器去获取请求对应的响应资源,并将响应交给自己编写的解析方法做提取处理:
1. 如果提取出需要的数据,则交给管道文件处理;
2. 如果提取出 url,则继续执行之前的步骤(发送 url 请求,并由引擎将请求交给调度器入队列...), 直到请求队列里没有请求,程序结束。
3. 根据 scrapy 的流程图,描述出五大组件、两个中间件,以及完成一个请求的流程。
scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量代码, 就能够快速的抓取到数据内容。Scrapy 使用了 Twisted 异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。
scrapy 框架的工作流程:
1.首先 Spiders(爬虫)将需要发送请求的 url(requests)经 ScrapyEngine(引擎)交给 Scheduler (调度器)。
2.Scheduler(排序,入队)处理后,经 ScrapyEngine,DownloaderMiddlewares(可选,主要 有 User_Agent, Proxy 代理)交给 Downloader。
3.Downloader 向互联网发送请求,并接收下载响应(response)。将响应(response)经 ScrapyEngine,SpiderMiddlewares(可选)交给 Spiders。
4.Spiders 处理 response,提取数据并将数据经 ScrapyEngine 交给 ItemPipeline 保存(可以是本 地,可以是数据库)。提取 url 重新经 ScrapyEngine 交给 Scheduler 进行下一个循环。直到无 Url 请求程序停止结束。
使用 FormRequest
class mySpider(scrapy.Spider):
# start_urls = ["http://www.taobao.com/"]
def start_requests(self):
url = 'http://http://www.taobao.com//login'
# FormRequest 是 Scrapy 发送 POST 请求的方法
yield scrapy.FormRequest(
url=url,
formdata={"email": "xxx", "password": "xxxxx"},
callback=self.parse_page
)
# do something
Scrapy 使用信号来通知事情发生,因此答案是 signals 模块。
1.通过 MD5 生成电子指纹来判断页面是否改变
2.nutch 去重。nutch 中 digest 是对采集的每一个网页内容的 32 位哈希值,如果两个网页内容完 全一样,它们的 digest 值肯定会一样。
数据量不大时,可以直接放在内存里面进行去重,python 可以使用 set()进行去重。当去重数据 需要持久化时可以使用 redis 的 set 数据结构。
当数据量再大一点时,可以用不同的加密算法先将长字符串压缩成 16/32/40 个字符,再使用 上面两种方法去重。
当数据量达到亿(甚至十亿、百亿)数量级时,内存有限,必须用“位”来去重,才能够满足需求。Bloomfilter 就是将去重对象映射到几个内存“位”,通过几个位的 0/1 值来判断一个对象是否已经存在。
然而 Bloomfilter 运行在一台机器的内存上,不方便持久化(机器 down 掉就什么都没啦),也不 方便分布式爬虫的统一去重。如果可以在 Redis 上申请内存进行 Bloomfilter,以上两个问题就都能解决了。
simhash 最牛逼的一点就是将一个文档,最后转换成一个 64 位的字节,暂且称之为特征字,然后判断重复只需要判断他们的特征字的距离是不是 可见 scrapy_redis 是利用 set 数据结构来去重的,去重的对象是 request 的 fingerprint(其实 就是用 hashlib.sha1()对 request 对象的某些字段信息进行压缩)。其实 fp 就是 request 对象加密 压缩后的一个字符串(40 个字符,0~f)。 优点: 1)scrapy 是异步的 2)采取可读性更强的 xpath 代替正则 3)强大的统计和 log 系统 4)同时在不同的 url 上爬行 5)支持 shell 方式,方便独立调试 6)写 middleware,方便写一些统一的过滤器 7)通过管道的方式存入数据库 缺点: 1)基于 python 的爬虫框架,扩展性比较差 2)基于 twisted 框架,运行中的 exception 是不会干掉 reactor(反应器),并且异步框架出错后 是不会停掉其他任务的,数据出错后难以察觉。 scrapy 是一个 Python 爬虫框架,爬取效率极高,具有高度定制性,但是不支持分布式。而 scrapy-redis 一套基于 redis 数据库、运行在 scrapy 框架之上的组件,可以让 scrapy 支持分布式策略, Slaver 端共享 Master 端 redis 数据库里的 item 队列、请求队列和请求指纹集合。 为什么选择 redis 数据库,因为 redis 支持主从同步,而且数据都是缓存在内存中的,所以基于 redis 的分布式爬虫,对请求和数据的高频读取效率非常高。 1.ip 2.带宽 3.cpu 4.io 传统定义:分布式存储系统是大量 PC 服务器通过 Internet 互联,对外提供一个整体的服务。 分布式存储系统具有以下的几个特性: 可扩展 :分布式存储系统可以扩展到几百台甚至几千台这样的一个集群规模,系统的整体性能线性增长。 低成本 :分布式存储系统的自动容错、自动负载均衡的特性,允许分布式存储系统可以构建在低成本的服务器上。另外,线性的扩展能力也使得增加、减少服务器的成本低, 实现分布式存储系统的自动运维。 高性能 :无论是针对单台服务器,还是针对整个分布式的存储集群,都要求分布式存储系统具备高性能。 易用 :分布式存储系统需要对外提供方便易用的接口,另外,也需要具备完善的监控、运维工具,并且可以方便的与其他的系统进行集成。 布式存储系统的挑战主要在于数据和状态信息的持久化,要求在自动迁移、自动容错和并发读写的过程中,保证数据的一致性。 容错:可以快速检测到服务器故障,并自动的将在故障服务器上的数据进行迁移。 负载均衡:新增的服务器在集群中保障负载均衡?数据迁移过程中保障不影响现有的服务。 事务与并发控制:实现分布式事务。 易用性:设计对外接口,使得设计的系统易于使用。 三种分布式爬虫策略: 1.Slaver 端从 Master 端拿任务(Request/url/ID)进行数据抓取,在抓取数据的同时也生成新任务,并将任务抛给 Master。Master 端只有一个 Redis 数据库,负责对 Slaver 提交的任务进行去重、加入待爬队列。 优点: scrapy-redis 默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作 scrapy-redis 都已经帮我们做好了,我们只需要继承 RedisSpider、指定 redis_key 就行了。 缺点: scrapy-redis 调度的任务是 Request 对象,里面信息量比较大(不仅包含 url, 还有 callback 函数、headers 等信息),导致的结果就是会降低爬虫速度、而且会占用 Redis 大量的存储空间。当然我们可以重写方法实现调度 url 或者用户 ID。 2.Master 端跑一个程序去生成任务(Request/url/ID)。Master 端负责的是生产任务,并把任务去重、加入到待爬队列。Slaver 只管从 Master 端拿任务去爬。 优点: 将生成任务和抓取数据分开,分工明确,减少了 Master 和 Slaver 之间的数据交流;Master 端生成任务还有一个好处就是:可以很方便地重写判重策略(当数据量大时优化判重的性能和速度还是很重要的)。 缺点: 像 QQ 或者新浪微博这种网站,发送一个请求,返回的内容里面可能包含几十个待爬的用户 ID,即几十个新爬虫任务。但有些网站一个请求只能得到一两个新任务,并且返回的内容里也包含爬虫要抓取的目标信息,如果将生成任务和抓取任务分开反而会降低爬虫抓取效率。毕竟带宽也是爬虫的一个瓶颈问题,我们要秉着发送尽量少的请求为原则,同时也是为了减轻网站服务器的压力,要做一只有道德的 Crawler。所以,视情况而定。 3.Master 中只有一个集合,它只有查询的作用。Slaver 在遇到新任务时询问 Master 此任务是否已爬,如果未爬则加入 Slaver 自己的待爬队列中,Master 把此任务记为已爬。它和策略一比较像,但明显比策略一简单。策略一的简单是因为有 scrapy-redis 实现了 scheduler 中间件,它并不适用于非 scrapy 框架的爬虫。 优点: 实现简单,非 scrapy 框架的爬虫也适用。Master 端压力比较小,Master 与 Slaver 的数据交流也不大。 缺点:“健壮性”不够,需要另外定时保存待爬队列以实现“断点续爬”功能。各 Slaver 的待爬任务不通用。 如果把 Slaver 比作工人,把 Master 比作工头。策略一就是工人遇到新任务都上报给工头,需要干活的时候就去工头那里领任务;策略二就是工头去找新任务,工人只管从工头那里领任务干活;策略三就是工人遇到新任务时询问工头此任务是否有人做了,没有的话工人就将此任务加到自己的“行程表”。 Celery、gearman 等,参考其他分布式爬虫策略。 判读字段缺失,做异常处理即可。 代理服务器英文全称是 Proxy Server,其功能就是代理网络用户去取得网络信息。形象的说:它是 网络信息的中转站。 代理服务器可以实现各种时髦且有用的功能。它们可以改善安全性,提高性能,节省费用。 代理可以假扮 Web 服务器。这些被称为替换物(surrogate)或反向代理(reverse proxy)的代理接收 发送给 Web 服务器的真实请求,但与 Web 服务器不同的是,它们可以发起与其他服务器的通信,以便按需定位所请求的内容。 可以用这些反向代理来提高访问慢速 Web 服务器上公共内容的性能。在这种配置中,通常将这些 反向代理称为服务器加速器(server accelerator)。还可以将替换物与内容路由功能配合使用,以创建按需复制内容的分布式网络。 lxml46.Scrapy 的优缺点?
47.scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?
48.分布式爬虫主要解决什么问题?
49.什么是分布式存储?
50.你所知道的分布式爬虫方案有哪些?
51.除了 scrapy-redis,有做过其他的分布式爬虫吗?
52.在爬取的时候遇到某些内容字段缺失怎么判断及处理?
53.什么是 HTTP 代理?作用是什么?
54. 什么是反向代理?作用是什么?
55.xpath 使用的什么库?