21.7 Python 使用Request库
Request库可以用来发送各种HTTP
请求,该框架的特点是简单易用,同时支持同步和异步请求,支持HTTP
协议的各种方法和重定向。它还支持Cookie
、HTTPS
和认证等特性。 Request
库的使用非常广泛,可以用于网络爬虫、API调用、网站测试等场景。
读者如果需要使用这个库,同样需要执行pip命令用以安装:
- 安装PIP包:pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
在开始使用之前,我们需要编写一个简单的生成随机User-Agent
的函数,User-Agent是一个HTTP协议头部,用于标识请求的客户端身份信息,包括客户端的应用软件、操作系统、硬件设备等信息。服务器可以通过User-Agent头部信息来确定客户端的类型,并针对不同类型的客户端提供不同的服务或页面展现效果。
对于爬虫来说我们并不希望固定这个值,而是希望每次调用时都会产生一个新的随机值,以此来实现每次访问固定页面时使用不同的User-Agent
头,并且让Referer
头也保持每次随机化,通过这种方式可以在一定程度上缓解反爬机制,如下则是实现随机请求体的实现代码;
import random
# 随机获取一个请求体
def GetUserAgent(url):
UsrHead = ["Windows; U; Windows NT 6.1; en-us", "Windows NT 5.1; x86_64", "Ubuntu U; NT 18.04; x86_64",
"Windows NT 10.0; WOW64", "X11; Ubuntu i686;", "X11; Centos 8 x86_64;",
"compatible; MSIE 9.0; Windows NT 8.1;",
"X11; SuUSE Linux i686", "Macintosh; U; Intel Mac OS X 10_6_8; en-us",
"compatible; MSIE 7.0; Windows Server 6.1",
"Macintosh; Intel Mac OS X 10.6.8; U; en", "compatible; MSIE 6.0; Windows NT 5.1", "iPad; CPU OS 4_3_3;",
"Windows NT 10.0; WOW64; rv:38.0", "Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C;",
"MSIE 10.0; Windows NT 6.1;",
"iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X;", "iPod; U; CPU iPhone OS 4_3_3 like Mac OS X;",
"Linux; U; Android 6.0;","Linux; U; Android 9.0;","Linux; U; Android 7.1;","Linux; U; Android 10.0;"
"Linux; U; Nexus One Build/FRF91", "BlackBerry; U; BlackBerry 9800;","BlackBerry; U; BlackBerry 7800;"
"hp-tablet; Linux; hpwOS/3.0.0; U; en-US",
"SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019;",
"compatible; MSIE 9.1; Windows Phone OS 7.5; IEMobile/9.0; HTC;"]
UsrFox = ["Chrome/70.0.3100.0", "Auburn Browser/10.05", "Safari/522.13", "Chrome/80.0.1211.0",
"Firefox/74.0 Safari/522.13",
"Gecko/20100101 Firefox/4.0.1", "Presto/2.8.131 Version/11.11", "Mobile/8J2 Safari/6533.18.5",
"Mobile/10 Safari/8536.25",
"Version/4.0 Safari/534.13", "wOSBrowser/233.70 Baidu Browser/534.6 TouchPad/1.0",
"BrowserNG/7.1.18124 Safari/522.13",
"rident/4.0; SE 2.X MetaSr 1.0;", "360SE/80.1 ", "wOSBrowser/233.70", "UCWEB7.0.2.37/28/999",
"Opera/UCWEB7.0.2.37 Safari",
"Chrome/80.0.3987.149 Safari/537.36", "Gecko/20100101 Firefox/74.0",
"Trident/7.0; rv:11.0) like Gecko Safari/522.13"]
UsrAgent = "Mozilla/5.0 (" + str(random.sample(UsrHead, 1)[0]) + ") AppleWebKit/" + str(
round(random.uniform(100, 600), 2)) \
+ " (KHTML, like Gecko) " + str(random.sample(UsrFox, 1)[0])
UsrRefer = str(url + "/" + "id_" + "".join(random.sample("1234567890", 6)) + ".html")
UserAgent = {"User-Agent": UsrAgent, "Referer": UsrRefer}
return UserAgent
if __name__ == "__main__":
ref = GetUserAgent("https://www.lyshark.com")
print("User-Agent: ",ref.get("User-Agent"))
print("Referer: ",ref.get("Referer"))
如下输出效果,我们通过传入一个参数,即可输出一条随机请求头,及一个来源地址,输出效果如下所示;
21.7.1 实现GET请求
HTTP GET请求是一种常见的HTTP请求方法之一,用于向服务器请求特定资源,比如网页、图片、视频等。在HTTP GET请求中,客户端向服务器发送一个带有请求参数的URL,服务器接收到请求后返回请求的资源。
要实现访问一个页面可以调用requests.get()
函数,该函数可用于发送http
以及https
请求,并返回相应结果,该方法的语法如下所示;
requests.get(url, params=None, **kwargs)
其中,url
是要请求的URL
,params
是可选的参数,可以包含查询字符串参数,**kwargs
是任意的关键字参数,它们将被转换为HTTP
请求头。这些参数包括但不限于:
- headers: 字典类型,
HTTP
请求头 - cookies: 字典或
CookieJar
类型,请求中发送的cookie - auth: 元组类型,支持
HTTP
身份验证 - timeout: 超时时间,单位为秒
- allow_redirects: 允许重定向,True或False
- proxies: 字典类型,代理服务器URL
- verify: 是否验证
SSL
证书,True或False
该方法返回一个响应对象,可以使用该对象访问HTTP响应状态码、响应头、响应正文等信息,如下一个案例则是一个简单实现访问特定页面的功能。
import re
import requests
header = {
'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
'referer': 'https://www.baidu.com'
}
if __name__ == "__main__":
ret = requests.get(url="https://www.lyshark.com", headers=header, timeout=5)
print("输出请求头: ", ret.headers)
print("服务器类型: ", ret.headers.get("Server"))
print("服务器时间: ", ret.headers.get("Date"))
# 检查是否访问成功
if ret.status_code == 200:
title = re.findall('<title>(.+)</title>', ret.text)
print("输出标题: ", title)
运行上述代码即可实现访问www.lyshark.com
服务器,并返回该服务器的相关参数信息,如下图所示;
21.7.2 实现POST请求
HTTP POST请求是指客户端向服务器提交数据的请求方式。在POST
请求中,提交的数据会被包含在HTTP
请求体中,并且请求头中会包含Content-Type
字段来指定提交的数据格式。与GET
请求相比,POST
请求更适用于需要向服务器提交大量数据、敏感数据或需要修改服务器状态的场景。
要实现POST请求,读者可调用requests.post
函数,该函数用于向指定的URL
发送HTTP POST
请求。通过POST
请求,客户端可以向服务器传递数据,这些数据存储在请求的正文中。与GET
请求不同,POST
请求不会将数据附加在URL
参数中。下面是requests.post
的语法:
requests.post(url, data=None, json=None, **kwargs)
其中,参数url
是POST
请求的目标URL。参数data
是POST
请求的正文数据,类型为字符串或字节流。参数json
是一个Python
对象,表示要发送的JSON
数据。其他的关键字参数将作为请求头的一部分发送。
import requests
if __name__ == "__main__":
headers = {
"content-type": "application/json",
"Authorization": "",
"Cookie": "",
"Host": ""
}
data = {"username": "lyshark", "tel": "18611184241"}
req = requests.post(url="https://www.lyshark.com/api", headers=headers, data=data)
print("响应结果: ",req)
如上一段代码,通过使用post
函数,并在调用时传入一个data
字典,此时在发送请求时会默认携带该字典传递,运行后如果对端相应了则会返回状态码。
21.7.3 使用HTTP代理
HTTP代理是一个允许用户将其计算机流量通过另一台服务器进行传输的网络服务。通过使用代理服务器,用户可以隐藏其真实IP地址和位置,从而增加其在互联网上的匿名性。HTTP代理通常可以用于访问被阻止的网站、绕过网络过滤器和提高用户隐私。可以通过设置代理服务器地址和端口来在请求中使用HTTP代理。
在requests
库中同样支持增加代理功能,代理的写法有两种分别是有密码与无密码,这两种格式可写为:
- 有密码写法:"https": "https://username:password@ip:port"
- 无密码写法:"http": "http://ip:port"
在使用代理时,我们只需要在调用requests.get
请求时增加一个proxies
字段并指定一个字典,该字典内存放我们的代理地址即可,这些代理地址可以在网络中很容易的获取到。
import json
import requests
header = {
'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
'referer': 'https://www.baidu.com'
}
proxy = { 'http': 'http://112.54.47.55:9091'}
if __name__ == "__main__":
ret = requests.get(url="http://httpbin.org/get", headers=header, proxies=proxy, timeout=5)
ret.encoding = "utf-8"
# 检查是否访问成功
if ret.status_code == 200:
load = json.loads(ret.text)
print("当前自身IP地址:",load.get("origin"))
如上则是一段使用代理访问目标地址的代码,当使用代理成功后其返回值应该与代理地址保持一致,如下图所示;
代理地址的获取有许多,此处我们可以使用如下所示的一个代理地址,该项目是一个长期项目代理地址每天都会更新,读者可自行打开查阅;
当然要想使用这些代理不转换肯定是不行的,我们可以通过编程的方式将这些代理根据自己所需要的格式进行转换,将其转换为可以直接在代码中引用的,如下则是一种简单的转换流程;
import json
import requests
header = {'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',}
# 获取代理并返回字典
def GetProxy():
ref_dict = {"http":[], "https":[]}
ret = requests.get(url="http://proxylist.fatezero.org/proxy.list", headers=header, timeout=5)
ret.encoding = "utf-8"
# 检查是否访问成功
if ret.status_code == 200:
# 切割并将代理地址逐个处理
local_address_list = ret.text.split("\n")
for index in local_address_list:
try:
dict = eval(index)
if len(dict["export_address"]) != 0 and dict["export_address"][0] != "unknown":
address = dict["export_address"][0]
port = dict["port"]
type = dict["type"]
if type == "http":
insert = f"http://{address}:{port}"
ref_dict["http"].append(insert)
if type == "https":
insert = f"https://{address}:{port}"
ref_dict["https"].append(insert)
except Exception:
pass
return ref_dict
if __name__ == "__main__":
proxy_list = GetProxy()
print(proxy_list)
读者可运行上述代码,此时即可将网页中的字符串转换为可以被直接使用的代理地址,输出效果图如下所示;
这些代理地址可能由于时间关系不保证全部能用,接着我们还需要实现一个CheckProxy
函数,该函数用于验证这些代理地址的可用性,实现代码如下所示;
import json
import requests
# 验证代理是否存活
def CheckProxy(proxy):
http = proxy["http"]
for index in http:
try:
proxy = {'http': 'http://127.0.0.1:8080'}
proxy.update({'http': index})
ret = requests.get(url="http://httpbin.org/get", headers=header, proxies=proxy, timeout=5)
# 检查是否访问成功
if ret.status_code == 200:
load = json.loads(ret.text)
print("代理头部: {} 实际访问时的地址: {}".format(index,load.get("origin")))
except Exception:
pass
if __name__ == "__main__":
proxy_list = GetProxy()
CheckProxy(proxy_list)
代码验证原理则是通过调用requests.get
函数访问http://httpbin.org/get
当代理地址与当前地址一致则说明该地址是可用的,通过循环的方式不断验证即可得到一批可用地址,如下图所示;
21.7.4 下载页面数据
有时候我们需要保存一个HTTP
页面或保存页面中的特定图片等元素,此时就需要自己实现页面的下载功能,针对网页的下载可以直接使用requests.get()
函数默认参数即可,而当需要下载大文件或者是图片资源时,我们可以在调用该函数时,增加一个stream=True
属性,该属性预示着将会采用流模式,此时就可以通过iter_content
迭代器迭代下载整个图片。
首先我们先来实现下载页面功能,该函数封装为download_page()
在执行时接收两个参数,分别是需要下载的页面网址,以及需要保存的文件名,当执行下载成功后则会返回response.status_code
状态码。
import os
import requests
header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0"}
# 下载页面到本地
def download_page(url,path,timeout):
params = {"encode": "utf-8"}
try:
response = requests.get(url=url, params=params, headers=header, timeout=timeout)
# 如果返回200
if response.status_code == 200:
# print("网页编码方式: {} -> {}".format(response.encoding, response.apparent_encoding))
context = response.text.encode(response.encoding).decode(response.apparent_encoding, "ignore")
# 检查文件不存在
if os.path.exists(path) == False:
# 将文件保存
with open(path,"w",encoding=response.apparent_encoding) as file_point:
ref = file_point.write(context)
# 验证是否保存
if ref != 0 or ref != None:
return ref
else:
return 0
# 如果文件存在则
else:
return 0
else:
return response.status_code
except Exception:
return 0
return 0
if __name__ == "__main__":
# 下载页面到本地为index.html设置超时时间5秒
down_page = download_page("https://www.lyshark.com","index.html",5)
if down_page != 0:
print("下载文件完成,返回代码: {}".format(down_page))
我们以下载www.lyshark.com
主页为例,当执行后读者可看到如下图所示的输出结果;
接着是针对图片的下载,下载图片可以调用download_picture()
函数,该函数传入三个参数,分别是需要下载的图片路径,保存图片的路径,以及设置一个超时时间。
import os
import requests
header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0"}
# 下载页面到本地
def download_picture(url,path,timeout):
params = {"encode": "utf-8"}
try:
img_download = requests.get(url=url, params=params, headers=header, timeout=timeout,stream=True)
# 如果返回200
if img_download.status_code == 200:
# 检查文件不存在
if os.path.exists(path) == False:
# 将图片保存
with open(path,"wb") as file_point:
# 流的方式保存,每次保存1024
chunk_size = 0
for chunk in img_download.iter_content(chunk_size=1024):
size = file_point.write(chunk)
chunk_size = chunk_size + size
print("[+] chunk = {}".format(chunk_size))
return chunk_size
# 如果文件存在则
else:
return 0
else:
return img_download.status_code
except Exception:
return 0
return 0
if __name__ == "__main__":
# 下载图片到本地
down_picture = download_picture("https://www.lyshark.com/images/baidu_logo.png","security.png",5)
if down_picture != 0:
print("下载文件完成,返回代码: {}".format(down_picture))
运行上述代码,将下载www.lyshark.com
下面的图标,并将该图标保存为security.png
,输出效果如下图所示;
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!