一、URL 基础
URL也就是网络资源地址,其满足如下格式规范
scheme://[username:password@]hostname[:port][/path][;parameters][?query][#fragment]
- scheme:协议,常用的协议有 Http,https,ftp等等;
- username,password:在某些情况下 URL 需要提供用户名和密码才能访问;
- hostname:主机地址,可以是域名或者是 IP 地址;
- port:端口,这是服务器设定的端口;
- path:路径,指的是网络资源在服务器中的指定地址;
- query:用来查询某类资源,如果有多个查询使用 & 隔开;
- fragment:对资源描述的部分补充,可以理解为内部的书签,有两个主要的运用,一个是做单页面路由如 Vue,另一个用作 Html 锚点,控制页面滚动到固定位置;
HTTPS 与 HTTP 不同的是 HTTPS 的安全基础是 SSL,SSL 的主要作用有以下两种:
- 建立一个信息安全通道,保证数据传输的安全性;
- 确认网站的真实性,使用了 HTTPS 协议的网站,可以通过点击浏览器地址栏的锁头标志来查看网站认证之后的真实信息,还可以通过 CA 机构颁发的安全签章来查询;
二、请求
请求分为三个部分:请求方法,请求头,请求体;
请求方法:用于表示请求客户端请求服务端的方式,常见的请求方法有两种:GET 和 POST;
- GET 请求中的参数包含在 URL 里面,数据可以在 URL 中看到;而 POST 请求的 URL 不会包含这些数据,数据都是通过表单形式传输的,会包含在请求体中;
- GET 请求提交的数据最多只有 1024 字节,而 POST 请求则没有限制;
除了 GET 和 POST 请求方式,还有以下请求方式;
序号 | 方法 | 描述 |
---|---|---|
1 | GET | 从服务器获取资源。用于请求数据而不对数据进行更改。例如,从服务器获取网页、图片等。 |
2 | POST | 向服务器发送数据以创建新资源。常用于提交表单数据或上传文件。发送的数据包含在请求体中。 |
3 | PUT | 向服务器发送数据以更新现有资源。如果资源不存在,则创建新的资源。与 POST 不同,PUT 通常是幂等的,即多次执行相同的 PUT 请求不会产生不同的结果。 |
4 | DELETE | 从服务器删除指定的资源。请求中包含要删除的资源标识符。 |
5 | PATCH | 对资源进行部分修改。与 PUT 类似,但 PATCH 只更改部分数据而不是替换整个资源。 |
6 | HEAD | 类似于 GET,但服务器只返回响应的头部,不返回实际数据。用于检查资源的元数据(例如,检查资源是否存在,查看响应的头部信息)。 |
7 | OPTIONS | 返回服务器支持的 HTTP 方法。用于检查服务器支持哪些请求方法,通常用于跨域资源共享(CORS)的预检请求。 |
8 | TRACE | 回显服务器收到的请求,主要用于诊断。客户端可以查看请求在服务器中的处理路径。 |
9 | CONNECT | 建立一个到服务器的隧道,通常用于 HTTPS 连接。客户端可以通过该隧道发送加密的数据。 |
请求头:用来说明服务器要使用的附加信息,比较重要的信息有 Cookie,Referer,User-Agent 等;
- Accept:请求报头域,用于指定客户端可接受哪些类型的信息;
- Accept-Language:用于指定客户端可接受的语言类型;
- Accept-Encoding:用于指定客户端可接受的内容编码;
- Host:用于指定请求资源主机 IP 和端口号,其内容为请求 URL 的原始服务器或网关的位置,请求必须包含此内容;
- Cookie:这是网站为了辨别用户,进行会话跟踪而存储在用户本地的数据,主要功能是维持当前访问会话;
- Referer:用于表示请求是从哪个页面发过来的,服务器可以拿到这一信息并做相应的处理,如来源统计、防盗链处理等等;
- User-Agent:添加此信息可以伪装成浏览器,如果不加很容易被识别出来;
- Content-Type:用来表示具体请求中的媒体类型信息;
请求体:一般承载的内容是 POST 请求中的表单数据,对于 GET 请求,请求体为空
Content-Type | POST 提交数据的方式 |
---|---|
application/x-www-form-urlencoded | 表单数据 |
multipart/form-data | 表单文件上传 |
application/json | 序列化 JSON 数据 |
text/xml | XML 数据 |
在构造 POST 请求中需要使用正确的 Content-Type,并了解设置各种请求库的各个参数时使用的都是哪种 Content-Type,如若不然可能会导致 POST 提交后无法得到正常响应
三、响应
响应是由服务端发送给客户端,可以分为三部分:响应状态码,响应头和响应体;
响应状态码:表示服务器的响应状态,如下所示:
状态码 | 状态码英文名称 | 中文描述 |
---|---|---|
100 | Continue | 继续。客户端应继续其请求 |
101 | Switching Protocols | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | OK | 请求成功。一般用于GET与POST请求 |
201 | Created | 已创建。成功请求并创建了新的资源 |
202 | Accepted | 已接受。已经接受请求,但未处理完成 |
203 | Non-Authoritative Information | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | No Content | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | Reset Content | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | Partial Content | 部分内容。服务器成功处理了部分GET请求 |
300 | Multiple Choices | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | Moved Permanently | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | See Other | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | Not Modified | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | Use Proxy | 使用代理。所请求的资源必须通过代理访问 |
306 | Unused | 已经被废弃的HTTP状态码 |
307 | Temporary Redirect | 临时重定向。与302类似。使用GET请求重定向 |
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
402 | Payment Required | 保留,将来使用 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | Method Not Allowed | 客户端请求中的方法被禁止 |
406 | Not Acceptable | 服务器无法根据客户端请求的内容特性完成请求 |
407 | Proxy Authentication Required | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | Request Time-out | 服务器等待客户端发送的请求时间过长,超时 |
409 | Conflict | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 |
410 | Gone | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | Length Required | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | Precondition Failed | 客户端请求信息的先决条件错误 |
413 | Request Entity Too Large | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | Request-URI Too Large | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | Unsupported Media Type | 服务器无法处理请求附带的媒体格式 |
416 | Requested range not satisfiable | 客户端请求的范围无效 |
417 | Expectation Failed(预期失败) | 服务器无法满足请求头中 Expect 字段指定的预期行为。 |
418 | I’m a teapot | 状态码 418 实际上是一个愚人节玩笑。它在 RFC 2324 中定义,该 RFC 是一个关于超文本咖啡壶控制协议(HTCPCP)的笑话文件。在这个笑话中,418 状态码是作为一个玩笑加入到 HTTP 协议中的。 |
500 | Internal Server Error | 服务器内部错误,无法完成请求 |
501 | Not Implemented | 服务器不支持请求的功能,无法完成请求 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | Service Unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | Gateway Time-out | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | HTTP Version not supported | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
响应头:包含了服务器对请求的应答信息 |
- Data:用于标识响应产生的时间;
- Last-Modified:用于指定资源的最后修改时间;
- Content-Encoding:用于指定响应内容的编码;
- Server:包含服务器的信息,例如名称,版本号等;
- Content-Type:文档类型,指定返回的数据是什么类型,如 text/html 代表返回 HTML 文档,application/x-javascript 代表返回 JavaScript 文件,image/jpeg 代表返回图片;
- Set-Cookie:设置 Cookie,响应头中的 Set-Cookie 用于告诉浏览器需要将此内容放在 Cookie 中,下次请求时将 Cookie 携带上;
- Expires:用于指定响应的过期时间,可以让代理服务器或浏览器将加载的内容更新到缓存中,当再次访问相同的内容时,就可以直接从缓存中加载,达到降低服务器负载,缩短加载时间的目的;
响应体:响应的正文数据都存在于响应体中,例如请求网页时,响应体就是网页的 HTML 代码;请求一张图片,响应体就是图片的二进制数据。做爬虫请求网页的时候,要解析的内容就是响应体;
四、Web 网页
网页基本由三部分组成,HTML,CSS 和 JavaScript;其中 HTML 相当于骨架,JavaScript 相当于肌肉,CSS 相当于皮肤;这三者结合起来才能形成一个完善的网页;
网页由一个个节点组成,CSS 选择器会为不同的节点设置不同的样式规则;CSS 选择器 | 菜鸟教程 (runoob.com)
选择器 | 示例 | 示例说明 |
---|---|---|
.class | .intro | 选择所有class="intro"的元素 |
#id | #firstname | 选择所有id="firstname"的元素 |
* | * | 选择所有元素 |
element | p | 选择所有<p>元素 |
element,element | div,p | 选择所有<div>元素和 <p> 元素 |
element.class | p.hometown | 选择所有 class=“hometown” 的<p> 元素 |
element element | div p | 选择<div>元素内的所有<p>元素 |
element>element | div>p | 选择所有父级是<div> 元素的 <p> 元素 |
element+element | div+p | 选择所有紧跟在 <div> 元素之后的第一个 <p> 元素 |
[attribute] | [target] | 选择所有带有target属性元素 |
[attribute=value] | [target=-blank] | 选择所有使用target="-blank"的元素 |
[attribute~=value] | [title~=flower] | 选择标题属性包含单词"flower"的所有元素 |
[attribute|=language] | [lang|=en] | 选择 lang 属性等于 en,或者以 en- 为开头的所有元素 |
:link | a:link | 选择所有未访问链接 |
:visited | a:visited | 选择所有访问过的链接 |
:active | a:active | 选择活动链接 |
:hover | a:hover | 选择鼠标在链接上面时 |
:focus | input:focus | 选择具有焦点的输入元素 |
:first-letter | p:first-letter | 选择每一个<p>元素的第一个字母 |
:first-line | p:first-line | 选择每一个<p>元素的第一行 |
:first-child | p:first-child | 指定只有当<p>元素是其父级的第一个子级的样式。 |
:before | p:before | 在每个<p>元素之前插入内容 |
:after | p:after | 在每个<p>元素之后插入内容 |
:lang(language) | p:lang(it) | 选择一个lang属性的起始值="it"的所有<p>元素 |
element1~element2 | p~ul | 选择p元素之后的每一个ul元素 |
[attribute^=value] | a[src^=“https”] | 选择每一个src属性的值以"https"开头的元素 |
[attribute$=value] | a[src$=“.pdf”] | 选择每一个src属性的值以".pdf"结尾的元素 |
[attribute*=value] | a[src*=“runoob”] | 选择每一个src属性的值包含子字符串"runoob"的元素 |
p:firs-of-type | p:first-of-type | 选择每个p元素是其父级的第一个p元素 |
:last-of-type | p:last-of-type | 选择每个p元素是其父级的最后一个p元素 |
:only-of-type | p:only-of-type | 选择每个p元素是其父级的唯一p元素 |
:only-child | p:only-child | 选择每个p元素是其父级的唯一子元素 |
:nth-child(n) | p:nth-child(2) | 选择每个p元素是其父级的第二个子元素 |
:nth-last-child(n) | p:nth-last-child(2) | 选择每个p元素的是其父级的第二个子元素,从最后一个子项计数 |
:nth-of-type(n) | p:nth-of-type(2) | 选择每个p元素是其父级的第二个p元素 |
:nth-last-of-type(n) | p:nth-last-of-type(2) | 选择每个p元素的是其父级的第二个p元素,从最后一个子项计数 |
:last-child | p:last-child | 选择每个p元素是其父级的最后一个子级。 |
:root | :root | 选择文档的根元素 |
:empty | p:empty | 选择每个没有任何子级的p元素(包括文本节点) |
:target | #news:target | 选择当前活动的#news元素(包含该锚名称的点击的URL) |
:enabled | input:enabled | 选择每一个已启用的输入元素 |
:disabled | input:disabled | 选择每一个禁用的输入元素 |
:checked | input:checked | 选择每个选中的输入元素 |
:not(selector) | :not§ | 选择每个并非p元素的元素 |
::selection | ::selection | 匹配元素中被用户选中或处于高亮状态的部分 |
:out-of-range | :out-of-range | 匹配值在指定区间之外的input元素 |
:in-range | :in-range | 匹配值在指定区间之内的input元素 |
:read-write | :read-write | 用于匹配可读及可写的元素 |
:read-only | :read-only | 用于匹配设置 “readonly”(只读) 属性的元素 |
:optional | :optional | 用于匹配可选的输入元素 |
:required | :required | 用于匹配设置了 “required” 属性的元素 |
:valid | :valid | 用于匹配输入值为合法的元素 |
:invalid | :invalid | 用于匹配输入值为非法的元素 |
除了 CSS 选择器,还可以使用 XPath 选择器来选择节点;
五、爬虫常见问题
越来越多的网页是采用 Ajax,前端模块化工具构建的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
如采用 Vue 开发的网页中,其 index.html 的 body 中只有一个 id 为 app 的 div 节点和一个 main.js 的 script,其负责整个网页的渲染;
因此当我们请求页面的时候,我们只得到 HTML 代码,而不会渲染 JavaScript 文件,无法看到完整的页面内容;对于这样的情况,我们只有分析源代码后台的 Ajax 接口,或者使用 Selenium 等库来模拟 JavaScript 的渲染;
六、服务器,Session 和 Cookie
将 html 代码文件放在某台具有固定公网 IP 的主机上,在这台主机上安装 Apache 或者 Nginx 等服务器,这台主机就可以作为服务器了;
Session 在服务端,用来保存用户的 Session 信息, Cookie 在客户端,浏览器在访问相同的网页时会自动带上 Cookie,服务器通过识别 Cookie 判断哪个用户访问,然后判断用户是否处于登入状态,并返回对应的响应;
在客户端第一次请求服务器时,服务器会创建一个 Session 并返回一个响应头中与 Session 对应的 Set-Cookie 字段的响应给客户端,客户端接受到响应后会将 Set-Cookie 中的字段保存为 Cookie,当下一次请求同一网站时,Cookie 会随着客户端的请求发送给服务器,服务器通过 Cookie 中的字段找到 Session,通过判断 Session 辨认用户状态并返回对应响应;
关闭浏览器并不会导致 Session 被删除,因此需要服务器为 Session 设置一个失效时间,当距离客户端上一次使用 Session 的时间超过这个失效时间,服务器才可以认为客户端已经停止了活动并删除 Session 以节省空间;
七、代理,多进程和多线程
服务器会检测某个 IP 在单位时间内的请求次数,如果请求次数超过设定的阈值,就直接拒绝提供服务,并返回一些错误信息,这种情况被称为 封IP
代理常用的有 HTTP 代理和 SOCKS 代理,其配置如下
import requests
# http 代理
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'https://proxy.example.com:8080'
}
# socks 代理
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
response = requests.get(url, proxies=proxies)
进程是线程的集合,一个进程是由一个或者多个线程构成的,线程是操作系统进行运算调度的最小单元;
并发是指多个线程对应的多条指令被快速轮换地执行,在宏观上看起来是同时在运行,而微观上是交换执行;并行是指同一时刻由多条指令在多个处理器上同时执行,这意味着并行必须依赖多个处理器,无论是从宏观还是微观,都是同时运行的;
在一个程序的进程中,有一些指令是比较耗时或者需要等待的,如果使用单线程,指令只能等待一个指令完毕后才能执行下一个指令,因此我们可以使用多线程来实现并效果;同理,如果使用多进程我们可以实现并行的效果;
-
在python中,实现多线程主要通过threading模块,而多进程主要通过multiprocessing模块。
-
这两个模块的主要区别是:threading模块基于线程,而multiprocessing模块基于进程。threading模块使用共享内存来实现多线程,所有线程都共享一样的变量(这点在后续的实例中可以感受到);而multiprocessing基于子进程,每个子进程之间都有独立的变量和数据结构。两者的区别意味着threading更使用于I/O密集型任务(例如需要进行多表格读取操作),multiprocessing模块更适用于包含较多计算的CPU密集型任务(矩阵运算,图片处理类任务)。
-
需要注意的是,由于python中的GIL锁的存在,Python解释器只允许一个Python进程使用,这意味着对于一个解释器只允许一个进程在运行,这也是为什么threading模块无法适用于CPU密集型这类需要大量CPU资源的任务,因为一个进程的CPU资源有限,无论开启多少个线程,总的资源就只有那些,总耗时不会有太大变化。而multiprocessing模块则可以开多个进程,能够更快速的处理CPU密集型任务。
代码参考:
【Python】超详细实例讲解python多线程(threading模块)_python的threading模块详解-CSDN博客
Python 爬虫进阶六之多进程的用法 | 静觅 (cuiqingcai.com)