答疑·限时优惠

如果,你想让我看见你的疑问并且百分之百的回答。可以加入我的知识星球。
AI悦创·进化岛
AI悦创·进化岛

你好,我是悦创。

互联网诞生之初,是为了让人们更容易的分享数据、交流通讯。互联网是桥梁,连接了世界各地的人们。网站的点击、浏览都是人为的,与你聊天的也是活生生的人。

然而,随着技术的发展,人们对数据的渴望,出现了各种网络机器人,这个时候,你不知道屏幕那端跟你聊天的是一个人还是一条狗,你也不知道你网站的浏览量是人点击出来的,还是机器爬出来的。

什么是网络爬虫?


表面上看,互联网上是各种各样的人;暗地里,已经布满了形形色色的网络爬虫。

在讲什么是爬虫之前呢,我来讲讲爬虫的职位问题,这也是很多同学报名我的爬虫私教课的初心之一。

1. 大数据时代的爬虫岗位

1567385090634

上面的图片数据,就是为了提高大家对于学习网络爬虫兴趣。可见,爬虫工程师的工资不低鸭!

2. 网络爬虫概况

当今最大的网络是互联网,最大的爬虫就是各类搜索引擎,包括谷歌、百度等。网络爬虫就是按照一定规则去爬取人类所需要的信息的程序,主要通过对 URL 的请求来实现。

一般来说,从搜索引擎这类爬虫搜索到的信息是非常宽泛的,而且夹杂着各种广告,信息是不纯粹的,也有可能不是我们需要的。

这种时候,就需要一些聚焦于某一方面信息的爬虫来为我们服务,比方说,专门爬取某一类书的信息,在网站上浏览的时候,可能会有形形色色的图片和一些其他信息干扰我们,如果编写网络爬虫的话,就可以单单把自己想要的信息存储下来,以便数据分析,提取有用的信息。

1567411344575

像我们平时用的,谷歌浏览器、火狐浏览器、IE浏览器等,这些浏览器不是搜索引擎哦,主要的作用是:渲染我们的这些网页。

其实,这个浏览器和我们平时写的小爬虫最大的区别就是:我们平时的小爬虫抓取的网页源代码的不渲染的,直接把网页的源代码 HTML 展现出来,而浏览器是会加载 HTML 相关的 CSS、JS 等。爬虫是不会执行这些关联的文件。

3. 搜索引擎时代的网络爬虫

关于网络爬虫的概念,我们先来瞅瞅维基百科(Wikipedia)上面的定义:

网络爬虫(英语:web crawler),也叫网上蜘蛛(spider),是一种用来自动浏览万维网的网络机器人。其目的一般为编纂网络索引。

这里提到的编纂网络索引,就是搜索引擎干的事情。我们对搜索引擎并不陌生,Google、百度等搜索引擎可能每天都在帮我们快速获得信息。可能同学们要问,搜索引擎的工作过程是怎样的呢?

首先,就是有网络爬虫不断抓取各个网站的网页,存放到搜索引擎的数据库;

接着,索引程序读取数据库的网页进行清理,建立倒排索引;

最后,搜索程序接收用户的查询关键词,去索引里面找到相关内容,并通过一定的排序算法(Pagerank等)把最相关最好的结果排在最前面呈现给用户。「吐槽一下:百度并不是把相关最好的结果排在最前面,而是广告比较多 !」

看上去简简单单的三个部分,却构成了强大复杂的搜索引擎系统。而网络爬虫是其中最基础也很重要的一部分,它决定着搜索引擎数据的完整性和丰富性。我们也看到网络爬虫的主要作用是获取数据。

由此简单地说,网络爬虫就是获取互联网公开数据的自动化工具。

这里要强调一下,网络爬虫爬取的是互联网上的公开数据,而不是通过特殊技术非法入侵到网站服务器获取的非公开数据。

那么同学们可能要问,什么是 “公开数据” 呢?

简而言之,就是网站上公开让用户浏览、获取的数据。

虽然数据是公开的,但是当某人或机构(如,搜索引擎)大量收集这些数据并因此获利时,也会让数据生产方——网站很不爽,由此而产生法律纠纷。比如,早些年 Google 因此而惹上官司。

网站们看着搜索引擎,因为搜索引擎抓取自己的内容而获利不爽,但也因为搜索引擎带来的流量而高兴不已,于是就出现了网站主动进行搜索引擎优化(SEO, Search Engine Optimization),也就是告诉搜索引擎,我这里的内容好,快来抓取吧!

