python爬虫—-多线程

1. 引入

我们之前写的爬虫都是单个线程的?这怎么够?一旦一个地方卡到不动了,那不就永远等待下去了?为此我们可以使用多线程或者多进程来处理。
不建议你用这个,不过还是介绍下了,如果想看可以看看下面,不想浪费时间直接看

2. 如何使用

爬虫使用多线程来处理网络请求,使用线程来处理URL队列中的url,然后将url返回的结果保存在另一个队列中,其它线程在读取这个队列中的数据,然后写到文件中去

3. 主要组成部分

3.1 URL队列和结果队列

将将要爬去的url放在一个队列中,这里使用标准库Queue。访问url后的结果保存在结果队列中
初始化一个URL队列

from queue import Queue
urls_queue = Queue()
out_queue = Queue()

3.2 类包装

使用多个线程,不停的取URL队列中的url,并进行处理:如果队列为空,线程就会被阻塞,直到队列不为空。处理队列中的一条数据后,就需要通知队列已经处理完该条数据

import threading

class ThreadCrawl(threading.Thread):
    def __init__(self, queue, out_queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.out_queue = out_queue

    def run(self):
        while True:
            item = self.queue.get()

 

3.3 函数包装

from threading import Thread
def func(args)
pass
if __name__ == '__main__':
info_html = Queue()
t1 = Thread(target=func,args=(info_html,)

 

3.4 线程池

# 简单往队列中传输线程数
import threading
import time
import queue

class Threadingpool():
    def __init__(self,max_num = 10):
        self.queue = queue.Queue(max_num)
        for i in range(max_num):
            self.queue.put(threading.Thread)

    def getthreading(self):
        return self.queue.get()

    def addthreading(self):
        self.queue.put(threading.Thread)


def func(p,i):
    time.sleep(1)
    print(i)
    p.addthreading()


if __name__ == "__main__":
    p = Threadingpool()
    for i in range(20):
        thread = p.getthreading()
        t = thread(target = func, args = (p,i))
        t.start()

 

4. Queue模块中的常用方法:

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步
– Queue.qsize() 返回队列的大小
– Queue.empty() 如果队列为空,返回True,反之False
– Queue.full() 如果队列满了,返回True,反之False
– Queue.full 与 maxsize 大小对应
– Queue.get([block[, timeout]])获取队列,timeout等待时间
– Queue.get_nowait() 相当Queue.get(False)
– Queue.put(item) 写入队列,timeout等待时间
– Queue.put_nowait(item) 相当Queue.put(item, False)
– Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
– Queue.join() 实际上意味着等到队列为空,再执行别的操作

5. 使用线程池爬取段子

from threading import Thread
import requests
from lxml import etree
from fake_useragent import UserAgent
from queue import Queue
class Spider(Thread):
    #构造函数
    def __init__(self,url_queue):
        Thread.__init__(self)
        self.url_queue = url_queue
    def run(self):
        while not self.url_queue.empty():
            url = self.url_queue.get()
            print(url)
            headers = {
                'User-Agent':UserAgent().chrome
            }
            resp = requests.get(url,headers=headers)
            e = etree.HTML(resp.text)
            contents =[ div.xpath('string(.)').strip() for div in e.xpath('//div[@class="content"]')]

            with open('duanzi.txt','a',encoding='utf-8') as f:
                for content in contents:
                    f.write(content + '\n')
if __name__ == '__main__':
    base_url = 'https://www.qiushibaike.com/text/page/{}'
    url_queue = Queue()
    for num in range(1,12):
        url_queue.put(base_url.format(num))
    # 3个线程
    for num in range(1,3):
        spider = Spider(url_queue)
        spider.start()

 

文章已创建 80

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部