前言
一直以来,对爬虫技术都十分向往,虽然是学Java出身,但是很少有编码的机会,因为热爱,想认真学习一下这方面的技术,故用此系列文章来记录自己的学习过程。一方面是提升自己的学习效果,另一方面希望能对同样想学习爬虫技术的同学能提供一些小小的帮助。
一、HTTP基础知识
(一)关于URL
URL的全称为 Universal Resource Locator,即统一资源定位符,也就是我们常说的网址。
URL由三部分组成:资源类型、存放资源的主机域名、资源文件名,也可认为由4部分组成:协议、主机、端口、路径。
URL的一般语法格式为:(带方括号[]的为可选项):
protocol:// hostname[:port] / path / [;parameters][?query]#fragment,例如:https://www.baidu.com/index.php
(二)关于URI
URI的全称是统一资源标识符(Uniform Resource Identifier),是一个用于标识某一互联网资源名称的字符串。
该种标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。URI由包括确定语法和相关协议的方案所定义。Web上可用的每种资源 -HTML文档、图像、视频片段、程序等 - 由一个通用资源标识符(Uniform Resource Identifier, 简称"URI")进行定位。
URI的语法格式:[协议名] : //[用户名]:[密码]@[服务器地址]:[服务器端口号]/[路径]?[查询字符串]#[片段ID]
URL 是 URI 的子集,也就是说每个 URL 都是 URI,但不是每个 URI 都是 URL。URI 还包括一个子类叫作 URN,它的全称为 Universal Resource Name,即统一资源名称。 URN当前的使用很少,我们暂可以理解为一般的网址都是URL。
(三)关于HTML
HTML称为超文本标记语言,是一种标识性的语言。它包括一系列标签,通过这些标签可以将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接等。当我们浏览一个网页时,按“F12”或者右键检查元素时,看到的网页源码就是HTML,如图所示。
(四)HTTP和HTTPS的区别
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。
可以理解为HTTPS是HTTP的安全版,不过安全性不是绝对的,且使用HTTPS会稍微影响传输效率,不过HTTPS依然是当前各大应用的趋势。
(五)HTTP请求过程
作为基础知识,学习爬虫的同学一定要熟悉HTTP的整个请求过程,以在浏览器输入某个网址为例,说明一下之后发生了哪些事情。
(1)对网址进行DNS域名解析,得到对应的IP地址;
(2)根据这个IP,找到对应的服务器,发起TCP的”三次握手“;
(3)建立TCP连接后,浏览器向服务器发起HTTP请求命令和请求头信息;
(4)服务器响应HTTP请求,服务器进行应答,并发送应答头信息和html代码信息;
(5)浏览器解析html代码,并继续请求 html 代码中的资源信息(如js、css、图片等);
(6)浏览器对页面进行渲染,最后将渲染结果呈现给用户;
(7)服务器关闭关闭TCP连接。
这中间涉及了很多知识,比如:域名是如何解析的?什么是”三次握手“?页面是怎么渲染的?TCP的相关知识。
这里用两种方式简单说明一下什么是 “三次握手”:
标准解释:
所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:
(1)首先客户端向服务器端发送一段TCP报文,其中:
标记位为SYN,表示“请求建立新连接”; 序号为Seq=X(X一般为1); 随后客户端进入SYN-SENT阶段。(2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据); 序号为Seq=y; 确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值; 随后服务器端进入SYN-RCVD阶段。(3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-
SENT阶段。并返回最后一段TCP报文。其中: 标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了); 序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值; 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值; 随后客户端进入ESTABLISHED阶段。服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。
在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。
此后客户端和服务器端进行正常的数据传输。这就是“三次握手”的过程。
通俗理解:
人们常用男女交往来举例说明“三次握手”,方便理解:
第一次:男方发消息告白女方:我喜欢你;
第二次:女方回复男方:我也喜欢你;
第三次:男方回复女方:我知道你喜欢我了,那我们交往吧。
之后的交往过程就是后面的数据传输了。
(六)浏览器中“F12”的相关知识
不管是学习爬虫还是前后端开发,学会使用浏览器的开发者模式是必不可少的,这个知识往往被一些入门者给忽视了,这里我详细说明一下,这在后面的学习过程中很重要。
首先,不管什么浏览器,通过 F12 或者 右键中的 检查元素 都可以进入开发者页面。点击 Network 或者 “网络” 查看页面请求情况,火狐浏览器打开效果如下:
不同浏览器打开的效果都不一样,这里简单说一下各列的含义,各位可以对照自己的页面进行验证,以上图为例:
当我们点击某一个请求时,会看到更详细的信息,如下图所示:
简单说明一下,右边部分从上到下分别是:
(七)内容补充
(一)常见请求方法
(二)响应状态码对照表
(三)Content-Type 和 POST 提交数据方式的关系
二、网页基础知识
(一)网页的组成
我们常见的网页主要由三大部分组成:HTML、CSS 和 JavaScript,一个简化的网页内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试页面</title>
<!-- 引入css文件 -->
<link rel="stylesheet" href="https://blog.csdn.net/m0_46422300/article/details/style.css">
</head>
<body>
<div class="container">
<div class="split left">
<h1>Hello Word</h1>
<a href="https://blog.csdn.net/m0_46422300/article/details/106079843#" class="button">Read More</a>
</div>
</div>
<!-- 引入js文件 -->
<script src="https://blog.csdn.net/m0_46422300/article/details/main.js"></script>
</body>
</html>
(二)HTML
我们在网页中看到的文字、图片、视频、按钮等元素都是通过HTML中不同的标签来实现的,比如是:< p >标签、< img >标签、< video >标签、< div >标签、< a >标签等。那些复杂的结构是通过不同的标签相互嵌套排列来实现的。这些标签是整个网站的框架。百度首页的源代码效果如下图所示,HTML即为下方左边的部分:
(三)CSS
HTML的内容决定了网页的架构,但是只有架构的网页看起来十分简陋且不美观,为了让网页看起来更好看,我们就会用到CSS。CSS,全称叫作 Cascading Style Sheets,即层叠样式表。上图下方中间和后面的内容就是CSS。
在学习CSS时我们需要知道,CCS是如何来定位生效节点的。
(1)节点的 id 为 logo,可以通过 #logo 来定位标签;
(2)节点的 class name ,可以通过 .name 来定位标签;
(3)节点类型为 p 标签,可直接通过 p 来定位标签。
同时,CSS 选择器还支持嵌套选择,各个选择器之间加上空格分隔开便可以代表嵌套关系,如 #logo.name p 则代表先选择 id 为 logo 的节点,然后选中其内部的 class 为 name的节点,然后再进一步选中其内部的 p 节点。这就是 CSS 选择器,其筛选功能十分强大的。
以上只是最基础的功能,还有其他更复杂的选择器功能值得大家去了解。
(四)JavaScript
单纯的HTML+CSS只会呈现一个好看的静态页面,为了让页面动起来或者与页面产生交互,这时候就需要JavaScript。
JavaScript,简称 JS,是一种脚本语言。它的出现使得用户与信息之间不只是一种浏览与显示的关系,而是实现了一种实时、动态、交互的页面功能。
综上所述,HTML 定义了网页的内容和结构,CSS 描述了网页的布局,JavaScript 定义了网页的行为。
(五)如何完成页面解析
在 HTML 中,所有标签定义的内容我们都把它当作一个节点,这些节点构成了一个 HTML DOM 树。
通过 HTML DOM ,我们可以使用JavaScript 对各个节点进行访问,修改,创建和删除。为了方便编辑,对这个树形结构做了详细的层级定义,用来描述节点之间的关系。
三、Session 与 Cookies
首先,了解 Session 与 Cookies 之前,大家需要了解 HTTP 的无状态,也就是 HTTP 协议对事务处理是没有记忆能力的。也就是说客户端和服务器端的交互是单次的,第二次交互不会与第一次交互结果产生关联。举个例子:无状态情况下,你第一次登陆成功一个网站,这是刷新页面,又会被要求重新登陆,因为服务器不知道你已经登录过了。
为了解决这一问题,这种用于保持 HTTP 连接状态的技术就出现了,它们分别是 Session 和 Cookies。
Session 在服务端,也就是网站的服务器,用来保存用户的 Session 信息。
Cookies 在客户端,也可以理解为浏览器端,有了 Cookies,浏览器在下次访问网页时会自动附带上它发送给服务器,服务器通过识别 Cookies 并鉴定出是哪个用户,然后再判断用户是否是登录状态,进而返回对应的响应。
在爬虫中,有的页面需要登录才能访问时,我们一般会直接将登录成功后获取的 Cookies 放在请求头里面直接请求,而不必重新模拟登录。
Session 知识点
Session ,简称为会话,是一段有始有终的动作或消息。就和打电话一样,从开始拨号到挂断电话,这是一个完整的过程,像这样的一个过程我们可以称之为一个 Session 。
Session 对象中储存着用户的信息,当用户请求在页面间跳转时,存储在Session 中的信息不会消失,会被用于下一个被请求的页面,或者在缓存中等待被使用。用户第一次请求时,服务其中没有该用户的 Session ,服务器会自动创建一个 Session 对象。Session 不会自己消失,只有在过期或者被放弃后,才会被服务器终止。
Session 与 Cookies 对接的过程:
客户端第一次请求时,服务器会返回一个响应头中带有 Set-Cookie 字段的响应给客户端,用来标记是哪一个用户,客户端浏览器会把 Cookies 保存起来。当浏览器下一次再请求该网站时,浏览器会把此 Cookies 放到请求头一起提交给服务器,Cookies 携带了 Session ID 信息,服务器检查该 Cookies 即可找到对应的 Session 是什么,然后再判断 Session 来以此来辨认用户状态。
在成功登录某个网站时,服务器会告诉客户端设置哪些 Cookies 信息,在后续访问页面时客户端会把 Cookies 发送给服务器,服务器再找到对应的 Session 加以判断。如果 Session 中的某些设置登录状态的变量是有效的,那就证明用户处于登录状态,此时返回登录之后才可以查看的网页内容,浏览器再进行解析便可以看到了。
反之,如果传给服务器的 Cookies 是无效的,或者 Session 已经过期了,我们将不能继续访问页面,此时可能会收到错误的响应或者跳转到登录页面重新登录。
所以,Cookies 和 Session 需要配合,一个处于客户端,一个处于服务端,二者共同协作,就实现了登录 Session 控制。
Cookies 知识点
Cookies 是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
会话 Cookie :就是把Cookie 放在浏览器内存里,浏览器在关闭之后该 Cookie 即失效;
持久 Cookie: 就是把Cookie保存到客户端的硬盘中,下次还可以继续使用,用于长久保持用户登录状态。
其实严格来说,没有会话 Cookie 和持久 Cookie 之 分,只是由 Cookie 的 Max Age 或 Expires 字段决定了过期的时间。因此,一些持久化登录的网站其实就是把 Cookie 的有效时间和 Session 有效期设置得比较长,下次我们再访问页面时仍然携带之前的 Cookie,就可以直接保持登录状态。
这里有一个知识点需要理解: 当我们关闭浏览器与服务器端断开连接时,并不意味着服务器端的 Session 消失了。因为你关闭客户端的操作,服务器端是不知道的。如果你的 Cookie 没有被浏览器保存到硬盘上,那么你下次登录的时候不能凭借之前的Cookie 找到对应的 Session ,所以网站会要求你重新登陆。如果Cookie 保存到了硬盘上,那么下次访问带上这个Cookie 去访问就可以找到原来的 Session ,保持登录状态了。
所以为 Session 设置一个过期时间就十分重要了,超过这个时间就终止这个 Session 的活动,这样可以节省服务器资源。
通过下图看看 Cookies 中包含了那些信息,因为涉及个人账户信息所以部分内容码了一下:
可以看到,这个请求的 Cookies 大致包含了这些内容:页面用户信息,本次访问的相关的网页信息,Cookies 本身相关的一些信息。 当前不同的浏览器看到的信息内容结构是不一样的,不过主要内容是差不多的。
四、多线程
爬虫在使用的过程中,不可避免的会用到多线程技术,这里会用 Python 中的技术来进行演示,讲解多线程的知识和使用场景。
首先简单了解一下什么是 “多进程、多线程” :我们在打开一台计算机时,可以同时运行多个程序,这就是多进程。有的程序工作量比较大,会使用多个线程来处理,这就是多线程。进程就是由一个或多个线程构成的,线程是操作系统进行运算调度的最小单位,是进程中的一个最小运行单元。
举例来说,当你打开一个浏览器,就是在运行一个浏览器的进程,你使用这个浏览器打开多个标签页进行浏览就是靠多个线程在运行。
并发
并发(concurrency),指单个处理器上同一时刻只能有一条指令执行,但是多个线程的对应的指令被快速轮换地执行。
并行
并行(parallel),指同一时刻,有多条指令在多个处理器上同时执行,并行必须要依赖于多个处理器。
处理器运行机制:就单个处理器来说,在某个时间点只能运行一个处理命令,然后快速切换其他处理命令,因为这个运算和切换过程十分迅速,所以用户在使用时根本感受不到停顿,给人处理器在同时处理多个任务的感觉。
多线程适用场景
在命令执行过程中,有的命令有一定的相应时间,需要等待一段时间才能进行下一步操作,这时候就可以使用多线程来利用这个等待的时间,增加命令的执行效率。
命令的执行场景根据类型主要分为:
1)IO 密集型任务,需要等待服务器响应,适合用多线程;
2)计算密集型任务,需要处理器一直运行,不适合用多线程。
使用多线程需要注意的问题
1)管理线程的关闭顺序问题;
2)守护线程的使用场景;
3)互斥锁的使用场景。
五、多进程
由于Python 进程中 GIL 的存在,Python 中的多线程并不能很好地发挥多核优势,一个进程中的多个线程,在同一时刻只能有一个线程运行。而对于多进程来说,每个进程都有属于自己的 GIL,所以,在多核处理器下,多进程的运行是不会受 GIL 的影响的。因此,多进程可以更好地发挥多核的优势。
多进程的使用要点较多,准备单独开一文进行阐述,包括多线程的一些场景使用。这里先罗列一下多进程中会遇到的问题:
(1)如何创建进程;
(2)如何使用守护进程;
(3)进程的等待和终止;
(4)进程互斥锁的使用;
(5)进程中信号量的问题;
(6)队列;
(7)管道;
(8)进程池。
六、爬虫的基本流程
首先,什么是爬虫?其实爬虫就是获取网页并提取和保存信息的自动化程序。
(一)获取网页
本次学习主要是使用python语言,python中提供了很多库来帮助我们获取页面信息,如:requests、urllib等。通过这些库我们获取到的是未经处理的页面信息,我们需要按照自己的需求进行结构解析,获取自己想要的部分。
(二)提取信息
因为页面结构的规则性,我们可以通过一些库快速的提取页面信息,如节点信息,文本内容,一些数值等。这个过程需要一定的分析能力,需要从复杂的页面结构中,获取到有价值的信息,且能使用效率最高的方式来实现。
(三)保存信息
我们从页面获取到的大量数据,我们可以按照用多种形式来保存。如:可以保存为txt文本、json文本或者存储到数据库中。甚至可以直接存储到远端的服务器中。
(四)自动化运行
爬取任务往往是复杂的、大量的,我们需要编写一些自动化脚本或者通过一些自动化工具来实现抓取过程的自动化、异常处理、错误重试等问题。
(五)其他问题
现在网站的前端框架越来越多样,很多网站的内容都是经过JavaScript 渲染出来的,我们直接读取原页面的代码往往是什么都没有的,这时候,我们可以通过 Selenium、Splash 这样的库来实现模拟 JavaScript 渲染。
七、简单爬虫实战
这里我简单做了一个读取CSDN网站某篇文章阅读量的小爬虫,十分简单,可以先了解一下,如果有什么不对的地方,欢迎指正。
import re
import requests
def main():
url="https://blog.csdn.net/m0_46422300/article/details/105756002"
read_num = link_crwael(url)
print('此文章阅读量:' + read_num)
def get_span(html):
web_regex=re.compile(r"<span class=\"read-count\">[0-9]*</span>")
return web_regex.findall(html)
def get_num(list):
num_regex=re.compile(r"[0-9]+")
s=""
for i in list:
s+=str(i)
return num_regex.findall(s)
def link_crwael(start_url):
html = download(start_url)
temp = get_num(get_span(html))
read_num = str(temp[0])
return read_num
def download(url):
print(f"访问的链接是:{url}")
resp=requests.get(url)
if resp.status_code==200:
return resp.text
if __name__ == '__main__':
main()
执行结果:
访问的链接是 : https://blog.csdn.net/m0_46422300/article/details/105756002
此文章阅读量:842
八、下期预告
下一篇文章,准备编写一些python爬虫常用库的使用方式,并进行项目实战,尽情期待。