第 1 章 Python 爬虫概念与 Web 基础
1.1 爬虫概念
1.1.1 什么是爬虫
爬虫,即网络爬虫,又称网络蜘蛛(Web Spider),是一种按照一定规则,用来自动浏览或抓取万维网数据的程序。可以把爬虫程序看成一个机器人,它的功能就是模拟人的行为去访问各种站点,或者带回一些与站点相关的信息。它可以 24 小时不间断地做一些重复性的工作,还可以自动提取一些数据。
有一点要注意,本章标题虽然写明 Python 爬虫,但并不是只有 Python 才能编写爬虫程序。其他的编程语言也可以用来编写爬虫程序,如 PHP 有 phpspider 爬虫框架,Java 有WebMagic 爬虫框架,C#,DotnetSpider 爬虫框架等。
1.1.2 爬虫使用场景的引入
爬虫到底能干些什么呢?我们通过下面几个场景引入。
场景一:
大部分读者应该都有看网络小说的习惯,而去正版站点看小说一般是需要付费的,所以衍生了很多盗版小说站点。这种盗版小说站点一般通过挂广告的形式来盈利,在浏览器底部会嵌入各种类型的广告,用户单击这些广告会打开其对应的网址,盗版小说站点以此获利。
这些盗版小说站点的广告一般都是误导读者打开它。比如,广告上有个 X 按钮,读者通常以为单击 X 按钮可以关闭这个广告,殊不知是打开了广告,而且有些广告中含有不堪入目的内容。想一想,在拥挤的地铁里,旁边的人看到你打开了这样的网页,会有多尴尬。
有没有办法既能看到小说又不用看这些烦人的广告呢?
答:通过爬虫可以解决这个问题,让爬虫只解析小说部分的内容并显示出来,甚至可以把整本小说的内容解析完,保存到本地,以便离线阅读。
场景二:
有些读者有一种类似于强迫症的行为,比如,快递预计今天会到,每隔一段时间你就会不由自主地输入单号看看快递到了没。有没有办法能摆脱这种频繁而又枯燥的工作呢?
答:对于这种轮询(每隔一段时间查询一次)的任务,我们可以编写一个定时爬虫,
每隔一段时间自动去请求相应的站点,然后处理结果,判断其是否符合我们的预期,与人工刷新相比,爬虫的频率更快、效率更高。
场景三:
有一些站点,会通过签到或以做每日任务的形式来提高用户的活跃度,当坚持到一定天数后会发放一些小奖励。比如,坚持十五天就能获得一个小礼物。因为忙碌或其他原因,你中断了签到,使得之前的努力就都白费了。而且有些每日任务非常枯燥,但每天要为此花上好几分钟。有没有办法把这种任务交给程序来做,然后坐享其成呢?
答:可以把这些任务交给爬虫。对于签到这种操作,通过抓包获取签到所需的接口、参数和请求规则,接着让脚本每天定时执行即可。每日任务一般通过模拟单击的方式完成,
通过 Selenium 自动化框架来模拟。对于 App 签到,则可以通过 Appium 移动端自动化测试框架来完成。
场景四:
如果你有志于从事 Python 开发相关的工作,想了解这个行业的一些情况,比如薪资、年限和相关要求等,而你身边又没有从事相关工作的朋友,怎样才能获取到这些信息呢?
答:可以编写爬虫爬取一些招聘网站,比如拉勾、前程无忧这类站点,把 Python 岗位相关的信息都抓取下来,然后通过数据分析基础三件套(NumPy、pandas、Matplotlib)进行基本的数据分析,以此获取和这个行业相关的一些信息。
1.1.3 爬虫的组成部分
相信在看完爬虫应用的四个场景后,读者对爬虫能做什么有了大致了解,接下来我们来了解爬虫由哪几部分组成。爬虫的三个组成部分如图 1.1 所示。
图 1.1 爬虫的三个组成部分
1.1.4 模拟请求
模拟请求就是如何把我们的爬虫伪装得像一个人一样去访问互联网站点。
-
最简单的站点,什么都不处理,只要发送请求,就会给出相应的结果。
-
稍微复杂一点的站点,会判断请求头中的 User-Agent 是否为浏览器请求,Host 字 段是否为正确的服务器域名,以及 Referer 字段的地址是否合法。
-
再复杂一点的站点,需要登录后才能访问。登录后会持有一个 Cookie 或 Session会话,你需要带着这个东西才能执行一些请求,否则都会跳到登录页。
-
更复杂一点的站点,登录很复杂,需要五花八门的验证码、最简单的数字图片加噪点、滑动验证码、点触验证码。除此之外,还有一些其他特立独行的验证方式,如最经典的微博宫格验证码、极验验证码的行为验证等。
-
还有更复杂的站点,其链接和请求参数都是加密的,需要研究、破解加密规则才能够模拟访问。
-
除此之外,还有一些反爬虫套路,如限制 IP 访问频次、JavaScript 动态加 载数据等。
在模拟请求之前,先要了解请求规则,一般通过抓包工具来完成。
(1)对最简单的浏览器请求(以 Chrome谷歌浏览器为例),在网页空白处右键单击并选择检查,或者依次单击如图 1.2 所示的“更多工具”→“开发者工具”。在 Windows 中打开开发者工具的快捷键 F12。
图 1.2 打开 Chrome 开发者工具
打开后会看到如图 1.3 所示的页面,单击 Network 切换到抓包页面。
图 1.3 单击 Network 切换到抓包页面
刷新页面,可以看到如图 1.4 所示的很多网络请求。单击对应的请求即可查看完整的请求信息。
图 1.4 Network 中抓取到的网络请求
(2)稍微复杂一点的网站或 App 请求抓包,可以通过 Charles、Fidder、Wireshark 等工具来实现,相关内容后面会详细讲解。
1.1.5 数据解析
数据解析是对模拟请求获得的不同类型的信息进行解析。
- 返回的结果是 HTML 或 XML,可利用 Beautiful Soup、Xpath、PyQuery 等模块解析需要的节点数据。
- 返回的是 JSON 字符串或其他字符串,可通过编写正则表达式提取所需信息。
- 返回的是加密后的数据,则需要解密后才能解析。
1.1.6 数据保存
数据保存是对解析后的数据进行保存。如果把采集到的数据放在内存里,一旦关闭程序,数据就丢失了,因此我们需要把爬取到的数据保存到本地。保存的形式有以下几种:
- 保存为文本文件。一些文字类型的信息,如小说内容,可保存成 TXT 文件。
- 保存为图片、音视频等二进制文件。如一些多媒体资源可保存为这种格式。
- 保存到 Excel 表格中。其好处是直观,而且方便不了解编程的读者使用。
- 保存到数据库中。数据库又分为关系型数据库和非关系型数据库。
1.2 HTTP 简述
1.2.1 简述一次网络请求过程
打开浏览器,输入一个网址,然后回车,等待网页加载结束,然后浏览网页。这个过程中都发生了什么事情吗?这里不去介绍 TCP/IP 这些枯燥的概念。在浏览器中输入 http://www.baidu.com 这个域名,然后回车。
- 通过 URL 查找服务器 IP
浏览器先要做的是找出与域名对应的服务器,即把域名解析成对应服务器的 IP 地址。对于 www.baidu.com,浏览器并不认识这个域名,前面的 www 是服务器名,baidu 可以理解为公司名或私人名,最后的 com 则是域名根服务器。浏览器先访问本地 Host 文件,检查文件中是否有与域名匹配的 IP 地址,如果有则直接访问 IP 对应的服务器;否则,向上层的 DNS 服务器询问;如果还没有,则继续向上层DNS 服务器询问,直到 DNS 根服务器。 - 三次握手建立 TCP 连接
获得服务器 IP 后,接下来是和服务器建立连接,这就是常说的 TCP 三次握手。
首先,客户端发送一个带 SYN 标志的数据包给服务器。服务器收到后,回传一个带SYN/ACK 标志的数据包表示信息确认。最后,客户端回传一个带 ACK 标志的数据包,表示握手结束,连接建立成功。
打个比方,你可以把客户端当作一个快递员,而把服务器当作收件人。
快递员(客户端):兄弟,在家吗?有你的快递。
收件人(服务器):嗯,在家,你在下午两点前送过来就行。
快递员(客户端):行,我两点前给你送过去。
这就类似于三次握手建立 TCP 连接。 - 发送 HTTP 请求
客户端和服务器建立连接后就可以开始发送 HTTP 请求了。浏览器发送请求行、请求头信息,还发送一个空行,代表请求头信息发送结束。如果是 Post 提交,还会提交请求体。 - 服务器响应请求
Web 服务器解析用户请求并进行相关处理,最后把处理结果组装成响应报文,返回给客户端。 - 浏览器解析 HTML
浏览器解析服务器返回的 HTML 代码,并请求 HTML 里用到的 CSS、JS、图片等资源。 - 页面渲染后呈现给用户
渲染的顺序是从上到下,下载和渲染是同时进行的,页面加载完成显示在浏览器上。
以上就是用户在浏览器输入一个地址并回车后,直到浏览器经历的大致流程。
1.2.2 URI和URL
URI(Uniform Resource Identifier,统一资源标志符)标记一个网络资源,强调的是给资源命名;URL 用地址标记一个网络资源,强调的是给资源定位。。
比如,你在某个技术网站上认识了一位技术高手,他自称 XXX 公司的技术总监,这个头衔就是 URI,但是只有这个头衔的话,你没有那么容易找到他,你还需要知道他所在公司的地址。深圳市南山区科技园 X 栋 X 楼/XXX 公司/技术总监/X 某,通过上面这串地址你就可以找到这个人。这个完整的地址就是URL。而通过这个 URL 也可以知道 X 某是 XXX公司的技术总监,它既能当作标记使用,又能当作地址使用,所以 URL 是 URI 的子集。
URI 由下面三部分组成:
- 访问资源的命名机制;
- 存放资源的主机名;
- 资源本身的名称,用路径标识,着重强调资源。
URL 由下面三部分组成:
- 协议(或称服务方式);
- 存有该资源的主机 IP 地址(有时也包含端口号);
- 主机资源的具体地址(如目录、文件名等)。
一般习惯性地把我们说的网址称为 URL。
1.2.3 HTTP 请求报文
HTTP(Hyper Text Transfer Protocol,超文本传输协议)是万维网服务器将超文本传输到本地浏览器的传送协议,基于 TCP/IP 通信协议来传递数据。HTTP 是无状态的,以此限制每次连接只处理一个请求。服务器在处理完客户端请求,并接收到客户端的应答后,即断开连接,这种方式的好处是节省传输时间。
当然,如果想保持连接,可以在请求首部字段中添加请求头 Connection: keep-alive,表明使用持久连接,或者通过 Cookie 这类方式间接地保存用户之前的 HTTP 通信状态。HTTP 请求报文由四部分组成,依次是请求行、请求头、空行和请求正文。下面依次对这四部分进行介绍。
-
请求行
它由请求方法、URL 和 HTTP 版本三个字段组成,使用空格进行分隔。比如访问百度,
请求行的内容为 GET/index.php HTTP/1.1。
在上述请求方法中,GET 和 POST 使用得最频繁。GET 请求无消息体,只能携带少量数据(最多只有 1024 字节),并将数据存放在 URL 地址中;而 POST 请求有消息体,可以携带大量数据,并将数据存放在消息体中。
URL 构成示例
-
请求头
它采用键值对的形式,关键字和值用英文冒号(:)进行分隔。
- User-Agent:标识客户端使用的浏览器和操作系统信息。可以通过$_SERVER[‘HTTP_USER_AGENT’]获取。
- Accept:指定客户端能够处理的内容类型,即可接受的媒体类型。可以通过$_SERVER[‘HTTP_ACCEPT’]获取。
- Content-Type:指定请求体中的数据格式类型。常见的取值有application/json、application/x-www-form-urlencoded等。可以通过$_SERVER[‘CONTENT_TYPE’]获取。
- Authorization:用于进行身份验证的凭证信息。常见的取值有Bearer Token、Basic Authentication等。可以通过$_SERVER[‘HTTP_AUTHORIZATION’]获取。
- Cookie:包含来自客户端的Cookie信息。可以通过$_SERVER[‘HTTP_COOKIE’]获取。
- Referer:指示当前请求是从哪个URL页面发起的。可以通过$_SERVER[‘HTTP_REFERER’]获取。
- Host:指定服务器的域名或IP地址。可以通过$_SERVER[‘HTTP_HOST’]获取。
- X-Requested-With:指示请求是否由Ajax发起的。通常在Ajax请求中会设置该头部字段,取值为"XMLHttpRequest"。可以通过$_SERVER[‘HTTP_X_REQUESTED_WITH’]获取。
- Content-Length:指定请求体的长度。可以通过$_SERVER[‘CONTENT_LENGTH’]获取。
- Cache-Control:控制缓存行为的指令。用于指定客户端和代理服务器如何缓存响应。可以通过$_SERVER[‘HTTP_CACHE_CONTROL’]获取。
在实际开发过程中,请求头不限于上面这些内容,可以通过抓包的方式查看所用到的请求头,然后在编写爬虫时添加上。Chrome 浏览器开发者工具下www.baidu.com的请求头如下:
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie:...
- 空行
请求头的最后会有一个空行,表示请求头结束,接下来是请求正文,这个空行必不可少。 - 请求正文
这一般是 POST 请求中提交的表单数据。另外,在请求头 Content-Type 中要使用正确的类型才能正常提交,如表单数据是 application/x-www-form-urlencoded、文件是 multipart/form-data、JSON数据时application/json、XML 数据是 text/xml,在抓包时可以获取。
1.2.4 HTTP 响应报文
HTTP 响应报文由四部分组成,依次是状态行、响应头、空行和响应正文。下面依次对这四部分进行讲解。
- 状态行
它由协议版本、状态码、状态码描述三个字段组成,它们之间使用空格进行分隔。比
如访问百度时,状态行的内容为 HTTP/1.1 200 OK。状态码分为下述五大类。- 1xx:指示信息,表示请求已接收,继续处理。
- 2xx:成功,表示请求已被成功接收、理解。
- 3xx:重定向,表示要完成请求必须进行更进一步的操作。
- 4xx:客户端错误,表示请求有语法错误或请求无法实现。
- 5xx:服务器端错误,表示服务器未能实现合法的请求。
详细的状态码无须记忆,使用时查表即可。
- 100 继续 请求者应继续提出请求。服务器返回此代码表示已收到请求的一部分,正在等待其余部分
- 101 协议切换 请求者已要求服务器切换协议,服务器已确认并准备切换
- 200 成功 服务器已成功处理了请求
- 201 已创建 请求成功,并且服务器创建了新的资源
- 202 已接收 服务器已接收请求,但尚未处理
- 203 非授权信息 服务器已成功处理了请求,但返回的信息可能来自另一来源
- 204 无内容 服务器成功处理了请求,但没有返回任何内容
- 205 重置内容 服务器成功处理了请求,内容被重置
- 206 部分内容 服务器成功处理了部分请求
- 300 多种选择 针对请求,服务器可执行多种操作
- 301 永久移动 请求的网页已永久移动到新位置,永久重定向
- 302 临时移动 请求的网页暂时跳转到其他页面,暂时重定向
- 303 查看其他位置 请求对应的资源存在另一个 URI,应使用 GET 方法定向获取请求的资源
- 304 未修改 此次请求返回的网页未修改,继续使用上次的资源
- 305 使用代理 请求者应使用代理访问请求的网页
- 307 临时重定向 请求的资源临时从其他位置响应
- 400 错误请求 服务器无法解析该请求
- 401 未授权 请求要求身份验证或验证未通过
- 403 禁止访问 服务器拒绝请求
- 404 未找到 服务器找不到请求的网页
- 405 方法禁用 服务器禁用请求中指定的方法
- 406 不接收 无法使用请求的内容特性响应请求的网页
- 407 需要代理授权 请求者需要使用代理授权
- 408 请求超时 服务器等候请求时发生超时
- 409 冲突 服务器在完成请求时发生冲突
- 410 已删除 请求的资源已永久删除
- 411 需要有效长度 服务器不接收不含有效内容长度标头字段的请求
- 412 未满足前提条件 服务器未满足请求者在请求中设置的其中一个前提条件
- 413 请求实体过大 请求实体过大,超出服务器的处理能力
- 414 请求的 URI 过长 请求的 URI(通常为网址)过长,服务器无法处理
- 415 不支持的媒体类型 请求的格式不被请求页面支持
- 416 请求范围不符合要求 页面无法提供请求的范围
- 417 未满足期望值 服务器未满足请求标头字段的要求
- 500 服务器内部错误 服务器遇到错误,无法完成请求
- 501 尚未实施 服务器不具备完成请求的功能
- 502 错误网关 服务器作为网关或代理从上游服务器收到无效响应
- 503 服务不可用 服务器目前无法使用(由于超载或停机维护)
- 504 网关超时 服务器作为网关或代理没有及时从上游服务器收到请求
- 505 HTTP 版本不受支持 服务器不支持请求中所用的 HTTP 版本
- 响应头
它包含了服务器对请求的一些应答信息。
- 空行
响应头的最后会有一个空行,表示响应头结束,接下来是响应正文。这个空行必不
可少。 - 响应正文
Content-Type 指定响应正文的 Mime 类型,比如 text/html 类型响应正文为 HTML 代码,
image/png 类型响应正文为 PNG 图片的二进制数据。
1.3 网页的组成
一般的网络站点都由多个网页组成,而一个网页由 HTML、CSS 和 JavaScript 三部分组成,它们各司其职。
- HTML 决定网页的结构和内容。
- CSS 决定网页的样式。
- JavaScript 控制网页的行为。
如果把网页比作一扇门,HTML 就是门板,CSS 是门上的油漆或花,JavaScript 则是门的开关。
1.3.1 HTML 简介
HTML(Hypertext Markup Languag,超文本标记语言)。我们来拆分这个名词,首先是超文本,文本一般指的是文字和符号,而在 HTML 中则可以是图片、音视频等其他媒体,远远超出了文本的范畴,所以称为超文本。其次是标记,在 HTML 中所有内容都叫作标记,用一个标记来包含一块内容,表示其作用,比如
标签用来标记一个文章段落。
- HTML 标签语法
HTML 标签是符号< >中的指令,分为单标签(<起始标签/>)和双标签(<起始标签></结束标签>),比如<‘br’/>和<‘div’ ></‘div’ >。
双 标 签 可 以 嵌 套 , 但 是 不 能 交 叉 , 比 如 <‘div’><‘p’></‘p’></‘div’> 是 正 确 的 ,<‘div’><‘p’></‘div’></‘p’>则是错误的
双标签中间可以添加标签的内容,比如<‘h1’>一级标题</‘h1’>。
标签还可以通过包含"属性"的方式来设置元素的其他特性,多个属性可以用空格
隔开,比如<‘a href=“http://coderpig.cn/” target=“_blank”’>小猪博客</‘a’>。 - 其他的语法
(1)HTML 使用 进行注释,注释不会在浏览器中显示。
(2)在 HTML 代码中直接输入一些特殊字符是没有效果的,需要用专有的代码标记,
比如空格为 ,更多的特殊字符可到 https://www.jb51.net/onlineread/htmlchar.htm 查看。
一个简单的 HTML 页面示例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>小猪博客</title>
</head>
<body>
<h1>博客介绍</h1>
<p>欢迎来到小猪的博客。</p>
</body>
</html>
可以把代码文件保存为 index.html,用浏览器打开查看效果.
HTML 的规则如上所述,本书并不介绍如何编写 HTML 网页,所以不会对每个标签及相关的属性进行讲解,有兴趣的读者可以访问http://www.w3school.com.cn/html/index.asp 进行学习。
1.3.2 CSS 选择器简介
CSS(Cascading Style Sheets,层叠样式表),层叠可以理解为利用 CSS 的选择器可以对 HTML 的元素堆叠很多样式。CSS 的作用就是为 HTML 元素添加样式,从而使页面更加漂亮。
HTML 通过修改属性就可以实现丰富的页面效果,为什么还要引入CSS?为了解决内容与表现分离的问题,通过修改一个简单的 CSS 文档,即可改变网页中对应的所有元素的布局和外观。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css>
h1 {background-color:#6495ed;}
</style>
<title>小猪博客</title>
</head>
<body>
<h1>博客介绍</h1>
<p>欢迎来到小猪的博客。</p>
</body>
</html>
代码执行结果
插入 CSS 的四种方法如下。
(1)内联样式。只为单个元素指定 CSS 样式,即在 HTML 的标签中添加 style 属性,
直接把样式写进去,比如:
<‘p’ style=“color:#FFFFFF;”>内联样式</‘p’>
(2)内嵌样式。把 CSS 样式写入 HTML 文档,用<‘style’>标签包含进去,放在<‘head’>里,示例如下:
<style type="text/css>
h1 {background-color:#6495ed;}
</style>
(3)用<‘link’>标签引入外部样式表。在 HTML 文档的<‘head’>标签里添加<‘link’>标签,通过 href 属性引用外部 CSS 文件,示例如下:
<head>
<link rel="stylesheet" type="text/css" href="mystyle.css"/>
</head>
(4)用@import 指令引入外部样式表。在<‘style’>标签中间,通过@import 指令引入外部 CSS,示例如下:
<style>
@import url("style.css") screen, print;
</style>
一个 HTML 可以同时使用这四种样式,当四种样式中有相同的属性时,优先级顺序为
内联 > 内嵌 > import > link。
CSS 选择器主要分为下述三大类。
- 标签选择器(文档中所有的某个标签都使用同一个CSS样式),比如:div{ color:red; border:1px; }。
- 类选择器(class=“xxx”,为不同的标签赋予不同的 CSS 样式),比如:.text{ color:red; border:1px; }。
- id 选择器(id=“xxx”,唯一,只可以获取独一无二的元素),比如:#id { color:red; border:1px; }。
这三种选择器可以用不同的方式组合,关于 CSS 具体的属性和值可访问下述站点查阅:
http://www.w3school.com.cn/css/index.asp。
1.3.3 JavaScript 简介
JavaScript 一般简称 JS,是一门脚本语言,用于控制网页的行为,很多人对于 JS 的印象可能还停留在使用 JS 写特效上,比如图片轮播、动画等。JS 现在也用于处理页面的逻辑、前后端的数据交互等,利用 Node.js 还可以让 JS 运行在服务器端上。JS 的语法过于烦琐,可以访问http://www.w3school.com.cn/js/进行学习。
本系列文章皆做为学习使用,勿商用。