# urllib

# 概述

urllib​ 是 Python 标准库中的一个模块,用于处理 URL 相关的操作。它提供了一组功能,用于从网络上获取数据、处理 URL、发送 HTTP 请求以及其他与网络通信相关的任务。urllib​ 包括多个子模块,包括 urllib.request​、urllib.parse​、urllib.error​ 和 urllib.robotparser​,每个子模块都有不同的用途。

以下是 urllib​ 主要子模块的简要介绍:

  1. urllib.request​: 这个子模块提供了用于发送 HTTP 请求的工具。您可以使用它来打开 URL、下载远程文件、发送 GET 或 POST 请求等。常用的函数包括 urlopen()​ 用于打开 URL,以及 urlretrieve()​ 用于下载文件。
  2. urllib.parse​: 这个子模块用于解析 URL,并处理 URL 的各个部分,如协议、主机名、路径、查询参数等。它提供了 urlparse()​ 用于解析 URL,以及 urlencode()​ 用于编码查询参数等功能。
  3. urllib.error​: 当发生与 URL 相关的错误时,这个子模块提供了一些异常类,例如 URLError​ 和 HTTPError​,用于处理异常情况。
  4. urllib.robotparser​: 用于处理 robots.txt​ 文件的解析和分析,以确定哪些页面可以被爬取。

# 示例-url编码解码

在 URL 中,某些字符会被转义以确保 URL 的正确性和可用性。以下是一些常见需要被转义的字符:

  1. 空格:空格通常被转义为 "%20" 或加号 "+"。
  2. 特殊字符:特殊字符如 "&"、"?"、"="、"#" 等都需要被转义。
  3. 非ASCII字符:非ASCII字符(如汉字、日文、俄文等字符)通常以 UTF-8 编码转义为一系列 "%xx" 形式的字符,其中 "xx" 是字符的十六进制表示。
  4. 控制字符:ASCII 控制字符通常会被转义为 "%xx" 形式的字符。
  5. 其他字符:根据需要,一些其他字符也可能需要被转义。

例如,空格会被转义为 "%20",而 "&" 会被转义为 "%26"。这样做是为了确保 URL 可以正确地传递和解释,因为某些字符在 URL 中具有特殊含义。

from urllib.parse import quote, unquote

original_string = "http://www.baidu.com/l?type=1&kw=深圳&start_time=2023:05:01"
encoded_string = quote(original_string)
decoded_string = unquote(encoded_string)

print("原始字符串:", original_string)
print("编码后的字符串:", encoded_string)
print("解码后的字符串:", decoded_string)

"""
原始字符串: http://www.baidu.com/l?type=1&kw=深圳&start_time=2023:05:01
编码后的字符串: http%3A//www.baidu.com/l%3Ftype%3D1%26kw%3D%E6%B7%B1%E5%9C%B3%26start_time%3D2023%3A05%3A01
解码后的字符串: http://www.baidu.com/l?type=1&kw=深圳&start_time=2023:05:01
"""

# 示例-解析并更新query

from urllib.parse import urlparse, urlencode, parse_qs, urlunparse


def update_url_params(url, params):
    # 将URL解析为其组成部分
    url_parts = urlparse(url)
    """
    # 解析 URL
    parsed_url = urlparse(url)

    # 提取不同部分
    scheme = parsed_url.scheme  # 协议(例如:https)
    netloc = parsed_url.netloc  # 域名(例如:www.example.com)
    path = parsed_url.path      # 路径(例如:/path/to/page)
    query = parsed_url.query    # 查询参数部分(例如:param1=value1&param2=value2)
    """

    # 获取URL中的查询参数
    query_params = parse_qs(url_parts.query)
    print(query_params)

    # 更新参数字典
    query_params.update(params)
    print(query_params)

    # 将参数字典转换为URL编码的字符串
    encoded_params = urlencode(query_params, doseq=True)

    # 创建更新后的URL组成部分
    modified_url_parts = list(url_parts)
    modified_url_parts[4] = encoded_params

    # 构造最终的URL
    modified_url = urlunparse(modified_url_parts)

    return modified_url


if __name__ == "__main__":
    base_url = "http://www.baidu.com/l?type=1&kw=%E6%B1%9F%E8%8B%8F&start_time=2023%3A04%3A15"

    params = {"kw": "上海", "start_time": "2023:05:01"}
    updated_url = update_url_params(base_url, params)
    print(updated_url)


"""
(test) lei@leideMacBook-Pro test % /Users/lei/miniconda3/envs/test/bin/python /Users/lei/workspace/program/test/test.py
{'type': ['1'], 'kw': ['江苏'], 'start_time': ['2023:04:15']}
{'type': ['1'], 'kw': '上海', 'start_time': '2023:05:01'}
http://www.baidu.com/l?type=1&kw=%E4%B8%8A%E6%B5%B7&start_time=2023%3A05%3A01
"""

# 示例 - 发送get请求

def send_request(fp):
    url = f"http://localhost:8080{fp}"
    print(f"正在测试: {url}")
    encoded_url = urllib.parse.quote(url, safe='/:')
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
    }

    req = urllib.request.Request(encoded_url, headers=headers)

    try:
        with urllib.request.urlopen(req) as response:
            status_code = response.getcode()
            # print(f"响应状态码:{status_code}")
            if status_code != 200:
                print(fp)
    except urllib.error.URLError as e:
        print(f"请求发生异常: {e}")