Python多进程与requests

最近在部署一个比赛环境,其中有一个需求,去一个服务器不断拉取文件进行分析,然后向这个服务器反馈分析结果。

问题一

初步使用多进程生产消费者模型,由于分析速度慢,拉取速度快,这个时候就出现一个重复拉取的问题,比如A文件拉取过来,然后扔给消费者处理,等了一会还是没有消费完,这个时候生产者又开始拉文件了,导致A文件又被拉取一次。

为了避免这个问题,设置一个全局共享变量,生产者一次性拉取若干文件,然后交给消费者处理,等待所有的文件都处理完毕之后,再向生产者发送一个反馈消息,告诉生产者可以再次生产数据了,之后生产者收到消息继而进行下一次的任务获取。

因为用到多进程,默认不能像多线程那样共享全局变量,这里需要通过进程共享变量实现。

    manager = multiprocessing.Manager()
    # 设置存放数据flag
    ready = manager.Value('b', 1)

同时需要注意的一点,要通过进程池的方式实现多进程,否则值还是无法进行传递。

示例:

#coding=utf8
import multiprocessing
import random
import time
lock = multiprocessing.Lock()

def produce(q,ready):
    while True:
        if ready.value:
            print("收到消息,开始生产数据")
            for i in range(20):
                q.put(1)
            print("停止生产")
            ready.value = 0
        time.sleep(2)

def comsume(q,ready):
    while True:
        if q.empty():
            # 告诉生产者,我这里消费完了,可以生产数据了
            ready.value = 1
            time.sleep(2)
            continue
        task = q.get()
        time.sleep(task)

if __name__ == '__main__':
    manager = multiprocessing.Manager()
    ready = manager.Value('b',1)
    pool = multiprocessing.Pool(10)
    q = manager.Queue(20)
    pool.apply_async(func=produce, args=(q, ready,))
    for i in range(8):
        pool.apply_async(func=comsume,args=(q,ready,))
    pool.close()
    pool.join()

输出:

收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产
收到消息,开始生产数据
停止生产

问题二

如何使用requests进行自定义构造内容包上传文件

requests官方文档里的标准文件上传格式是这样的

>>> url = 'http://httpbin.org/post'
>>> multiple_files = [
        ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
        ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
>>> r = requests.post(url, files=multiple_files)
>>> r.text
{
  ...
  'files': {'images': 'data:image/png;base64,iVBORw ....'}
  'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
  ...
}

也就是说我们要先获得一个文件的句柄,调用open()函数,如果我们只有文件内容,如果想通过这种方式就要先把他存储下来,然后再open打开上传,非常麻烦。

后面研究了下这个requests函数,下面是构造file数据包代码。

		files = to_key_val_list(files or {})
		...
            if isinstance(v, (tuple, list)):
                if len(v) == 2:
                    fn, fp = v
                elif len(v) == 3:
                    fn, fp, ft = v
                else:
                    fn, fp, ft, fh = v
            else:
                fn = guess_filename(v) or k
                fp = v

            if isinstance(fp, (str, bytes, bytearray)):
                fdata = fp
            elif hasattr(fp, 'read'):
                fdata = fp.read()
            elif fp is None:
                continue
            else:
                fdata = fp
                
       rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)

先判断输入的变量v是不是一个元组,如果是二元组,则fn = v[0] , fp = v[1]

之后再看fp 是不是一个(str, bytes, bytearray)或是否具有read属性,也就是说支持f.read 以及f这两种类型,如果都不是那么fdata = fp,然后filename=fn,继续构造数据包。注意到传入的files字段会通过to_key_val_list进行处理,因此我们构造以下两种方式即可直接构造文件内容上传,示例如下:

r = requests.post("http://qq.com/",files={'file': ("filename.txt",filedata)})
print(r.request.body.decode("utf-8"))

r = requests.post("http://100.65.6.50/phpscan.php",files=[('file',("1.txt",filedata))])
print(r.request.body.decode("utf-8"))

输出:

--5b32e3e126eb8751351f4b8b7a7e742d
Content-Disposition: form-data; name="file"; filename="1.txt"

123
--5b32e3e126eb8751351f4b8b7a7e742d--
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值