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
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)
|