1567651213396

搜索引擎和网站的博弈,催生了一个君子协议: robots.txt 。网站在自己的网站上放上这个文件,告诉爬虫哪些内容可以抓,哪些内容不可以抓;

搜索引擎读取网站的 robots.txt 来知道自己的抓取范围,同时也在访问网站时通过 User-Agent 来向网站表明自己的身份(这种表明也是君子协议,技术上很容易假扮他人),比如,Google 的爬虫叫做 Googlebot,百度的爬虫叫做 Baiduspider。这样,二者和平共处,互惠互利。

1567651533972

3.1 使用 robots.txt

1567651829580

from urllib import robotparser

rp = robotparser.RobotFileParser()
rp.set_url('https://www.baidu.com/robots.txt')
url = 'https://www.baidu.com/'
print(rp.can_fetch('Python', url))

4. 大数据时代的网络爬虫

时代在发展,数据变得越来越重要,“大数据”已经成为各行各业讨论的话题,人们对数据的渴望也变成贪婪,数据也就成了“石油”,爬虫也就成了“钻井机”。

为了获取石油,人们使用钻井机;

为了获取数据,人们使用爬虫。

为了获得数据,人们把互联网钻的是“千疮百孔”。

哈哈,这里有些夸张。

但人们对数据的获取,已经打破的君子协定,和网站们玩起了猫捉老鼠的游戏,展开了道高一尺魔高一丈的较量。

为什么说是较量呢?

因为大量爬虫的行为会给网站带来网络带宽、服务器计算力等方面很大的压力,却几乎不带来任何利益。

为了降低这种毫无利益的压力和避免自己的数据被他人集中收集,网站肯定要通过技术手段来限制爬虫;另一方面,爬虫为了获取石油般的数据,就想方设法来突破这种限制。

对于这种较量的理解,还是看活生生的例子来得更透彻。

  • 你有没有花几十块钱让某个软件帮你抢火车票?
    • 攻: 抢票爬虫会不断访问 12306 来获得火车票座位数据,并进而购买火车票;
    • 防: 12306 网站出了变态的认证码,人都经常识别错误。
  • 各种秒杀让你很受伤!
    • 攻: 研究网站的秒杀机制,提前写好爬虫,秒杀时刻,人快不过机器;
    • 防: 有些秒杀的宣传作用很大就懒得防;有些秒杀机制复杂到你很难写出对应的爬虫;有些秒杀成功被发现作弊也会被取消。

爬虫变得越来越多,越来越肆无忌惮,网站也不得不使用各种技术手段来禁止或限制爬虫。这些手段大致包括:

  • 使用账户保护数据,数据仅对登录用户可见;
  • 数据多次异步加载;
  • 限制IP访问频率,甚至封锁 IP;
  • 输入验证码以获得访问权限;
  • 数据在服务器端加密,浏览器端解密;
  • ……

而这些手段也是爬虫在技术实现中要解决和突破的问题。

5. 网络爬虫的分类

网络爬虫的分类


现在的网络爬虫大体可以分为四类:全网爬虫,主题爬虫,增量式爬虫和深层爬虫。

  1. 全网爬虫:也就是谷歌百度等搜索引擎,这类爬虫会从一些非常基础的 URl 出发,一直延伸到整个网站,这类爬虫庞大臃肿,需要很大的存储空间以及极高的爬行速度。

  2. 主题爬虫:满足特定人的特定需求,不同于全网爬虫,它是有选择地爬行与需求相关的信息。

  3. 增量式爬虫:对已经下载的页面采取增量式更新的爬虫,只爬取新产生的或者发生变化的网页,一定程度上可以保证爬取得页面是最新的,减少了空间的浪费,但是复杂度较高。

  4. 深层网络爬虫:不能通过静态 URL 访问,隐藏在表单后,只有用户提交一些关键词才能得到的页面。

PS: 深层网络爬虫也就是我们所说的暗网,我们一般接触到就是一些 POST 表单,登录页面之类的,你输入账户密码之后,点击登录。这就是一个深层网络爬虫。

为啥子呢?因为我们的爬虫是自动爬不到里面的,必须设置一些参数才是可以的。

举个例子:比如我建立了一个网络爬虫。要求它从百度开始遍历所有网站,它遇到有验证码的有登录的就进不去了。因为,它之后的页面是隐藏在表单之后,这个东西就叫网络爬虫(它也是归入暗网的范畴)

