文章目录
- 浏览器抓包
- 浏览器抓包介绍
- 浏览器抓包页面介绍
- python 爬虫
- 爬虫是什么
- web网页渲染的方式
- http 协议
- http协议对资源的操作
- requests 库
- requests 是什么
- requests 的安装
- requests库的基础使用
- requests中不同的请求方式
- GET传递参数
- POST传递参数
- 响应内容
- 定制请求头
- Cookie
- 获取服务器响应的Cookie
- 向服务器发送 Cookie
- 重定向
- 服务器响应超时
- request库的进阶使用
- 请求与响应
- SSL证书验证
- 流式上传和请求
- 代理
- 编码方式
- 身份认证
浏览器抓包
浏览器抓包介绍
抓包:即抓取数据包
,几乎所有的浏览器都提供了抓取数据包的功能,因为浏览器为抓包提供了一个专门的操作页面,因此,这种抓包方式也被称为控制台方式
。
控制台抓包非常适合
POST请求
类型,我们知道POST请求
使用From表单
向服务器提交数据,通过抓包可以获取POST请求体
的数据和相应参数,从而对相应内容进行分析。
浏览器抓包页面介绍
- 打开浏览器,登录任意网站(这里以百度为例),鼠标右键点击,选择
检查
。
- 抓包页面如下:
抓包页面中的各个选项:
- Elements(元素)-----该选项下存放的是该网页的
html代码
。 - console(控制台)-----该选项用于调试一些前端代码,类似python中的IDLE,代码写一行,解释器就立马解释一行。
- 应用-----该选项用来查看和修改
本地存储
,会话存储
,cookie
等 - network(网络)-----该选项是最常用的,该选项下记录了该网页的所有的请求和响应,以及它们各自的数据。我们一般需要在该选项下进行筛选,这样才能找到我们想要的东西。
常用筛选条件如下:
Fetch/XHR
----- 只展示动态数据包文档
----- 只展示该网页的html骨架
(无任何其他资源与数据)css
----- 只展示该网页上的CSS代码
JS
----- 只展示该网页上的JS代码
字体
----- 只展示字体相关的请求和响应img
---- 只展示该网页上的所有图片资源媒体
----- 只展示该网页上的所有媒体文件WS
----- 只展示符合web socket协议
的一个筛选其他
-----展示一些其他的资源
python 爬虫
爬虫是什么
爬虫:是指通过程序代码去获取互联网上的资源。
web网页渲染的方式
一般情况,web网页
会有两种渲染方法:
- 服务器渲染:在服务器那边,直接将
数据
与html页面代码
整合在一起,返回给浏览器-----在浏览器上的页面源代码
中能够找到对应的数据。 - 客户端渲染: 第一次请求服务器,只要一个
html
的骨架,第二次请求才会拿到对应的数据
,然后由客户端(浏览器)将html
和数据
整合在一起,展示出来-----在浏览器上的页面源代码
中找不到对应的数据。
http 协议
http协议
即超文本传输协议,主要是用于传输超文本标记语言(html代码
)。其主要分为请求和响应两个部分,而这两个部分的结构如下;
请求:
- 请求行->请求方式(
get/post等
),请求url地址,协议。 - 请求头->存放服务器要使用的一些附加信息(发出该请求的浏览器是什么类型的浏览器,该浏览器的数据要求是什么,浏览器有没有反扒机制)。
- 请求体->存放一些请求参数。
响应:
- 状态行->协议,状态码(
200,404
等)。 - 响应头->存放客户端要使用的一些附加信息。
- 响应体->存放服务器返回给客户端的真正要用的东西(
html
,json数据
等)。
对于爬虫来说:
请求头里面的重要东西:
User-Agent
: 请求载体的身份标识(该请求是由什么浏览器发出的
)。Referer
:防盗链(这个请求是从哪个页面来的,涉及到反爬
)cookie
:本地的字符串数据信息(用户的账号和密码,反爬的token令牌
)响应头里面的重要东西:
cookie
:本地的字符串数据信息(用户的账号和密码,反爬的token令牌
)- 一些用于反爬的字符串
http协议对资源的操作
- Get:主要用于请求数据。当客户端需要从服务器获取数据时,通常会使用GET方法。
- Post:主要用于提交数据,特别是在创建新的资源或提交表单时。
- Put:用于更新资源。与POST不同,PUT请求通常用于替换整个资源的内容。
- Delete:用于删除资源。
- Patch:用于部分更新资源。与PUT不同,PATCH请求只更新资源的部分属性,而不是整个资源。
requests 库
requests 是什么
requests
是一个用于发送HTTP请求
的Python库,它简化了与Web服务
交互的过程,使开发者能够轻松地构建和解析HTTP请求和响应。
requests 的安装
打开pycharm 终端,输入安装命令:pip install requests
requests库的基础使用
requests中不同的请求方式
requests.get(url)
-----向对应网址(url) 的服务器发出GET请求。requests.post(url,data=posts)
-----向对应网址(url) 的服务器发出POST请求,posts为一个字典时,会自动放在form字段
下面,posts不是字典时,会字段放在data字段
下面。requests.put(url, data=payload)
-----向对应网址(url) 的服务器发出PUT请求。requests.patch(url, data=payload)
-----向对应网址(url) 的服务器发出PATCH请求。requests.delete(url)
-----向对应网址(url) 的服务器发出DELETE请求。requests.head(url)
----- 只会返回响应的头部信息而不包含消息体,这意味着你可以获取关于资源的信息(如状态码、内容类型、最后修改时间等
)而无需下载整个资源。
请求的结构:
GET传递参数
当你想要为url的查询字符串(query string)添加数据时,你可以使用 params
关键字参数来提供这些参数。params
接受一个字典或包含键值对的列表,这些键值对会被编码到url中,跟在问号(?)后面。
import requests#传递单个值#定义要传递的参数
payload = {'key1': 'value1', 'key2': 'value2'}
# 发送GET请求并附带参数
response = requests.get(url=url, params=payload)#最终的url为:网址?key1=value1&key2=value2# 当一个键同时有多个值时# 定义要传递的参数
payload = {'key1':'value1','key2': ['value2', 'value3']}
# 发送GET请求并附带参数
response = requests.get(url=url, params=payload)# 最终url为:网址?key1=value1&key2=value2&key2=value3
注意:如果参数中某个键值对的值为空(None
),这些键不会被添加到最终的url中。
POST传递参数
post 提交的数据一般在请求头的表单(form
)当中。
import requests# 一个键只对应一个值# 定义要传递的参数
payload = {'key1': 'value1', 'key2': 'value2'}
# 发送POST请求并附带参数
response = requests.post(url=url, data=payload)
import requests# 多个相同键的值作为元组列表传递
payload = [('key1', 'value1'), ('key1', 'value2')]
# 发送POST请求并附带参数
response = requests.post(url=url, data=payload)
对于向 API 发送请求,通常一般的API会接受 JSON 编码
的数据。想要传递JSON类型的数据,其方法为使用 json.dumps()
方法将字典转换为 JSON 字符串,并将其传递给 data
参数。
import requests
import json# 定义要发送的POST请求的URL
url = 'http://httpbin.org/post'# 定义要传递的参数
payload = {'key1': 'value1'} #json数据# 发送POST请求并附带参数
response = requests.post(url=url,
data=json.dumps(payload))# 打印服务器响应
print(response.text)
上传文件:只需要定义一个字典,其中键名是表单字段名,值是一个文件对象或包含文件内容的字符串。如果需要,还可以指定文件名、MIME 类型和额外的请求头。
import requestsfilest = {'file': open('D:\\demo.xls', 'rb')}
response = requests.post(url=url, files=filest)
request方法:
requests.request(method,url,**kwargs) #requests.request()为requests库的基础方法,上面右边六种函数就是该方法的封装
#method 对应上面大写的六种方法(get,put,post,patch,delete,head)
#**kwargs 可选参数#params :访问url时携带的参数(用字典表示)#headers :修改http头部的信息 headers=kv ( kv={'user-agent':'Mozilla/5.0'} )#通过修改user-agent来进行爬虫的浏览器伪装,#'Mozilla/5.0'----一般通用浏览器的身份标识#data :修改http主体内容的数据(添加,修改)#files :传输文件 files=fs ( fs={'file':open(文件路径,打开方式)} )
响应内容
import requestsr=requests.get("http://www.baidu.com")
#requests.get(a) :访问目标网站,a为目标网站网址#函数作用:构造一个向服务器请求资源的Request对象,
#返回值为一个包含服务器资源的Response对象(即r,爬虫抓取的结果)print(r.status_code)
#r.status_code :访问的状态码,200为访问成功,404或其他码为访问失败print(r.encoding)
# r.encoding 从http header中相关字段来猜测
#响应内容的编码方式(爬取结果的编码方式)# r.apparent_encoding 从http 的内容中分析出的响应内容
#编码方式(备选编码方式)(比前者更准确)r.encoding="utf-8" #将抓取结果的编码方式改为utf-8print(r.text)
#.text http响应的字符串形式,即目标网址对应的html代码print(r.content)
#爬取结果的二进制形式print(r.headers)
#以 Python 字典形式展示的服务器响应头信息
将响应内容解析成json格式
的数据:
# 将响应内容解析为 JSON 格式,并存储在变量 json_data 中
json_data = response.json()# 打印第一个键值对中的的所有键名
print(json_data[0].keys())
例子:
#百度关键词提交接口:"http://www.baidu.com/s?wd=keyword"
#只需要替换keyword,即可爬取到百度搜索keyword后的结果try:kv={'wd':'海贼王'}r = requests.get("http://www.baidu.com/s",params=kv)r.raise_for_status() #如果状态码不是200,则引发HTTPError异常r.encoding=r.apparent_encodingprint(r.request.url) #获取发给服务器的urlprint(r.url)print(r)except Exception as e:print(e)
定制请求头
import requestsurl = 'https://api.github.com/some/endpoint'# 定制请求头
headers = {'user-agent': '自定义浏览器的身份标识'}
response = requests.get(url, headers=headers)print(response.text)
Cookie
获取服务器响应的Cookie
import requestsurl = 'http://www.baidu.com'response = requests.get(url)# 打印服务器响应的所有cookie
print(response.cookies)# 获取指定cookie的三种写法:# 打印从服务器响应中获取到的名为 'H_PS_PSSID' 的 cookie 的值。
# 如果不存在名为 'H_PS_PSSID' 的 cookie,则会抛出 KeyError 异常。
print(response.cookies['H_PS_PSSID'])# 如果 cookie 不存在,它将返回 None 或者指定的默认值,而不会抛出异常
print(response.cookies.get('H_PS_PSSID'))# 如果 cookie 不存在,返回指定的值
print(response.cookies.get('cookie名字', 'cookie不存在,返回的值'))
注意:不同的网站,不同的
cookie
,名字各不相同,'H_PS_PSSID'
只是百度的cookie名字
向服务器发送 Cookie
import requestsurl = 'http://httpbin.org/cookies'cookies = dict(cookies_are='working')
# cookies = {'cookies 名字': 'cookie的值'}response = requests.get(url=url, cookies=cookies)# 发送的cookie 格式:
#{
#"cookies": {
# "cookies_are": "working"
# }
#}
重定向
默认情况下,除了 HEAD 请求外,requests
会自动处理所有的重定向。可以使用 Response.history
来追踪重定向的历史记录,它是一个按照从最老到最近排序的 Response
对象列表。
GitHub 会将所有 HTTP 请求重定向到 HTTPS:
import requestsurl = 'http://github.com'response = requests.get(url)# 打印url print(response.url)# 打印重定向记录 print(response.history)
打印的结果为:
https://github.com/ [<Response [301]>]
从打印结果可以看到
github
的http
请求被重定向到了https
。
禁用重定向:
import requestsresponse = requests.get(url=url,allow_redirects=False)
启用 HEAD 请求的重定向:
对于 HEAD 请求,默认情况下不会跟随重定向,可以显式地启用它
import requestsurl = 'http://github.com'# 设置 allow_redirects=True,表示启用重定向
response = requests.head(url=url, allow_redirects=True)print(response.url)
print(response.history)
服务器响应超时
为了避免程序因等待响应而无限期挂起,可以使用 timeout
参数指定一个超时时间(以秒为单位)。如果服务器在这个时间内没有响应,requests
将抛出一个 Timeout
异常。
import requestsurl = 'http://github.com'response = requests.get(url=url, timeout=0.001)
request库的进阶使用
请求与响应
任何时候当你调用 requests.get()
或其他类似方法
时,实际上你在执行两个主要操作:构建一个 Request 对象
以向服务器请求或查询资源;以及接收一个从服务器返回的 Response 对象
。这个 Response 对象
包含了来自服务器的所有信息,并且也包含了你最初创建的 Request 对象
。
获取响应头:
import requestsurl = 'http://www.baidu.com'response = requests.get(url)print(response.headers) #打印出响应头
获取发送到服务器的请求头:
import requestsurl = 'http://www.baidu.com'response = requests.get(url)print(response.request.headers) #打印出请求头
SSL证书验证
所谓的SSL证书
,就是来标识服务器身份的,其可以防止钓鱼网站假冒,保护用户数据安全,如果服务器的SSL证书
不被信任,则浏览器会被限制对其的访问(通过https协议来实现),以保护用户数据安全。Requests
可以为 HTTPS 请求
验证 SSL 证书
,就像 web 浏览器
一样。SSL 验证默认是开启的,如果证书验证失败,Requests
会抛出 SSLError
。
在某些特殊情况下,比如你信任但服务器证书不受信任的情况下,你可能想要忽略 SSL 证书验证,以保证对其的访问。
import requests
from urllib3.exceptions import InsecureRequestWarningurl = 'https://example.com'# 禁用不安全请求警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)# 忽略 SSL 证书验证
response = requests.get(url, verify=False)
print(response.status_code)
流式上传和请求
- 流式上传:
Requests
支持流式上传,这允许你发送大的数据流或文件而无需先把它们读入内存,直接传,无中间商,要使用流式上传,仅需为你的请求体提供一个类文件对象即可。
with open('massive-body', 'rb') as f:requests.post('http://some.url/streamed', data=f)
data=f
:这里将文件对象f
直接赋值给了data
参数。这意味着requests
将会逐块读取文件内容,并通过 HTTP 请求进行流式传输。这样做的好处是,即使文件非常大,也不会占用过多的内存,因为数据是一部分一部分地发送出去的。
- 流式请求:
流式请求和普通请求的区别:
普通请求
- 一次性读取:当发起一个普通的 GET 或 POST 请求时,requests 会立即将整个响应体下载到内存中。这意味着如果响应体很大,可能会占用大量的内存。
- 简单易用:对于小文件或轻量级的数据交换,这种方式非常方便,因为它不需要额外的配置就可以直接获取完整的响应内容。
流式请求
- 逐块读取:通过设置
参数 stream=True
,你可以告诉requests
不要立即下载整个响应体。相反,它会在需要时逐步从网络流中读取数据。这允许你处理超大文件或长时间运行的数据流,而不会一次性占用大量内存。- 节省资源:流式请求非常适合于处理大型文件、长连接
API 响应
或者实时数据流
,因为你可以一边接收数据一边处理,从而有效管理资源。- 更复杂的逻辑:由于数据是分块到达的,你需要编写额外的代码来处理这些数据块,例如将它们写入文件或进行增量处理。
流式请求迭代器方法
iter_content()
:以字节为单位返回响应内容的迭代器。可以指定chunk_size
参数来控制每次读取的大小。iter_lines()
:以行为单位返回响应内容的迭代器,适用于按行处理的文本响应。
iter_lines() 的使用:
import json
import requests# 发送 GET 请求到指定的 URL,使用 stream=True 以便逐行读取响应内容
response = requests.get('http://httpbin.org/stream/20', stream=True)# 检查响应的编码,如果未设置,则将其设置为 'utf-8'
if response.encoding is None:response.encoding = 'utf-8'# 使用 iter_lines() 方法创建一个可迭代的行生成器
lines = response.iter_lines()# 使用 next() 函数获取并跳过第一行,first_line 存储的是第一行的内容
first_line = next(lines)# 逐行处理剩余的响应内容
for line in lines:# 打印当前行的内容print(json.loads(line)) #读取json的格式的内容
iter_content() 使用:
import requests# 定义要请求的 URL
url = 'https://api.github.com/events'# 发送 GET 请求到指定的 URL,使用 stream=True 以便逐块下载内容
response = requests.get(url=url, stream=True)# 打开一个文件以写入二进制数据,路径为 'D:\\demo.txt'
with open('D:\\demo.txt', 'wb') as fd:# 遍历响应内容,按块读取数据,块大小为 8192 字节for chunk in response.iter_content(chunk_size=8192):# 将读取的块写入文件fd.write(chunk)
代理
当我们频繁地访问某个网站时,又不希望暴露自己的真实ip地址,那么这个时候,我们就可以使用ip代理,即当我们向外发出请求,请求都会经过代理的服务器,再由代理服务器向外发出请求(或者接收外部请求时,由代理服务器接收,再由其转发给我们),这样外部就会将代理服务器的ip地址当成我们的ip地址。
注意:在实际工作中,一般都是
代理服务端
,保证服务器ip地址
不被泄露,爬虫中的代理是类似代理客户端。
- 获取免费代理
- 使用代理配置单个请求
如果需要使用代理,可以通过为任意请求方法提供 proxies
参数来配置单个请求。
import requestsurl = 'http://www.baidu.com'proxies = {"http": "47.119.22.92:8008" #代理服务器的ip地址
}# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)# 从外部看来,所有的爬虫请求就是代理IP发出的print(response.status_code)
3.使用代理池
使用代理池可以提高请求的成功率和匿名性。通过每次发送请求时从多个代理服务器中随机选择一个来发送,可以分散请求源,减少被目标网站封禁的风险。
import randomimport requestsurl = 'http://www.baidu.com'# 使用代理池
proxies_pool = [{'http': '47.122.65.254:8080'},{'http': '8.130.34.44:8800'},{'http': '47.121.183.107:8443'},{'http': '111.1.61.50:3128'},{'http': '47.119.164.33:3128'}
]proxies = random.choice(proxies_pool)# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)print(response.status_code)
- 针对特定主机设置代理
要为某个特定的连接方式或主机设置代理,可以使用 http://指定主机的IP地址
作为键。这种方式将针对指定的主机和连接方式进行匹配
import requestsurl = 'http://www.baidu.com'# 针对特定主机设置代理
proxies = {"http://指定主机的IP地址": "http://代理服务器的IP地址:端口号"
}
# "http://27.0.0.1" 是本机回环地址,代表本机
#"http://127.0.0.1": "http://47.121.183.107:8443"
#如上,指定主机为本机# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)print(response.status_code)
编码方式
当你收到一个 HTTP 响应时,requests
库会猜测响应内容的编码方式,以便在你调用 Response.text
方法时能够正确解码响应内容。以下是 requests
处理编码方式的具体机制。
自动检测编码:
- 优先检查 HTTP 头部:
requests
首先会在HTTP
响应头部查找Content-Type 字段
中的字符集声明。如果存在明确指定的字符集(例如charset=UTF-8
),则使用该字符集进行解码。 - 使用 charade 猜测编码:如果
HTTP 头部
没有明确指定字符集,并且Content-Type
包含text 类型
,则requests
会使用内置的chardet
库(原名为 charade)来推测最可能的编码方式。 - 默认编码:根据
RFC 2616 的规定
,当 Content-Type 是 text 类型
但没有指定字符集时,默认字符集应该是ISO-8859-1
。requests
遵循这一规范并默认采用ISO-8859-1
进行解码。
手动设置编码:
如果你知道正确的编码方式并且希望覆盖 requests
的自动检测结果,可以通过直接设置 Response.encoding
属性来实现。
import requestsurl = 'https://api.github.com/events'response = requests.get(url=url)# 查看推测的文本编码
print("自动推测的编码方式:" + response.encoding)# 手动指定编码为 ISO-8859-1
response.encoding = 'ISO-8859-1'
# 打印编码方式
print("手动指定的编码方式:" + response.encoding)
使用原始字节数据:
如果你不确定编码或者不想依赖于 requests
的自动解码功能,可以直接访问 Response.content
属性以获取未经解码的原始字节数据。然后根据需要自行解码。
import requestsurl = 'https://api.github.com/events'response = requests.get(url=url)# 获取未经解码的原始字节数据,返回的是服务器返回的二进制内容
raw_data = response.content# 使用 UTF-8 编码方式对原始字节数据进行解码,转换为字符串
decoded_text = raw_data.decode('utf-8')
print(decoded_text)
身份认证
HTTP Basic Authentication
是一种简单的认证机制,广泛用于需要认证的 Web 服务
中,客户端只有通过了认证,才能访问对应的受保护的资源,requests
库对这种认证方式提供了直接的支持。
可以通过导入 HTTPBasicAuth
类来使用 HTTP Basic Auth。
import requests
from requests.auth import HTTPBasicAuthurl = 'https://api.github.com/user'
auth = HTTPBasicAuth('用户名', '密码')# 发送带有基本身份认证的 GET 请求
response = requests.get(url=url, auth=auth)print(response.status_code)
简写形式:由于 HTTP Basic Auth
非常常见,requests
提供了一种更为简洁的方式来传递认证信息——直接在 auth
参数中提供一个元组。
import requestsurl = 'https://api.github.com/user'
# 发送带有基本身份认证的 GET 请求
response = requests.get(url=url, auth=('user', 'pass'))print(response.status_code)