fineconey 发表于 2023-4-14 01:03:20

关于多线程堆列的问题

如图,初学者,想多线程写一个爬虫,构思了一个框架,尝试了一下,发现不能运行完整,中途就结束了,请各位大佬劳烦看一下问题在哪里。

代码如下

import threading
import time
from queue import Queue
import requests

t1 = time.time()
url_queue = Queue()


def download():
    while not url_queue.empty():
      url=url_queue.get()
      res = requests.get(url)
      print(url,res.status_code,res.encoding)
      return res.status_code
    # print(res.headers)


urls = ['http://www.038909.xyz', 'http://www.solucky.com.cn',
      'http://www.baidu.com', 'http://www.bing.com', 'http://www.cnbeta.com', 'http://16666.com'

      ]

for url in urls:
    url_queue.put(url)

for i in range(3):
    t = threading.Thread(target=download)
    t.start()




运行结果:
当range(3)时,只跑前三个,后面的url不跑。
/Volumes/DATA/PythonData/venv/bin/python /Volumes/DATA/doc&docx/2.py
http://www.038909.xyz 200 ISO-8859-1
http://www.baidu.com 200 ISO-8859-1
http://www.solucky.com.cn 502 None

isdkz 发表于 2023-4-14 01:06:12

从你提供的代码来看,你创建了三个线程来执行 `download` 函数。每个线程在队列中取出一个 URL 进行下载,但是当 `download` 函数返回结果后,线程就结束了。所以你观察到的现象是只有前三个 URL 被处理了。

你可以通过让每个线程处理多个 URL 来解决这个问题。这可以通过在 `download` 函数中添加一个循环来实现。当一个线程处理完一个 URL 后,它将继续处理队列中的下一个 URL,直到队列为空。这里是修改后的代码:

import threading
import time
from queue import Queue
import requests

t1 = time.time()
url_queue = Queue()


def download():
    while not url_queue.empty():
      url = url_queue.get()
      res = requests.get(url)
      print(url, res.status_code, res.encoding)
      url_queue.task_done()# 需要添加这行,以通知队列此任务已完成

urls = [
    'http://www.038909.xyz', 'http://www.solucky.com.cn',
    'http://www.baidu.com', 'http://www.bing.com', 'http://www.cnbeta.com', 'http://16666.com'
]

for url in urls:
    url_queue.put(url)

threads = []# 创建一个线程列表,用于保存所有线程
for i in range(3):
    t = threading.Thread(target=download)
    t.start()
    threads.append(t)# 把线程添加到线程列表

# 等待所有任务完成
url_queue.join()

# 等待所有线程结束
for t in threads:
    t.join()

t2 = time.time()
print('Total time: ', t2 - t1)


这样修改后,你的代码应该可以正确地处理所有的 URL 了。不过,还有一点需要注意:由于多线程操作不是线程安全的,可能会出现一些意外情况。在实际编写爬虫时,建议使用线程池 (如 `concurrent.futures.ThreadPoolExecutor`) 等更高级的并发工具,以确保程序的稳定性和可扩展性。

fineconey 发表于 2023-4-14 01:12:52

isdkz 发表于 2023-4-14 01:06
从你提供的代码来看,你创建了三个线程来执行 `download` 函数。每个线程在队列中取出一个 URL 进行下载, ...

非常感谢,让我多了一点思考,和发现一些没想到的地方。再次感谢(那么晚还没睡)

isdkz 发表于 2023-4-14 01:15:45

fineconey 发表于 2023-4-14 01:12
非常感谢,让我多了一点思考,和发现一些没想到的地方。再次感谢(那么晚还没睡)

不客气{:5_109:}。最近熬夜熬习惯了,虽然知道熬夜不好{:10_277:}
页: [1]
查看完整版本: 关于多线程堆列的问题