咱们来个简单的介绍暗网:

暗网(不可见网,隐藏网)是指那些存储在网络数据库里、但不能通过超链接访问而需要通过动态网页技术访问的资源集合,不属于那些可以被标准搜索引擎索引的表面网络。

暗网是深网(Deep Web)的一个子集,属于深网的一小部分。

迈克尔·伯格曼将当今互联网上的搜索服务比喻为像在地球的海洋表面的拉起一个大网的搜索,大量的表面信息固然可以通过这种方式被查找得到,可是还有相当大量的信息由于隐藏在深处而被搜索引擎错失掉。绝大部分这些隐藏的信息是须通过动态请求产生的网页信息,而标准的搜索引擎却无法对其进行查找。传统的搜索引擎“看”不到,也获取不了这些存在于暗网的内容,除非通过特定的搜查这些页面才会动态产生。于是相对的,暗网就隐藏了起来。 ----------来源----------《百度百科》

其实,多说一句,暗网并不难,使用洋葱路由器就可以登陆。


5.1 增量式爬虫 (爬虫策略)

1567507132647


举个例子:

还是以微博为例,微博上有个热搜版块,现在公司的需求是抓取实时的热搜信息,持续一周的时间。这个时候,我们最优的爬取就是增量爬,每次只爬新出现 的,或者被修改过的。这样数量越多,速度越快,后期速度就可以提升几百倍。

具体举例:

第一次抓取,则需要抓取全部数据。所需的抓取时间比如:12h,那等你第二天再抓取该微博热搜榜,难道要继续再重新全部抓取一遍和存储么?

显然这是非常低效的,所以,这个增量式爬虫就是 只爬取微博热搜榜上新出现的数据(评论)或者哪些式被修改的数据等等 这样原本所需要 12h 的抓取时间,就比如变成 2h 实际时间。不过这个时间还是按实际情况来。(有硬件、网络、策略、实现方法等影响因素)

我们先来快速简单的回顾一下:

  1. 请求网站资源
  2. 如果网站的给你返回一个 status_code 是200,那服务器就会给你返回那个资源
  3. 然后,我们需要 Parser 来解析我们得到的资源。可以用来解析的轮子有哪些呢?
    • BeautifulSoup
    • PyQuery
    • Xpath
    • re (正则表达式)
  4. 存储入库

实现:

  1. 发送请求前——判断这个 URL 是不是之前爬取过的(爬取过的 Url 我们就不再继续爬取)
  2. 解析内容后——判断这部分内容是不是之前爬取过(也就是解析得到数据之后,判断之前是否有爬取到过。实现方法就类似我们可以创建一个很大的数据库池。然后,把你解析得到的数据和里面的数据进行比对一下,看有无变化)
  3. 存储介质(数据入库时)——判断内容是不是已经在介质中存在(判断我解析得到的数据是不是在我们数据库已经出现过了,如果出现的话,我们就不入库。如果是修改过的我们就把新修改过的在重新入库,替换掉原先那个)

难点:其实增量式爬虫最难的那部分,就是数据的比对呢?

  • 常见的增量式爬虫使用 哈希
  • 哈希可以生成独一无二的哈希数字
  • 我们只需要比对哈希即可

代码示例:

# -*- coding: utf-8 -*-
# 开发团队   :AI悦创
# 开发人员   :AI悦创
# 开发时间   :2019/9/4  8:25 
# 文件名称   :haxi_1.PY
# 开发工具   :PyCharm
text = "这是第一个评论"
text2 = "这是第二个评论"
text3 = "这是第一个评论"
print(hash(text))
print(hash(text2))
print(hash(text3))
compare = text == text3
print(f'text == text3 is {compare}')

输出:
# 注意,不同编译器,不同电脑环境生成的哈希是不一样的。
#  就算是同一台电脑同一个编译器,每次运行生成的哈希数字也是不一样的。

# 第一次运行输出:
1136825877591950482
-1853188872266928196
1136825877591950482
text == text3 is True

# 第二次运行输出:
-1711655599760904659
-4125108592533926432
-1711655599760904659
text == text3 is True

# 第三次运行输出:
-1365827303885436725
-4683858178280503991
-1365827303885436725
text == text3 is True

# 这里你还会发现,虽然每次生成都会变化,但最后一行对相同的字符串做出比较还是成功的也就是(True)。
# 哈希值设涉及数据结构和算法,有兴趣的学员的自行了解。

