• 21.7 Python 使用Request库


    Request库可以用来发送各种HTTP请求,该框架的特点是简单易用,同时支持同步和异步请求,支持HTTP协议的各种方法和重定向。它还支持CookieHTTPS和认证等特性。 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"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    如下输出效果,我们通过传入一个参数,即可输出一条随机请求头,及一个来源地址,输出效果如下所示;

    21.7.1 实现GET请求

    HTTP GET请求是一种常见的HTTP请求方法之一,用于向服务器请求特定资源,比如网页、图片、视频等。在HTTP GET请求中,客户端向服务器发送一个带有请求参数的URL,服务器接收到请求后返回请求的资源。

    要实现访问一个页面可以调用requests.get()函数,该函数可用于发送http以及https请求,并返回相应结果,该方法的语法如下所示;

    requests.get(url, params=None, **kwargs)
    
    • 1

    其中,url是要请求的URLparams是可选的参数,可以包含查询字符串参数,**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('(.+)', ret.text)
            print("输出标题: ", title)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行上述代码即可实现访问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)
    
    • 1

    其中,参数urlPOST请求的目标URL。参数dataPOST请求的正文数据,类型为字符串或字节流。参数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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如上一段代码,通过使用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"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如上则是一段使用代理访问目标地址的代码,当使用代理成功后其返回值应该与代理地址保持一致,如下图所示;

    代理地址的获取有许多,此处我们可以使用如下所示的一个代理地址,该项目是一个长期项目代理地址每天都会更新,读者可自行打开查阅;

    • 代理地址:http://proxylist.fatezero.org/proxy.list

    当然要想使用这些代理不转换肯定是不行的,我们可以通过编程的方式将这些代理根据自己所需要的格式进行转换,将其转换为可以直接在代码中引用的,如下则是一种简单的转换流程;

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    读者可运行上述代码,此时即可将网页中的字符串转换为可以被直接使用的代理地址,输出效果图如下所示;

    这些代理地址可能由于时间关系不保证全部能用,接着我们还需要实现一个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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    代码验证原理则是通过调用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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    我们以下载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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    运行上述代码,将下载www.lyshark.com下面的图标,并将该图标保存为security.png,输出效果如下图所示;

  • 相关阅读:
    Cargo 教程
    3D激光SLAM:ALOAM---后端 lasermapping构建角点约束与面点约束
    搭建青龙面板和接入傻妞机器人
    vue3源码分析——实现createRenderer,增加runtime-test
    redis:常用的数据类型
    关于web前端大作业的HTML网页设计——我的班级网页HTML+CSS+JavaScript
    Java中如何使用BufferedInputStream,BufferedOutputStream分批快速读取大文件呢?
    力扣刷题 day54:10-24
    亚远景科技-ASPICE评估师等级、ASPICE评估师培训和ASPICE评估项目等级简介
    使用单调栈解决接雨水问题——LeetCode 42 接雨水+单调栈说明
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134059568