You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.5 KiB

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/8/29 21:31
# @Author : old tom
# @File : http_request.py
# @Project : Futool
import urllib.request as req
import urllib.parse
from futool.http.http_response import ResponseWrapper
from http import cookiejar
import json
import shutil
import os
DEFAULT_HEADER = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70",
"Accept": "*/*",
"Connection": "keep-alive"
}
DEFAULT_TIMEOUT = 10
class HttpRequestError(Exception):
def __init__(self, msg=''):
Exception.__init__(self, msg)
def get(url, param=None, header=None, timeout=DEFAULT_TIMEOUT):
"""
普通get请求
:param url: 请求地址
:param param: 参数字典 自动拼接url
:param header: 请求头
:param timeout: 超时(秒)
:return:
"""
return request(url, 'GET', param, header=header, timeout=timeout)
def head(url, param=None, header=None, timeout=DEFAULT_TIMEOUT):
"""
发起head请求
:param url:
:param param:
:param header:
:param timeout:
:return:
"""
return request(url, 'HEAD', param, header, timeout)
def post_form(url, data=None, header=None, timeout=DEFAULT_TIMEOUT):
"""
post 请求提交普通表单
:param url:
:param data:
:param header:
:param timeout:
:return:
"""
return request(url, 'POST', data=data, header=header, timeout=timeout)
def post(url, json_param=None, header=None, timeout=DEFAULT_TIMEOUT):
"""
post 请求提交body 参数
:param url:
:param json_param:
:param header:
:param timeout:
:return:
"""
return request(url, 'POST', json_param=json_param, header=header, timeout=timeout)
def request(url, method, param=None, data=None, json_param=None, header=None, timeout=DEFAULT_TIMEOUT, before_send=None,
success_handler=None,
error_handler=None):
"""
基础请求方法
:param method: 请求方法 目前支持get post 方法
:param url: 请求地址
:param param: 请求参数拼接url或表单
:param data: 表单参数
:param json_param: json body参数
:param header: 请求头
:param timeout: 超时
:param before_send: 发送前处理
:param success_handler: 钩子函数(成功处理)
:param error_handler: 钩子函数(失败处理)
:return:
"""
_request = None
if method not in ['GET', 'POST', 'HEAD']:
raise HttpRequestError('not support method')
if header is None:
header = DEFAULT_HEADER
opener, cookie = _init_cookie_jar()
if before_send:
before_send(opener, cookie, header)
if method in ['GET', 'HEAD']:
if param:
param_str = urllib.parse.urlencode(param)
url = url + '?' + param_str
_request = req.Request(url, headers=header, method=method)
if 'POST' == method:
if data:
# 表单
data = urllib.parse.urlencode(data).encode('utf-8')
header.update({"Content-Type": "application/x-www-form-urlencoded"})
if json_param:
# json body
data = bytes(json.dumps(json_param), 'utf-8')
header.update({"Content-Type": "application/json"})
_request = req.Request(url, data=data, headers=header, method=method)
wrapper = ResponseWrapper(opener.open(_request, timeout=timeout), cookie)
if success_handler and wrapper.is_ok():
return success_handler(wrapper)
elif error_handler and not wrapper.is_ok():
return error_handler(wrapper)
return wrapper
def _init_cookie_jar():
"""
初始化cookie容器
:return:
"""
cookie = cookiejar.CookieJar()
handler = req.HTTPCookieProcessor(cookie)
return req.build_opener(handler), cookie
def upload_file():
# TODO
pass
def download_file(url, dst_path, overwrite=True, duplicate_handler=None, buffer=16 * 1024):
"""
文件下载
:param url: URL路径
:param dst_path: 目标位置
:param overwrite: 是否覆盖同名文件
:param duplicate_handler: 自定义重复文件处理
:param buffer:
:return:
"""
if os.path.isfile(dst_path) and overwrite:
os.remove(dst_path)
if os.path.isfile(dst_path) and not overwrite and duplicate_handler:
duplicate_handler(dst_path)
b_resp = req.urlopen(url)
with open(dst_path, 'wb') as f:
shutil.copyfileobj(b_resp, f, buffer)