扩展:

A:老师,我想选择的是标签是span class是font的,为什么上面那个class='day font'也会被选择到

Teacher:标签里的class可以使用多个类,在前端多个css一起用是用空格分割的,每一个class都是独立的

B:老师python3的hash() 是不是和python2里的 hash() 不一样呀

代码示例:

Python2:

1567641445917

Python3:

1567641507981

C:好像每一次生成的都不一样

Teacher:本身就是随机的,环境不同会出现不同运算结果,算法改进了。

那这个 hash 生成的随机数,如何来帮助我们实现 增量式爬虫呢?

我例如可以,在每一条得到的数据在入库之前,哈希一下。然后可以把它的数字比如存进一个集合里面(集合:里面只能存在不同的对象)。

set()

再详细一些就是:当我们把第一个数据例如上面的 hash 测试代码 第一个哈希:这是第一个评论,生成的伪随机数,存到我们的集合里面,第二个哈希由:这是第二个评论,生成的伪随机数,也存到我们所创建的集合中。当第三个哈希由:这是第一个评论,生成的伪随机数,存到集合中,集合将会将他阻挡在外。

当然,你还可以使用数据库,建立一个唯一索引

扩展:还有 指纹、布隆过滤器等(相关数学)

5.2 提取信息

1567644524354

5.3 保存爬虫数据

1567644679528

1567644780589


问题:有人可能会问为什么存到数据库里,这个数据库不也是在我电脑硬盘里面存在的吗?

答:虽然数据库也是装在我们的电脑里面,和我们直接存储这些:txt、world、Excel、CSV等文件,有什么区别呢?

其实,学过计算机原理的都懂哈。我们直接存储在硬盘里面(Disk)存储的速度是比较慢的。这是因为如下:

1.我们的操作系统,会把它压入一个高速缓冲区,之后再慢慢的刷新到我们的硬盘里面。

相比之下,我们直接操作 CPU 就非常之快了,例如:我们的内存型数据库 Redis 就是直接存储在数据库中。(我们的 CUP 内存里面)比操作在硬盘里面的高速缓冲区,快了不止十倍。

所以,Redis 现在是默认程序员掌握的。

但是,Redis 存储在内存有个不好的地方就是,你可能存的太多有可能把内存搞奔溃——内存溢出

另一个就是,我i可能偶尔发生断电这些,电脑突然黑屏关机了。那这些数据全部消失了,所以,用 CPU 这样的方法,还是要有集群方案,和容灾措施、及时的备份、和 log(日志)

6. 网络爬虫的自我约束

看完上面“猫捉老鼠”的游戏的描述,同学们不禁要问,网站和爬虫这种对抗较量会不会引起法律问题?

这是一个很好的问题,也是值得每个爬虫开发者思考的问题。

爬虫作为一种技术本身可能无所谓善恶,但是使用它的人就有善恶之分。

如何使用爬虫,爬取的数据如何使用,都可能产生潜在的法律问题。作为技术开发的程序员,都应该思考这个问题。无论何种目的,网络爬虫都不能突破法律的底线,同时也有遵守一定的准则:

  • 遵循 robots.txt 协议;
  • 避免短时间高并发访问目标网站,避免干扰目标网站的正常运行;
  • 不要抓取个人信息,比如手机通讯录等;
  • 使用抓来的数据注意隐私保护,合法合规。

守法合规,既是一直自我约束,也是自我保护。

7. 我们可以抓什么数据

1567652770920


8. 识别网站技术

pip install builtwith

可以检测网站的一些常见技术

# !/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author:AI悦创 @DateTime :2020/1/5 17:44 @Function :功能  Development_tool :PyCharm
# code is far away from bugs with the god animal protecting
#    I love animals. They taste delicious.
# 如何识别网站技术
import builtwith
from pprint import pprint

# url = 'https://www.baidu.com/'
url = 'https://www.cnblogs.com/'
html = builtwith.builtwith(url)
pprint(html)

# ----------------输出----------------
{'advertising-networks': ['DoubleClick for Publishers (DFP)'],
 'javascript-frameworks': ['jQuery']}

Process finished with exit code 0

9. 网络爬虫策略:

1567653517846


9.1 广度优先算法

1567653581134


比如下图是个 url 树,在程序进行 url 提取和访问的时候所提取的步骤是图中所写的编号(其实,这个也是二叉树)图中的顺序就是按广度优先算法来操作与读取的。也就是一层一层的来操作。


image-20200106002434484


我们用糗事百科来说:

比如我吗要爬取这个热门下面的所有 url,我使用广度优先算法(BFS)来进行抓取的话,它的顺序是:先把这个热门页面下的 所有 url 都爬取下来,我们不会特别进入每一个里面,我们就会继续爬 第二页、第三页、第四页......

image-20200106005356414


然后,我们再进入到单个里面把所有的 url 爬取下来。再进入到下一个爬取 url

(这其实,就是一层一层的往下爬取)

也就是,先扩展再深入。

image-20200106181857876


1567653839406


9.2 深度优先算法

1567653920231


可以理解为:一条路走到黑(不撞南墙不回头)

我们也再一次的来使用 二叉树来讲解我们的深度优先算法,下图所标的序号就是我们所说的深度优先算法。

image-20200106185501105

9.3 聚焦爬虫

1567654129820


相对于通用网络爬虫,聚焦爬虫解决三个主要问题:

  1. 对抓取目标的描述或定义;
  2. 对网页或数据的分析与过滤;
  3. 对 URL 的搜索策略。

抓取目标的描述和定义是决定网页分析算法与 URL 搜索策略如何制定的基础。

而网页分析算法和候选 URL 排序算法是决定搜索引擎所提供的服务形式和爬虫网页抓取行为的关键所在。这两个部分的算法又是紧密相关的。

制定 URL 搜索策略:

当然除了上面讲的:BFS(广度优先)、DFS(深度优先),我们不经常使用这么简单的爬虫策略了。

例如:按优先级的爬虫策略

比如我们现在要爬取豆瓣上的书籍内容,所以,比方说我们现在要爬取的网站 url 是:/var/page=1/view/page=1这样的 url 我们该怎么处理呢?

我们对这些 url 做优先级划分,比方说 用 var 开头的,我们就放在列表前面、以 view 开头我们就放在列表的后面。优先爬取与我们 var 相关的。——这就是我们所说的优先级

我们都会对 url 进行分析的。


10. 反爬虫案例

1567654495615


PS:Ajax 交互:在我们访问一个网站的时候,页面在不断的刷新,而我们的 url 没有变化。(就像百度图片这样的就是 Ajax 交互。)

10.1 Referer

referer:防盗链,作用就是你次的这次请求是从哪里来的。

我们一一来看一看:

Headers 检测

下面的 iter_content(512) 小块读取(第一篇就是大揽,之后都会讲到)

1567654920141

import requests
url = 'http://img3.laibafile.cn/p/m/310277586.jpg'
headers = {
    'Referer': 'http://bbs.tianya.cn/pic-no04-2829676.shtml'
#我上一次请求在哪里(或者说,我发起下载这个图片的请求是从哪个地方发起的。
}
img = requests.get(url, headers = headers)
with open('refer.jpg', 'wb') as f:
    f.write(img.content)

1567655600678

import requests
url = 'http://img3.laibafile.cn/p/m/310277586.jpg'
# headers = {
#   'Referer': 'http://bbs.tianya.cn/pic-no04-2829676.shtml'
#我上一次请求在哪里(或者说,我发起下载这个图片的请求是从哪个地方发起的。
#
# }
# img = requests.get(url, headers = headers)
img = requests.get(url)
with open('refer.jpg', 'wb') as f:
    f.write(img.content)

1567655669677


10.2 用户访问频率限制(这个刚刚开始只需要了解即可-涉及异步)

1567738874708

以上代码是异步爬虫,然后上面的图片就是为了加快速度让豆瓣封我 IP 代码实现都不用疑惑,之后都会讲到滴。爬取到了许多资源。

如何,防止被封 IP 第一个使用: IP,第二个就是:降低爬虫速度。

10.3 用户延迟访问插件

该插件详细解析:还没用异步,爬取就速度太快?更智能的延迟插件

1567740076280

有基础的你,有可能会有疑惑。为什么不使用 time.sleep(sum) 我可以明确告诉你,可以使用。但是,会造成时间浪费。

10.4 Ajax 交互

举个例子就是百度图片,这个你直接 Get 是请求不到的,之后会有找 Json 接口、API 构造一些参数来

1567741212328

10.5 网页数据加密

1567742232842

10.6 验证码

1567742321436

1567742360563

10.7 字体反爬虫

1567742415017

字体反爬虫最近也是比较流行的。往期教程有讲到实习僧的网站的抓取。

10.8 用户延迟访问插件使用演示

1567742705455

from urllib import parse
from datetime import datetime
import time,requests
class DelayWait:
    def __init__(self, delay = 3):
        # delay = 3 ,每次延迟 3 秒;
        self.delay = delay
        self.urls = dict()
    def wait(self, url):
        netloc = parse.urlparse(url).netloc
        # print(netloc)
        lastOne = self.urls.get(netloc)
        # print(lastOne)

        if lastOne and self.delay>0:
            timeWait = self.delay - (datetime.now()-lastOne).seconds
            if timeWait>0:
                time.sleep(timeWait)

        self.urls[netloc] = datetime.now()

urls = ['http://www.baidu.com']*10
d = DelayWait()
for url in urls:
    html = requests.get(url)
    d.wait(url)
    print(html.status_code)

同学理解:

from urllib import parse
from datetime import datetime
import time,requests
class DelayRequests:
    def __init__(self,delay=3): #定义延迟类
        self.delay=delay#类的属性,类的延迟等于3
        self.urls=dict()#链接
    def wait(self,url):#定义类的方法:延迟方法
        netloc=parse.urlparse(url).netloc
        #print(netloc)  输出域名,netloc是域名的意思 ,这里不是很确定
        lastOne=self.urls.get(netloc)
        #print(lastOne),获取最后一个域名对应的链接
        if self.delay>0 and lastOne:#延时设置
            sleepTime=self.delay-\
                        (datetime.now()-lastOne).seconds#3与两个链接分钟差值进行运算,其中'-\'不理解,李老师说的难度可能在这
            if sleepTime>0:
                time .sleep(sleepTime)#修改sleep时间,避免课程中说的时间浪费
        self.urls[netloc]=datetime.now()#得到当前时间即上一延迟的后的链接,从而把它当初下一延迟的初始链接
urls=['https://blog.csdn.net/']*10#运用
d=DelayRequests()#实例化
for url in urls:
    html=requests.get(url)
    d.wait(url)#链接延时
    print(html.status_code)

PS:这么理解即可

from urllib import parse # 解析 URL
from datetime import datetime  # 获取时间(标注时间)时间加减
import time,requests # time 实现睡眠 # requests  爬虫库

# 一般插件的功能是很专一的,当个文件只实现一个功能
class DelayWait:
    # 内置函数初始化: __init__
    # 一般来说,在我们实行这个类的的时候,就会自动执行这个类的初始化函数(它是第一个执行的)
    def __init__(self, delay = 3):
        # 初始化参数(初始化属性,属性:对象的某个静态特征)
        # delay = 3 ,每次延迟 3 秒;
        self.delay = delay # 延迟时间
        self.urls = dict() # 存储各种 URL

    # 函数:对象的某个动态能力
    def wait(self, url):
        # 解析我们的 URL,来对比每次访问的主站,是否是同一个主站,同一个就是使用该延迟插件,不是就不用啦!
        # 因为,我们封 IP 其实就是,快速重复访问同一个网站,才有可能被封
        netloc = parse.urlparse(url).netloc

        # 我们上一步请求的网址是什么,看有没有这个主站。
        # 这里的 get('', null) 是字典的一个方法,使用get来查询字典中的数据,如果这个数据存在,则返回改键对应的值。
        # 不存在则返回:预先设定的内容:null
        lastOne = self.urls.get(netloc)

        # 如果,我们上一次请求过的话,就执行这个语句
        if lastOne and self.delay>0:
            # 本次访问和上一次访问的时间差.
            timeWait = self.delay - (datetime.now()-lastOne).seconds
            # seconds 转换为秒
            # 解析:
            #   如果两次请求的时间差(datetime.now()-lastOne)非常小,表明,两次请求的时间间隔,非常小.
            #   所以,以每次请求 delay 所设定的时间为标准.如果得出来的差为 3s(举例)那就不执行延迟,
            #   如果差小于 3s 则执行与 3s 相差的时间的差.
            if timeWait>0:
                time.sleep(timeWait)

        # 为字典 urls 添加:键对值:主站:对应添加的时间
        self.urls[netloc] = datetime.now()

urls = ['http://www.baidu.com']*10
d = DelayWait()
for url in urls:
    html = requests.get(url)
    d.wait(url)
    print(html.status_code)

1567755263323

AI悦创·创造不同!
AI悦创 » 01-什么是网络爬虫

Leave a Reply